原理
要模拟绸缎材质的质感,首先我们要对绸缎材质有所了解。说到绸缎,就不得不布料。一开始进行资料检索绸缎,布料,丝绸等这些概念的时候就会容易让人产生困惑。然而基本上可以说这些文字上的概念对我们而言毫无意义。我们只需要了解不同布料在视觉表现上有何不同,再进行近似即可。
布料包含了各种组织的形式,而正式这种组织方式的不同才造就了这些繁杂的概念。组织的方式可以简单的分为约三种(对视觉表现的不同贡献较大),分别是:
组织方式 | 结构图 |
平纹组织 | |
斜纹组织 | |
缎纹组织 | |
其中,由于平纹组织和斜纹组织浮长线长度较短的特征,可以用PBR模型来进行近似。而缎纹组织的浮长线较长,就会产生类似头发般各向异性的高光。因此,要模拟出绸缎的效果,我们要做的就是各向异性的高光,结合缎纹组织的一些特殊的细节。
实现方法
为了实现各向异性的高光,我们首先需要找到一个各向异性高光的模型,这里我们使用HDRP中的各项异性高光模型,并将它移植到URP中。
float3 DirectBRDFSpecularAnisotropy(BRDFData brdfData, float3 V, float3 L, float3 N, float3 tangentWS, float3 bitangentWS)
{
float NdotL = dot(N, L);
float NdotV = dot(N,V);
float clampedNdotV = ClampNdotV(NdotV);
float clampedNdotL = saturate(NdotL);
float LdotV = 0, NdotH = 0, LdotH = 0, invLenLV = 0;
GetBSDFAngle(V, L, NdotL, NdotV, LdotV, NdotH, LdotH, invLenLV);
float3 F = F_Schlick(_SpecularColor, LdotH);
float DV;
float3 H = (L + V) * invLenLV;
float TdotL = dot(tangentWS, L);
float TdotH = dot(tangentWS, H);
float BdotH = dot(bitangentWS, H);
float BdotL = dot(bitangentWS, L);
float roughnessT = 0, roughnessB = 0;
ConvertAnisotropyToRoughness(brdfData.perceptualRoughness, _Anisotropy, roughnessT, roughnessB);
DV = DV_SmithJointGGXAniso(TdotH, BdotH, NdotH, clampedNdotV, TdotL, BdotL, abs(NdotL),
roughnessT, roughnessB, 1);
float diffTerm = DisneyDiffuse(clampedNdotV, abs(NdotL), LdotV, brdfData.perceptualRoughness) * clampedNdotL;
float3 specTerm = F * DV;
specTerm *= clampedNdotL;
return specTerm;
}
因为HDRP中使用的是BSDF,这里使用了BRDF进行近似。在使用上我们只需要遵循URP中PBR的常规流程即可,初始化brdf数据。各向异性函数中还有一个重要的点,就是如何获取2个方向上的不同的粗糙度(也就是各向异性)。这里使用到的是SRP库中的原生函数ConvertAnisotropyToRoughness。参考HDRP中的做法,以一个值为[-1,1]的shader property来进行模拟,之后就使用这个参数传入函数中,即可获得2个不同方向上的粗糙度。这里贴一下转化的函数,都是RP库中的源码:
real PerceptualRoughnessToRoughness(real perceptualRoughness)
{
return perceptualRoughness * perceptualRoughness;
}
void ConvertValueAnisotropyToValueTB(real value, real anisotropy, out real valueT, out real valueB)
{
// Use the parametrization of Sony Imageworks.
// Ref: Revisiting Physically Based Shading at Imageworks, p. 15.
valueT = value * (1 + anisotropy);
valueB = value * (1 - anisotropy);
}
void ConvertAnisotropyToRoughness(real perceptualRoughness, real anisotropy, out real roughnessT, out real roughnessB)
{
real roughness = PerceptualRoughnessToRoughness(perceptualRoughness);
ConvertValueAnisotropyToValueTB(roughness, anisotropy, roughnessT, roughnessB);
}
为了能够更加逼近缎纹材质的细节,我们这里使用了缎纹组织的细节贴图。(HDRP中布料材质的sample中有)
其中g和a通道分别组成了切线空间的法线。R通道是AO,B通道是光滑度。
通过获取这些值再使用一个漫反射模型进行结合基本就可以出效果了。由于受限于移动端平台的性能,我这里使用的是兰伯特漫反射+高相异性的高光+简单的环境球的采样。\
总结
通过这张细节贴图的启发,可以容易地想到对于不同组织形式的细节,我们所使用的信息贴图应该是大致一样的,因为在纺织领域中,平纹,斜纹和缎纹已经有比较完整的规范了。
最后,强烈推荐大家前往HDRP中的sample查看完整版丝绸示例,HDRP团队也在不断更新更多的材质示例。
效果
unity绸缎材质(URP)_哔哩哔哩_bilibili
参考
High Definition Render Pipeline overview | High Definition RP | 14.0.0https://people.csail.mit.edu/kuiwu/rtfr.html#:~:text=Real%2Dtime%20Cloth%20Rendering%20with%20Fiber%2Dlevel%20Detail,-Kui%20Wu%2C%20Cem&text=Modeling%20cloth%20with%20fiber%2Dlevel,even%20for%20offline%20rendering%20applications.High Definition Render Pipeline overview | High Definition RP | 14.0.0