本系列主要参考《Unity Shaders and Effects Cookbook》一书(感谢原书作者),同时会加上一点个人理解或拓展。
这里是本书所有的插图。这里是本书所需的代码和资源(当然你也可以从官网下载)。
========================================== 分割线 ==========================================
有时候,我们并不想让物体的所有部分都反射,例如一个物体可能某些部分是玻璃材质的可以反射,而有些是塑料材质就不会反射。
在这篇教程里,我们将会学习一种技术来控制反射范围,这是通过一张texture作为遮罩(mask)来实现的。也就是说,我们可以使用一张texture的灰度值去决定该平面该如何反射,这意味着,一个为黑色的灰度值对应一个不会反射的子平面,而一个白色的灰度值对应一个完全反射的子平面。如今,基本所有的游戏制作都是使用这种方法来控制反射效果的。
下面,我们来看看在Unity里怎么使用Surface Shaders来实现它。
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) = ""{} }
CGPROGRAM #pragma surface surf Lambert sampler2D _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; }
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 200 CGPROGRAM #pragma surface surf Lambert sampler2D _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" }