表面着色器光照示例
这里例举了一些表面着色器中自定义光照模型的示例。有关一般的表面着色器 (Surface Shader) 示例,请查看此页面。
由于延时光照 (Deferred Lighting) 与一些自定义的逐材质光照模型不能很好的配合,因此在大部分示例中,我们都仅将着色器编译成正向渲染 (Forward Rendering)。
漫反射
我们将从使用内置 Lambert 光照模型的着色器开始:
Shader "Example/Diffuse Texture" { Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader { Tags { "RenderType" = "Opaque" } CGPROGRAM #pragma surface surf Lambert struct Input { float2 uv_MainTex; }; sampler2D _MainTex; void surf (Input IN, inout SurfaceOutput o) { o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb; } ENDCG } Fallback "Diffuse" }
这是有纹理和没有实际纹理的样子(场景中存在一盏方向灯):
现在,让我们进行一次完全相同的操作,但要编写出我们自己的光照模型,而不是使用内置的 Lambert 模型。表面着色器光照模型只是我们需要编写的一些函数。这是一个简单的 Lambert 模型。请注意,“着色器部分”(即下面灰色的部分)自身并未改变:
Shader "Example/Diffuse Texture" { Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader { Tags { "RenderType" = "Opaque" } CGPROGRAM #pragma surface surf SimpleLambert half4 LightingSimpleLambert (SurfaceOutput s, half3 lightDir, half atten) { half NdotL = dot (s.Normal, lightDir); half4 c; c.rgb = s.Albedo * _LightColor0.rgb * (NdotL * atten * 2); c.a = s.Alpha; return c; } struct Input { float2 uv_MainTex; }; sampler2D _MainTex; void surf (Input IN, inout SurfaceOutput o) { o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb; } ENDCG } Fallback "Diffuse" }
因此,我们的简单漫反射 (Diffuse) 光照模型是 LightingSimpleLambert
函数。它通过在表面法线和光线方向之间执行一次数量积来计算光照,然后应用光衰减和颜色。
漫反射遮蔽
下面是遮蔽的漫反射 - 漫反射 (Diffuse) 光照的一种改进,其中照明“环绕”在对象边缘。它对模拟子面散射效果有用。同样,表面着色器本身并未改变。我们仅仅是使用了不同的光照函数。
Shader "Example/Diffuse Wrapped" { Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader { Tags { "RenderType" = "Opaque" } CGPROGRAM #pragma surface surf WrapLambert half4 LightingWrapLambert (SurfaceOutput s, half3 lightDir, half atten) { half NdotL = dot (s.Normal, lightDir); half diff = NdotL * 0.5 + 0.5; half4 c; c.rgb = s.Albedo * _LightColor0.rgb * (diff * atten * 2); c.a = s.Alpha; return c; } struct Input { float2 uv_MainTex; }; sampler2D _MainTex; void surf (Input IN, inout SurfaceOutput o) { o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb; } ENDCG } Fallback "Diffuse" }


卡通渐变
这是一个“渐变”(Ramp) 光照模型,它使用纹理渐变来定义表面如何对光线与法线之间的夹角作出反应。这可用于各种效果,包括卡通 (Toon) 光照。
Shader "Example/Toon Ramp" { Properties { _MainTex ("Texture", 2D) = "white" {} _Ramp ("Shading Ramp", 2D) = "gray" {} } SubShader { Tags { "RenderType" = "Opaque" } CGPROGRAM #pragma surface surf Ramp sampler2D _Ramp; half4 LightingRamp (SurfaceOutput s, half3 lightDir, half atten) { half NdotL = dot (s.Normal, lightDir); half diff = NdotL * 0.5 + 0.5; half3 ramp = tex2D (_Ramp, float2(diff)).rgb; half4 c; c.rgb = s.Albedo * _LightColor0.rgb * ramp * (atten * 2); c.a = s.Alpha; return c; } struct Input { float2 uv_MainTex; }; sampler2D _MainTex; void surf (Input IN, inout SurfaceOutput o) { o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb; } ENDCG } Fallback "Diffuse" }



简单高光
这是一个简单的高光光照模型。它是内置的 BlinnPhong 模型,实际上操作起来非常简单。我们把它列举出来只是为了说明它是如何工作的。
Shader "Example/Simple Specular" { Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader { Tags { "RenderType" = "Opaque" } CGPROGRAM #pragma surface surf SimpleSpecular half4 LightingSimpleSpecular (SurfaceOutput s, half3 lightDir, half3 viewDir, half atten) { half3 h = normalize (lightDir + viewDir); half diff = max (0, dot (s.Normal, lightDir)); float nh = max (0, dot (s.Normal, h)); float spec = pow (nh, 48.0); half4 c; c.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * spec) * (atten * 2); c.a = s.Alpha; return c; } struct Input { float2 uv_MainTex; }; sampler2D _MainTex; void surf (Input IN, inout SurfaceOutput o) { o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb; } ENDCG } Fallback "Diffuse" }

