表面着色器光照示例        

这里例举了一些表面着色器中自定义光照模型的示例。有关一般的表面着色器 (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"  }
,