寫在前面
有時候,我們並不想讓物體的所有部分都反射,例如一個物體可能某些部分是玻璃材質的可以反射,而有些是塑料材質就不會反射。
在這篇教程裡,我們將會學習一種技術來控制反射範圍,這是通過一張texture作為掩碼(mask)來實現的。也就是說,我們可以使用一張texture的灰階值去決定該平面該如何反射,這意味著,一個為黑色的灰階值對應一個不會反射的子平面,而一個白色的灰階值對應一個完全反射的子平面。如今,基本所有的遊戲製作都是使用這種方法來控制反射效果的。
下面,我們來看看在Unity裡怎麼使用Surface Shaders來實現它。
準備工作
實現
最後整體代碼如下:
Shader "Custom/MaskedReflection" {Properties {_MainTex ("Base (RGB)", 2D) = "white" {}_MainTint ("Diffuse Tint", Color) = (1,1,1,1)_ReflAmount ("Reflection Amount", Range(0, 1)) = 1_Cubemap ("Cubemap", CUBE) = ""{}_ReflMask ("Reflection Mask", 2D) = ""{}}SubShader {Tags { "RenderType"="Opaque" }LOD 200CGPROGRAM#pragma surface surf Lambertsampler2D _MainTex;sampler2D _ReflMask;samplerCUBE _Cubemap;float4 _MainTint;float _ReflAmount;struct Input {float2 uv_MainTex;float3 worldRefl;};void surf (Input IN, inout SurfaceOutput o) {half4 c = tex2D (_MainTex, IN.uv_MainTex);float3 reflection = texCUBE(_Cubemap, IN.worldRefl).rgb;float4 reflMask = tex2D(_ReflMask, IN.uv_MainTex);o.Albedo = c.rgb * _MainTint;o.Emission = (reflection * reflMask.r) * _ReflAmount;o.Alpha = c.a;}ENDCG} FallBack "Diffuse"}
將情境中球體對應的材質設定如所示:
最後效果,其中左面的球體使用了掩碼反射,對比右面沒有使用掩碼反射:
解釋
這個Shader非常的簡單,僅僅使用了texCUBE函數在Cubemap中採樣。這個函數是內建的CGFX函數,它提供給我們一個Cubemap中的顏色值,然後我們將該值應用到平面上。Unity通過Input結構體中的worldRefl變數來幫我們在Cubemap中找到對應的採樣位置。正如上一篇解釋的一樣,這個屬性將會把攝像機視角的反射向量傳遞給我們。一旦我們知道了反射元素(即反射的顏色值),我們就需要接著去採樣我們的掩碼貼圖。我們可以使用tex2D函數來完成它,這個函數在第二章中就接觸過。當我們知道了兩個textures對應的值後,我們就可以把Cubemap的顏色值乘以反射貼圖的顏色值,並傳遞給o.Emission。最後,為了可以全域控制反射密度,我們需要把結果再乘以_ReflAmount屬性。這可以幫我們控制平面的整體反射量(越大表明反射度越高,越接近鏡子的效果)。下面展示了不同的_ReflAmount值對應的不同的反射效果: