Surface Shader Illumination Example
Here are some examples of custom lighting models and surface shaders. The usual surface shader examples are here.
Because delayed illumination does not perform well in some custom light-to-material lighting models, in most of the following examples, we have shader compiled into forward rendering only.
Diffuse reflectance (diffuse)
Let's start with a shader that uses the built-in Lambert lighting model!
Shader"Example/diffuse Texture"{Properties {_maintex ("Texture", 2D) =" White"{}} subshader {Tags {"Rendertype"="Opaque"} cgprogram#pragmaSurface Surf LambertstructInput {float2 Uv_maintex; }; Sampler2d _maintex; voidSurf (Input in, InOut surfaceoutput o) {O.albedo=tex2d (_maintex, In.uv_maintex). RGB; } ENDCG} Fallback"Diffuse" }
Here's what it's like to use a texture map and not use a real texture map (there's a directional light in this scene)
Now, let's do exactly the same, but use our own lighting model instead of the built-in Lambert illumination model. Surface shader lighting models are just some of the functions we need to write. Here is a simple Lambert illumination model. Notice that only the Cgprogram part has changed, and the surrounding shader code is exactly the same:
Shader"Example/diffuse Texture"{Properties {_maintex ("Texture", 2D) =" White"{}} subshader {Tags {"Rendertype"="Opaque"} cgprogram#pragmaSurface Surf SimplelambertHalf4 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; returnC; } structInput {float2 Uv_maintex; }; Sampler2d _maintex; voidSurf (Input in, InOut surfaceoutput o) {O.albedo=tex2d (_maintex, In.uv_maintex). RGB; } ENDCG} Fallback"Diffuse" }
So our simple diffuse light model is a LightingSimpleLambert
function. It calculates the light by calculating the dot product of the surface normals and the direction of the light, and then applies light attenuation and color.
Surround diffuse reflection (diffuse wrap)
Here is a modified version of the diffuse light, which surrounds the edge of the object. It is useful for imitating sub-surface scattering effects. Because only the Cgprogram part has changed, the cliché once, the surrounding shader code is omitted:
... Shaderlab code ... Cgprogram#pragmaSurface Surf WraplambertHalf4 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; returnC; } structInput {float2 Uv_maintex; }; Sampler2d _maintex; voidSurf (Input in, InOut surfaceoutput o) {O.albedo=tex2d (_maintex, In.uv_maintex). RGB; } ENDCG ... Shaderlab code ...
Cartoon gradient (Toon Ramp)
The following is a "gradient (Ramp)" Lighting model. It uses a gradient texture to define how the surface reacts to the angle of light and normals. This can be used to achieve a variety of effects, including cartoon lighting.
... Shaderlab code ... Cgprogram#pragmaSurface Surf Rampsampler2d _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; returnC; } structInput {float2 Uv_maintex; }; Sampler2d _maintex; voidSurf (Input in, InOut surfaceoutput o) {O.albedo=tex2d (_maintex, In.uv_maintex). RGB; } ENDCG ... Shaderlab code ...
Simple Mirror (specular)
Here is a simple specular light model. This is very easy for the built-in Blinnphong to actually do. We put it here to show how it works.
... Shaderlab code ... Cgprogram#pragmaSurface Surf SimplespecularHalf4 Lightingsimplespecular (surfaceoutput s, half3 Lightdir, Half3 viewdir, half atten) {half3 h= Normalize (Lightdir +Viewdir); Half diff= Max (0, Dot (s.normal, lightdir)); floatNH = MAX (0, Dot (s.normal, h)); floatSpec = POW (NH,48.0); Half4 C; C.rgb= (S.albedo * _lightcolor0.rgb * diff + _lightcolor0.rgb * spec) * (Atten *2); C.A=S.alpha; returnC; } structInput {float2 Uv_maintex; }; Sampler2d _maintex; voidSurf (Input in, InOut surfaceoutput o) {O.albedo=tex2d (_maintex, In.uv_maintex). RGB; } ENDCG ... Shaderlab code ...
Decode Light Map (decoding lightmaps)
We'll start with such a shader: it mimics the built-in lighting map decoding work, uses UNITY's own Decodelightmap function to decode the data stored in Lightmap, and uses its own unity_ The Dirbasis macro defines the basic vectors of the directional illumination map (directional lightmap):
Shader"Example/standard Lightmap decoding"{Properties {_maintex ("Texture", 2D) =" White"{}} subshader {Tags {"Rendertype"="Opaque"} cgprogram#pragmaSurface Surf StandardHalf4 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; returnC; } inline Fixed4 Lightingstandard_singlelightmap (surfaceoutput s, fixed4 color) {half3 lm=decodelightmap (color); returnFixed4 (LM,0); } inline Fixed4 Lightingstandard_duallightmap (surfaceoutput s, fixed4 Totalcolor, Fixed4 Indirectonlycolor, ha LF Indirectfade) {half3 lm=Lerp (Decodelightmap (Indirectonlycolor), Decodelightmap (Totalcolor), indirectfade); returnFixed4 (LM,0); } inline Fixed4 Lightingstandard_standardlightmap (surfaceoutput s, fixed4 color, fixed4 scale,BOOLsurffuncwritesnormal) {unity_dirbasis half3 lm=decodelightmap (color); Half3 Scaleperbasisvector=Decodelightmap (scale); if(surffuncwritesnormal) {half3 normalinrnmbasis=saturate (Mul (unity_dirbasis, s.normal)); LM*=dot (normalinrnmbasis, scaleperbasisvector); } returnFixed4 (LM,0); } structInput {float2 Uv_maintex; }; Sampler2d _maintex; voidSurf (Input in, InOut surfaceoutput o) {O.albedo=tex2d (_maintex, In.uv_maintex). RGB; } ENDCG} Fallback"Diffuse" }
Now let's add some tone mapping for the light stored in the light map (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#pragmaSurface Surf tonemappedHalf4 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; returnC; } 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)); returnFixed4 (LM,0); } inline Fixed4 Lightingtonemapped_duallightmap (surfaceoutput s, fixed4 Totalcolor, Fixed4 Indirectonlycolor, Half indirectfade) {half3 lm=tonemaplight (Lerp (Decodelightmap (Indirectonlycolor), Decodelightmap (Totalcolor), Indirectfade)); returnFixed4 (LM,0); } inline Fixed4 Lightingtonemapped_standardlightmap (surfaceoutput s, fixed4 color, fixed4 scale,BOOLsurffuncwritesnormal) {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); } returnFixed4 (LM,0); } structInput {float2 Uv_maintex; }; Sampler2d _maintex; voidSurf (Input in, InOut surfaceoutput o) {O.albedo=tex2d (_maintex, In.uv_maintex). RGB; } ENDCG} Fallback"Diffuse" }
Unity shader--writing Surface Shaders (3)--surface Shader Lighting Examples