표면 쉐이더에서 사용자 정의 라이팅 모델
표면 쉐이더와 DX11 테셀레이션

표면 쉐이더 라이팅의 예

아래는 Surface ShadersCustom Lighting Model의 샘플입니다. 일반적인 표면 쉐이더의 예는, 이 페이지에 있습니다.

지연 라이팅은 사용자 정의 메테리얼 당 라이팅 모델에 따라 잘 작동하지 않기 때문에, 다음 대부분의 예에서 쉐이더는 포워드 렌더링에만 컴파일합니다.

Diffuse

내장 램버트 라이팅 모델을 사용하는 쉐이더에서 시작합시다.

  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"
  }

다음은 텍스처가 있는 경우와 실제 텍스처가 없는 경우에 어떻게 보이는지의 예입니다(한 개의 디렉셔널 라이트가 씬에 있습니다).

똑같은 일을 하지만, 내장 램버트 라이팅 모델을 사용하는 대신, 자신의 라이팅 모델 을 작성합니다. Surface Shader Lighting Models는 작성해야 하는 함수입니다. 다음은 간단한 램버트 라이팅 모델입니다. 쉐이더 부분 자체(회색 부분)는 변경되지 않았음에 유의하시기 바랍니다 :

    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);
              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 함수입니다. 표면 법선과 빛 방향 사이의 내적을 수행하여 라이팅을 계산하고 빛의 경감 및 색상을 적용합니다.

디퓨즈 랩(Diffuse Wrap)

다음은 랩 된 디퓨즈, 디퓨즈 라이팅의 변형에서 조명이 오브젝트의 가장자리를 합니다. 하위 표면 산란 효과의 페이크(Fake)에 유용합니다. 다시 말하지만, 표면 쉐이더 자체는 전혀 변하지 않습니다. 다른 라이팅 함수를 사용하는 것 뿐입니다.

    ...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);
        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 라이팅 모델입니다. 이것은 툰 라이팅 등의 각종 효과에 사용할 수 있습니다.

    ...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;
        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이 실제로 실행할 것을 아주 쉽게 할 수 있습니다. 여기에서는 어떻게 행해지는지를 보여주기 위해 이것을 삽입합니다.

    ...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;
        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...

라이트맵 디코딩

내장 라이트 맵 디코딩과 Unity 내장 함수 DecodeLightmap, 라이트맵 텍스처 및 내장 UNITY_DIRBASIS 매크로를 사용하여 방향성 라이트맵의 기본 벡터를 정의에 저장된 데이터의 디코딩을 재현하는 쉐이더를 시작해야 합니다 :

    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);
                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_DirLightmap (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"
    }

다음은 라이트맵에 포함된 톤 매핑을 추가해보겠습니다 :

    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); 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_DirLightmap (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"
    }
표면 쉐이더에서 사용자 정의 라이팅 모델
표면 쉐이더와 DX11 테셀레이션