Unity Shader——Writing Surface Shaders(3)——Surface Shader Lighting Examples

Surface Shader 光照例子

  這裏有一些自定義光照模型Surface Shaders的例子。一般的Surface Shader例子在這裏html

  因爲延遲光照在某些自定義的逐材質光照模型中表現得並很差,在下面大多數例子中,咱們讓shader只編譯到正向渲染中。app

漫反射(Diffuse)

  讓咱們以使用內建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

環繞漫反射(Diffuse Wrap)

  這裏是環繞漫反射——漫反射光照的修改版,即照明環繞在物體的邊緣。它對用來仿照次表面散射效果頗有用。由於只是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...

 

卡通漸變(Toon Ramp)

  下面是一個"漸變(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...

 

簡單鏡面(Simple Specular)

  下面是一個簡單鏡面光照模型。這對於內置的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...

解碼光照貼圖(Decoding Lightmaps)

  咱們將以這樣一個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"
    }
相關文章
相關標籤/搜索