Unity3D ShaderLab布料着色器
布料着色器是我们在虚拟现实中经常使用的着色器。本篇就来完成一个较为简单的布料着色器。
新建Shader,Material,InteractiveCloth【布料】。完成的代码如下
Shader "91YGame/ClothShader" { Properties { //参数; _MainTint("Base Color",Color)=(1,1,1,1) _BumpMap ("Normal Map", 2D) = "bump" {} _DetailBump("Detail Normal",2D)=""{} _DetailTex("Fabric Weave",2D)=""{} _FresnelColor("Fresnel Color",Color)=(1,1,1,1) _FresnelPower("Fresnel Power",Range(0.01,10))=3 _RimPower("Rim Falloff",Range(0.01,10))=3 _SpecIntesity("Specular Intensity",Range(0.01,1))=0.3 _SpecWidth("Specular Width",Range(0.01,1))=0.2 } SubShader { Tags { "RenderType"="Opaque" } LOD 200 CGPROGRAM #pragma surface surf VelvetCloth #pragma target 3.0 //变量; sampler2D _BumpMap; sampler2D _DetailBump; sampler2D _DetailTex; float4 _MainTint; float4 _FresnelColor; float _FresnelPower; float _RimPower; float _SpecIntesity; float _SpecWidth; //输入结构体; struct Input { float2 uv_BumpMap; float2 uv_DetailBump; float2 uv_DetailTex; }; inline fixed4 LightingVelvetCloth(SurfaceOutput s,fixed3 lightDir, fixed3 viewDir, fixed atten){ //光照向量; viewDir =normalize(viewDir); lightDir = normalize(lightDir); half3 halfVec = normalize(lightDir+viewDir); fixed NdotL = max(0.01,dot(s.Normal,lightDir)); //计算高光; float NdotH = max(0.01,dot(s.Normal,halfVec)); float spec = pow(NdotH,s.Specular*128)*s.Gloss; //视线越贴近布料表面,纤维吸收的背面光就越多,高光也就越强; float HdotV = pow(1-max(0,dot(halfVec,viewDir)),_FresnelPower); float NdotE = pow(1-max(0,dot(s.Normal,viewDir)),_RimPower); float finalSpecMask = NdotE*HdotV; //最终颜色; fixed4 c; c.rgb = (s.Albedo*NdotL*_LightColor0.rgb)+(spec*(finalSpecMask*_FresnelColor))*(atten*2); c.a =1; return c; } void surf (Input IN, inout SurfaceOutput o) { half4 c = tex2D (_DetailTex, IN.uv_DetailTex); //提取法线; fixed3 normals = UnpackNormal(tex2D(_BumpMap,IN.uv_BumpMap)).rgb; fixed3 detailNormals = UnpackNormal(tex2D(_DetailBump,IN.uv_DetailBump)).rgb; fixed3 finalNormals = float3(normals.x+detailNormals.x,normals.y+detailNormals.y,normals.z+detailNormals.z); o.Normal = normalize(finalNormals); o.Specular = _SpecWidth; o.Gloss = _SpecIntesity; o.Albedo = c.rgb*_MainTint; o.Alpha = c.a; } ENDCG } FallBack "Diffuse" }
返回Unity,设置变量。最终效果如下:
在上面的实现过程中,我们将两张不同平铺率的法线贴图结合到一起。计算出新的法线向量。
所以使用UnpackNormal从变化法线贴图中提取出法线向量在产生新的法线贴图。然后使用normalize对最后的向量进行归一化,这样可以避免法线贴图看起来杂乱。
最后 将菲涅尔计算和高光计算的结果进行合并,创建出布料的纤维效果。