서피스 아웃풋 (SurfaceOutput)

SurfaceOutput 구조체 안에는 머테리얼의 최종 모습을 결정하기 위해 사용되는 여러가지 프로퍼티를 포함

1
2
3
4
5
6
7
8
9
struct SurfaceOutput
{
    fixed3 Albedo;  // diffuse color
    fixed3 Normal;  // tangent space normal, if written
    fixed3 Emission;
    half Specular;  // specular power in 0..1 range
    fixed Gloss;    // specular intensity
    fixed Alpha;    // alpha for transparencies
};
cs

Albedo : 기본색상

Normal : 반사각을 결정하는 면의 방향

Emission : 오브젝트가 스스로 생성하는 빛의 양

Specular : 머테리얼이 빛을 반사하는 정도 (0~1)

Gloss : 스펙큘러 반사가 퍼지는 정도(세기)

Alpha : 머테리얼의 투명한 정도



서피스 인풋 (SurfaceInput)

Input에는 일반적으로 셰이더에 의해 요구되는 텍스쳐 좌표가 있음.

텍스쳐 좌표의 이름은 uv뒤에 텍스쳐 이름이 오는 형태로 해야함.


Input 안에 아래를 입력할 수 있음.

float3 viewDir - 뷰 방향을 포함합니다. 시차 효과, 림 라이팅 등의 계산에 사용

float4 screenPos - 반사 효과의 스크린스페이스 위치 또는 스크린스페이스 효과를 포함합니다.

float3 worldPos - 월드 공간상의 위치를 ​​포함합니다.

float3 worldRefl - Surface Shaders이 o.Normal에 기입하지 않는 경우 월드 반사 벡터를 포함

float3 worldNormal - Surface Shaders이 o.Normal에 기입하지 않는 경우 월드 법선 벡터를 포함

float3 worldRefl; INTERNAL_DATA - Surface Shaders이 o.Normal에 쓸 경우 월드 반사 벡터를 포함합니다. 

픽셀 당 법선 맵에 기초하여, 반사 벡터를 얻으려면 WorldReflectionVector(IN, o.Normal)를 사용합니다. 

float3 worldNormal; INTERNAL_DATA - _Surface Shaders가 o.Normal에 쓰는 경우 _ 월드 반사 벡터를 포함합니다. 

픽셀 당 법선맵에 기초하며, 법선 벡터를 얻으려면 WorldNormalVector (IN, o.Normal)를 사용합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
Shader "Example/Diffuse Distance" {
    Properties {
        _MainTex ("Texture", 2D) = "white" {}
        _Center ("Center", Vector) = (0,0,0,0)
        _Radius ("Radius", Float) = 0.5
     }
    SubShader {
        Tags { "RenderType" = "Opaque" }
        CGPROGRAM
        #pragma surface surf Lambert
        
        struct Input {
            float2 uv_MainTex;
            float3 worldPos;
        };
 
        sampler2D _MainTex;
        float3 _Center;
        float _Radius;
 
         void surf (Input IN, inout SurfaceOutput o) {
            float d = distance(_Center, IN.worldPos);
            float dN = 1 - saturate(d / _Radius);
 
             if (dN > 0.25 && dN < 0.3)
                o.Albedo = half3(1,1,1);
            else
                o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
        }
        ENDCG
    } 
    Fallback "Diffuse"
}
cs

22번째 줄에서 인스펙터에서 받은 _Center값과 그려질 픽셀(IN.worldPos)의 거리를 계산

23번째 줄에서 그것을 0~1 사이의 값으로 클램프함. _Center에 가까울수록 1, _Radius에 가까울수록 0

이후 거리가 일정 범위 안이면 Albedo를 흰색으로 만듬



서피스 함수

색 변경하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Shader "Example/Diffuse Simple" {
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #pragma surface surf Lambert
      struct Input {
          float4 color : COLOR;
      };
      void surf (Input IN, inout SurfaceOutput o) {
          o.Albedo = 1;
      }
      ENDCG
    }
    Fallback "Diffuse"
}
cs

#pragma surface surf Lambert는 surface함수 이름은 surf이고 Lambert(디퓨즈) 라이트 모델을 사용한다는 의미

10번째줄 o.Albedo = 1에서 아웃풋의 색상을 흰색으로 변경함.



텍스쳐 적용하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Shader "Example/Diffuse Distance" {
    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"
}
cs

Input에서 tex2D() 함수를 통해 _MainTex에서 uv_MainTex 좌표의 색상 정보를 가져와서 적용한다.



노멀맵 적용하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Shader "Example/Diffuse Distance" {
    Properties {
        _MainTex ("Texture", 2D) = "white" {}
        _BumpMap ("Bumpmap", 2D) = "bump" {}
     }
    SubShader {
        Tags { "RenderType" = "Opaque" }
        CGPROGRAM
        #pragma surface surf Lambert
        
        struct Input {
            float2 uv_MainTex;
            float2 uv_BumpMap;
        };
 
        sampler2D _MainTex;
        sampler2D _BumpMap;
         void surf (Input IN, inout SurfaceOutput o) {
            o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
            o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));
        }
        ENDCG
    } 
    Fallback "Diffuse"
}
cs

텍스쳐 적용과 마찬가지로 노멀맵을 받아와서 o.Normal에 UnpackNormal로 텍스쳐를 적용



기타 서피스 셰이더의 사용 예시는 공식문서를 참고

https://docs.unity3d.com/kr/530/Manual/SL-SurfaceShaderExamples.html

Posted by misty_
,