找回密码
 立即注册
查看: 574|回复: 5

[简易教程] 【浅入浅出】Unity 布料渲染

[复制链接]
发表于 2021-5-12 09:27 | 显示全部楼层 |阅读模式
在unity教程中对于布料这块的渲染好像并不多,网上能搜到的也是寥寥,因为目前大多数的基于物理的材质都是用BRDF进行渲染的,但是传统的BRDF是建立在微表面理论,但是对于微表面不能当成完美镜面的,传统的BRDF并不能很好的模拟,所以我们需要找到一个能“模拟”布料的BRDF公式。
在下面实现的代码都是基于以下的公式:
diffuse项是DisneyDiffuse 项:


其中,
在UnityStandardBRDF中已经为我们实现好了,我们直接拿来用:
half diffuseTerm = DisneyDiffuse(nv, nl, lh, perceptualRoughness);如果我们要为其添加次表面散射,则需要用到如下公式:


其中w是一个0-1之间的值,用来控制散射的柔和程度,实际上就是WrapLighting,
代码:
inline float Wrap(float nl, float w) {
                return saturate((nl + w) / (1.0 + w)*(1.0 + w));
            }
diffuseTerm *= Wrap(nl,_FabricScatterSale);
half3 Fd = diffColor * diffuseTerm * saturate(_FabricScatterColor + nl);这样Fd就算好了,接着就是specular项:
这里的公式和Cook-Torrance公式有点不一样,首先是D项:
在Physically Based Rendering in Filament 种他提到了两种模型,一种是Ashikhmin模型,他们认为在衣物的渲染中distribution占了很大的比重并且建立在这样的假设上:遮罩带来的影响为0。模型本身是一个逆高斯函数,并且当添加偏移后能很好的灯光对毛绒的高光的模拟,这里偏移为1:


第二个模型为Charlie模型,这也是建立在遮罩影响为0的情况下,并且相对于上面的cot运算,Charlie模型的运算量更小。




两种代码:
inline float D_Ashikhmin(float roughness,float nh){
                float a2 = roughness * roughness;
                float cos2h = nh * nh ;
                float sin2h = max(1.0 - cos2h, 0.0078125); // 2^(-14/2), so sin2h^2 > 0 in fp16
                    float sin4h = sin2h * sin2h;
                float cot2 = -cos2h / (a2 * sin2h);
                    return 1.0 / (PI * (4.0 * a2 + 1.0) * sin4h) * (4.0 * exp(cot2) + sin4h);

            }
inline float D_Charlie(float roughness, float nh) {
               
                float invAlpha  = 1.0 / roughness;
                float cos2h = nh * nh;
                float sin2h = max(1.0 - cos2h, 0.0078125); // 2^(-14/2), so sin2h^2 > 0 in fp16
                return (2.0 + invAlpha) * pow(sin2h, invAlpha * 0.5) / (2.0 * PI);
            }对于specular中的G项(Unity中的Visibility


inline float VisibilityCloth(float nl, float nv, float roughness){
                return  1/(4 * ( nl + nv - nl*nv) + 1e-5f);
            }最后整合得到Fr。
注意我们没有菲尼尔项,取而代之的是用Sheen来控制高光。在Physically Based Rendering in Filament 一文中,Sheen的缺省值为0.04 以实现天鹅绒的效果,如果考虑实现其他布料材质,我们可以考虑使用luminance来作为sheen值。
高光项的效果如下:(注意黑丝)
Charlie模型下的高光结果
加上漫反射项:
没有使用sss
加上sss:
加上sss后感觉更透了,像超能陆战队的大白一样。
不同参数下的结果:
注意:我们在使用sss时,不应该乘
最后我们的代码应该看起来像这样的:
half4 Cuntom_BRDF_PBS(half3 diffColor, half3 specColor, half oneMinusReflectivity, half smoothness,
            float3 normal, float3 viewDir,
            UnityLight light, UnityIndirect gi)
            {
                float perceptualRoughness = SmoothnessToPerceptualRoughness (smoothness);
                float3 halfDir = Unity_SafeNormalize (float3(light.dir) + viewDir);

               
                #define UNITY_HANDLE_CORRECTLY_NEGATIVE_NDOTV 0

                #if UNITY_HANDLE_CORRECTLY_NEGATIVE_NDOTV
                    // The amount we shift the normal toward the view vector is defined by the dot product.
                    half shiftAmount = dot(normal, viewDir);
                    normal = shiftAmount < 0.0f ? normal + viewDir * (-shiftAmount + 1e-5f) : normal;
                    // A re-normalization should be applied here but as the shift is small we don&#39;t do it to save ALU.
                    //normal = normalize(normal);

                    half nv = saturate(dot(normal, viewDir)); // TODO: this saturate should no be necessary here
                #else
                    half nv = abs(dot(normal, viewDir));    // This abs allow to limit artifact
                #endif

                    half nl = saturate(dot(normal, light.dir));
                    float nh = saturate(dot(normal, halfDir));

                    half lv = saturate(dot(light.dir, viewDir));
                    half lh = saturate(dot(light.dir, halfDir));
                 //diffuse term
                half diffuseTerm = DisneyDiffuse(nv, nl, lh, perceptualRoughness);
               
                //specular term
                float roughness = PerceptualRoughnessToRoughness(perceptualRoughness);
                roughness = max(roughness, 0.002);
                half V = VisibilityCloth (nl, nv, roughness);
                half D = DistributionCloth(roughness, nh);
                #ifdef USE_LUMINANCE
                    half luminance = dot(diffColor,half3(0.299,0.587,0.114));
                    half3 F = luminance;
                #else
                    half3 F = specColor;//0.04 should be  default
                #endif

                half specularTerm = V * D * _SpecularScale;
                specularTerm = max(0, specularTerm * nl);


                half surfaceReduction;
                surfaceReduction = 1.0 / (roughness*roughness + 1.0);

                 specularTerm *= any(specColor) ? 1.0 : 0.0;

               
               
               
                 
                //half grazingTerm = saturate(smoothness + (1-oneMinusReflectivity));

                #ifdef  SUBSURFACE_COLOR_ON
                    diffuseTerm *= Wrap(nl,_FabricScatterSale);
                    half3 Fd = diffColor * (gi.diffuse + light.color * diffuseTerm
                     * saturate(_FabricScatterColor + nl));
                    half3 Fr = specularTerm * light.color;
                    half3 color = Fd + Fr;
                    
                #else
                    
                    half3 Fd = diffColor * (gi.diffuse + light.color * diffuseTerm
                     * nl);
                    half3 Fr = specularTerm * light.color;
                    half3 color = Fd + Fr;
                    

                #endif        

                return half4(color, 1);

            }另外网上还有一种Custom Fabric的文章,并且知乎上有人实现了效果,传送门。但我觉得并不是很真实,他使用了比较强的菲尼尔系数,导致材质看起来蒙蒙的。
最后还有一篇关于快速模拟sss的文章,与本篇内容无关,但挺有意思的,传送门。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
发表于 2021-5-12 09:33 | 显示全部楼层
厉害
发表于 2021-5-12 09:37 | 显示全部楼层
模型有木有传送门
发表于 2021-5-12 09:40 | 显示全部楼层
sketchfab 搜索 “gwen”
发表于 2021-5-12 09:44 | 显示全部楼层
大佬,小白前来请教!我想问问专精衣物布料的制作和物理模拟这块,怎么点亮技能树?
发表于 2021-5-12 09:47 | 显示全部楼层
这个DisneyDiffuse的返回值是不是写错了,为啥返回是一个标量啊?
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-5-20 06:29 , Processed in 0.093865 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表