创建各向异性类型的高光反射着色器 各向异性(Anisotropic) 类型可以用来模拟高光或者反射,常用于表面凹槽的方向和高光在垂直方向上的扭曲形变。当你想模拟金属抛光表面的时候这种类型的着色器就会非常有用,因为这种表面并不干净,光滑和明亮。 你可以想象当你看CD或者VCD光盘的数据那面时的高光或者底面被打磨过的金属盘子和盆子。 当你仔细检查这些表面的时候你会发现,表面的这些沟纹是有方向的,通常就是被抛光的方向。当你对这样的表面应用高光时,在垂直方向上会被扭曲。
这个知识点中我们会向你介绍不同的抛光表面高光概念。在将来的一些知识点中,我们会探索如何使用这个知识点介绍的一些概念来获得一些类似于头发的扭曲反射效果,但是在这里我们还是要先学习这个技术的一些原理知识。我们自定义的各向异性着色器将使用下面这个着色器作为参考:
http://wiki.unity3d.com/index.php?title=Anisotropic_Highlight_Shader
下图展示了使用 各向异性(Anisotropic) 着色器能获得的不同类型高光效果: 始前准备
让我们开始学习新的知识点吧,先按照下面的步骤在场景中创建一个着色器,材质和一些光源:
创建一个新的场景,在场景中添加一些游戏对象,添加一个平行光源,这样我们好可视化的调试我们的着色器。 创建一个新的着色器和材质,它们都应用到刚刚创建的游戏对象上去。 最后,我们需要某种法线贴图,它能指出我们各向异性类型高光的方向。 下图展示的就是这个知识点要用的各向异性类型的法线贴图。在本书的支持网页中可以获得[就在本书附带的工程代码中,获取方法前面有介绍]:
https://www.packtpub.com/books/content/support
操作步骤
为了获得各向异性效果,我们需要对我们前面创建的着色器进行如下的修改:
首先得再着色器中添加我们需要用到的一些属性。这些属性允许我们控制很多中艺术效果从而最终决定表面的效果呈现: { _MainTint ("Diffuse Tint", Color) = (1,1,1,1) _MainTex ("Base (RGB)", 2D) = "white" {} _SpecularColor ("specular Color", Color) = (1,1,1,1) _Specular ("Specular Amount", Range(0,1)) = 0.5 _SpecPower ("Specular Power", Range(0,1)) = 0.5 _AnisoDir ("Anisotropic Direction", 2D) = "" {} _AnisoOffset ("Anisotropic Offset", Range(-1,1)) = -0.2 } 接着我们要让我们的 SubShader{} 代码块跟我们的 属性(Properties) 块关联起来,这样才能让我们使用 属性(Properties) 中的数据: sampler2D _MainTex; sampler2D _AnisoDir; float4 _MainTint; float4 _SpecularColor; float _AnisoOffset; float _Specular; float _SpecPower; 接下来我们要创建我们自己的光照函数,用来处理物体表面的各向异性效果。我们的代码如下: fixed4 LightingAnisotropic(SurfaceAnisoOutput s, fixed3 lightDir, half3 viewDir, fixed atten) { fixed3 halfVector = normalize(normalize(lightDir) + normalize(viewDir)); float NdotL = saturate(dot(s.Normal, lightDir)); fixed HdotA = dot(normalize(s.Normal + s.AnisoDirection),halfVector); float aniso = max(0, sin(radians((HdotA + _AnisoOffset) * 180))); float spec = saturate(pow(aniso, s.Gloss * 128) * s.Specular); fixed4 c; c.rgb = ((s.Albedo * _LightColor0.rgb * NdotL) + (_LightColor0.rgb * _SpecularColor.rgb * spec)) * atten; c.a = s.Alpha; return c; } 为了使用我们新的光照函数,我们需要修改**#pragma**指示,让Unity去使用我们的光照函数,而不是Unity内建的光照函数。我们同时还要告诉着色器目标着色器模式是3.0,这样我们可以让我们的程序拥有更多的空间用来存放纹理: CGPROGRAM #pragma surface surf Anisotropic #pragma target 3.0 为了让各向异性法线贴图能使用它自己的UV数据,我们需要再 输入(Input) 结构中添加如下定义代码。 我们其实并不是说完全需要这样做,因为我们也可以使用主帖图上的UV数据,但是如果有它自己单独UV数据的话我们就能单独控制金属抛光效果的截取,这样我们就可以把它进行缩放任何我们想要的大小: { float2 uv_MainTex; float2 uv_AnisoDir; }; 我们还需要定义 SurfaceAnisoOutput 这个输出结构体: struct SurfaceAnisoOutput { fixed3 Albedo; fixed3 Normal; fixed3 Emission; fixed3 AnisoDirection; half Specular; fixed Gloss; fixed Alpha; }; 最后,我们需要通过表面函数 surf() 给我们的光照函数传递正确的数据。这样,我们将会获得我们各向异性法线贴图的每个像素信息,然后像下面的代码一样设置我们的高光参数: void surf(Input IN, inout SurfaceAnisoOutput o) { half4 c = tex2D(_MainTex, IN.uv_MainTex) * _MainTint; float3 anisoTex = UnpackNormal(tex2D(_AnisoDir, IN.uv_AnisoDir)); o.AnisoDirection = anisoTex; o.Specular = _Specular; o.Gloss = _SpecPower; o.Albedo = c.rgb; o.Alpha = c.a; } 各向异性法线贴图允许我们给出表面的方向并且能帮助我们分散物体表面周围的高光效果。下图就是我们的各向异性着色器的效果:
...