转载请标明出处http://www.cnblogs.com/zblade/
最近捣鼓了一下金属光泽的shader的实现,在一些高模展示的时候或者模型的金属部分的表现的时候,我们需要给模型添加一些金属光泽,表现出一个模型某些金属装备上有一定的反光。今天我主要写一种基于贴图实现的金属反光的效果。不过我没有添加最终的效果,大家可以自己理解一下做一些贴图实现各自的模型效果。
Unity5在更新后推出一种基于物理的shader-standard shader,其中给定了一个参数就是metallic 和 smoothness,可以通过添加一个纹理贴图来实现模型的金属表现。大概查看了一下源代码,主要也是对金属光泽纹理贴图的采样,然后分别赋值。主要的操作代码:
half2 MetallicGloss(float2 uv) { half2 mg; #ifdef _METALLICGLOSSMAP mg = tex2D(_MetallicGlossMap,uv.xy).ra; #else mg = half2(_Metallic,_Glossiness); #endif return mg }
分析其实现的原理,其实就是如果有贴图,则采样贴图的r通道和alpha通道,如果没有贴图,则根据参数进行赋值。基于standard提供的思路,我提供了一个类似的实现方式:首先让美术提供一个黑白透的贴图,合并在主纹理贴图中(通过合并,可以减少贴图数量),其中的通道值可以用来作为金属光泽的过滤效果。然后让美术提供一个贴图,可以用来实现金属光泽的光照,常见的为圆形光照,所以这儿我就采用的圆形光照来实现。主要的计算是在顶点shader中计算圆形光照的贴图采样坐标,所以我主要给出计算的关键部分即可:
v2f vert(a2v) { v2f o = (v2f)0; o.pos = mul(UNITY_MATRIX_MVP,v.vertex); o.uv = v.texcoord; //计算球形光源的采样坐标,在观察空间中 half3 viewNormal = mul((float3x3)UNITY_MATRIX_MV,v.normal); half4 viewPos = mul(UNITY_MATRIX_MV,v.vertex); half3 projPos = normalize(viewPos.xyz/viewPos.w); half3 reflectVar = reflect(projPos,viewNormal); half m = 2.0 * sqrt(reflectVar.x * reflectVar.x + reflectVar.y*reflectVar.y + (reflectVar.x+1)*(reflectVar.z + 1)); o.sphereUV = fixed2(reflectVar.x/m + 0.5, reflectVar.y/m + 0.5); } fixed4 frag(v2f i):SV_Target { //基本计算 ... half4 mainVar = tex2D(_MainTex,i.uv); //用主贴图的alpha通道来做金属光泽的处理 half3 specular = tex2D(_SphereTex,i.sphereUV).rgb * mainVar.a *_SpecPower; // half3 diffuse = mainVar.rgb * _LightColor.rgb * _MainColor.rgb * max(0,dot(v.normal,lightDir)) ; fixed4 color; color.rgb = diffuse + specular; color.a = 1; return color; }
本文实现的基本思路就是用一个基本的圆形贴图作为金属光泽的光照,其具体的调节做在住贴图的alpha通道中采样,所以关键计算是球形的采样坐标和通道的计算过滤。大家可以测试一下表现效果,基本的金属光泽就是这样,大家有什么反馈可以给我留言,共同讨论成长~