这里有一些自定义光照模型和Surface Shaders的例子。一般的Surface Shader例子在这里。html
因为延迟光照在某些自定义的逐材质光照模型中表现得并很差,在下面大多数例子中,咱们让shader只编译到正向渲染中。app
让咱们以使用内建Lambert光照模型的shader做为开始吧!函数
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" }
下面是使用一张纹理贴图和不使用一张真实的纹理贴图的样子(此场景中有一个方向光)spa
如今,咱们来作个彻底同样的,可是使用咱们本身的光照模型,而不是内建Lambert光照模型。Surface Shader光照模型仅是一些咱们须要编写的函数。这里有一个简单的Lambert光照模型。注意到只有CGPROGRAM部分发生了改变,周边的shader代码是彻底同样的:code
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" }
因此咱们的简单漫反射光照模型就是LightingSimpleLambert
函数。它经过计算表面法线和光线方向的点积来计算光照,而后应用光照衰减和颜色。orm
这里是环绕漫反射——漫反射光照的修改版,即照明环绕在物体的边缘。它对用来仿照次表面散射效果颇有用。由于只是CGPROGRAM 部分发生了改变,老生常谈一次,周边的shader代码就省略了:htm
...ShaderLab code... 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 ...ShaderLab code...
下面是一个"渐变(Ramp)"光照模型。它使用一张渐变纹理来定义表面怎样对光线和法线的夹角作出反应。这能用来实现多种效果,包括卡通光照。blog
...ShaderLab code... 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 ...ShaderLab code...
下面是一个简单镜面光照模型。这对于内置的BlinnPhong实际所作的内容来讲很是简单。咱们把它放在这来讲明它是如何工做的。get
...ShaderLab code... 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 ...ShaderLab code...
咱们将以这样一个shader做为开始:它模仿内置的光照贴图解码工做,使用Unity自带的DecodeLightmap函数解码lightmap中储存的数据信息,以及使用自带的UNITY_DIRBASIS宏定义方向光照贴图(Directional lightmap)的基本向量: it
Shader "Example/Standard Lightmap Decoding" { Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader { Tags { "RenderType" = "Opaque" } CGPROGRAM #pragma surface surf Standard half4 LightingStandard (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; } inline fixed4 LightingStandard_SingleLightmap (SurfaceOutput s, fixed4 color) { half3 lm = DecodeLightmap (color); return fixed4(lm, 0); } inline fixed4 LightingStandard_DualLightmap (SurfaceOutput s, fixed4 totalColor, fixed4 indirectOnlyColor, half indirectFade) { half3 lm = lerp (DecodeLightmap (indirectOnlyColor), DecodeLightmap (totalColor), indirectFade); return fixed4(lm, 0); } inline fixed4 LightingStandard_StandardLightmap (SurfaceOutput s, fixed4 color, fixed4 scale, bool surfFuncWritesNormal) { UNITY_DIRBASIS half3 lm = DecodeLightmap (color); half3 scalePerBasisVector = DecodeLightmap (scale); if (surfFuncWritesNormal) { half3 normalInRnmBasis = saturate (mul (unity_DirBasis, s.Normal)); lm *= dot (normalInRnmBasis, scalePerBasisVector); } return fixed4(lm, 0); } 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" }
如今,让咱们为光照贴图中储存的光添加些色调映射(tone mapping):
Shader "Example/Tonemapped Lightmap Decoding" { Properties { _MainTex ("Texture", 2D) = "white" {} _Gain ("Lightmap tone-mapping Gain", Float) = 1 _Knee ("Lightmap tone-mapping Knee", Float) = 0.5 _Compress ("Lightmap tone-mapping Compress", Float) = 0.33 } SubShader { Tags { "RenderType" = "Opaque" } CGPROGRAM #pragma surface surf Tonemapped half4 LightingTonemapped (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; } half _Gain; half _Knee; half _Compress; inline half3 TonemapLight (half3 i) { i *= _Gain; return (i > _Knee)? (((i - _Knee)*_Compress)+_Knee): i; } inline fixed4 LightingTonemapped_SingleLightmap (SurfaceOutput s, fixed4 color) { half3 lm = TonemapLight(DecodeLightmap (color)); return fixed4(lm, 0); } inline fixed4 LightingTonemapped_DualLightmap (SurfaceOutput s, fixed4 totalColor, fixed4 indirectOnlyColor, half indirectFade) { half3 lm = TonemapLight(lerp (DecodeLightmap (indirectOnlyColor), DecodeLightmap (totalColor), indirectFade)); return fixed4(lm, 0); } inline fixed4 LightingTonemapped_StandardLightmap (SurfaceOutput s, fixed4 color, fixed4 scale, bool surfFuncWritesNormal) { UNITY_DIRBASIS half3 lm = TonemapLight(DecodeLightmap (color)); half3 scalePerBasisVector = DecodeLightmap (scale); if (surfFuncWritesNormal) { half3 normalInRnmBasis = saturate (mul (unity_DirBasis, s.Normal)); lm *= dot (normalInRnmBasis, scalePerBasisVector); } return fixed4(lm, 0); } 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" }