커스텀 라이팅2

2022. 7. 17. 20:27Public/Shader

Tags {"LightMode" = "ForwardBase"}

이것의 의미는 이 패스를 포워드 렌더러의 첫 번째 라이트 패스로 사용하겠다는 것이다. ForwardBase 패스가 오직 하나라면 첫 번째 빛을 제외한 다른 빛은 최종 결과에 영향을 미치지 않을 것이다. 만약 다른 빛도 영향을 주길 원한다면 또 다른 패스를 추가하고 그것의 태그를 다음과 같이 바꾼다.

Tags {"LightMode" = "ForwardAdd"}

 

#include "UnityLightingCommon.cginc"

 

UnityLightingCommon.cginc는 라이팅 셰이더에 필요한 많은 유용한 변수 및 함수들이 담긴 파일이다.

 

커스텀 라이팅을 할때 주의해야 할 점은 

노멀 벡터와 빛의 방향 벡터의 좌표 공간을 일치시켜야 한다. 생각해보자. 객체 공간을 사용해선 안 된다. 왜냐하면 빛은 렌더링하는 모델의 바깥에 있기 때문이다. 이러한 라이팅 계산을 하는 데 적합한 공간은 월드 공간이다.

 

 

먼저 렌더러에게 노멀 벡터에 대한 정보를 받아야한다. 따라서 렌더러에게 요청하는 정보가 담긴 appdata에 노멀 슬롯을 하나 추가해야한다. 

 

            struct appdata
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL; //추가
            };

NORMAL 시맨틱 선언을 추가해 노멀을 사용하겠다고 컴파일러에게 알려주고 있다.

 

 

이 정점 함수에서는 노멀 위치 벡터를 월드 공간에서 계산해야 한다.

우리에게는 편리한 함수가 존재한다. UnityObjectToWorldNormal

이 함수는 appdata를 통해 정점 셰이더로 방금 전달한 노말 벡터를 기존의 객체 공간에서 월드 공간으로 변환한다.

            v2f vert(appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                float3 worldNormal = UnityObjectToWorldNormal(v.normal); //추가 , 월드 노멀 벡터 계산
                o.worldNormal = worldNormal; //추가 , 출력 데이터 구조체에 할당
                return o;
            }
            struct v2f
            {
                float4 vertex : SV_POSITION;
                float3 worldNormal : TEXCOORD0; //추가 , 출력 구조처에 결과 값을 할당해야 한다.
            };

TEXCOORD0 시맨틱을 사용해 해당 슬롯을 추가해야 한다. 그러면 3차원 혹은 4차원 벡터에 적합한 슬롯을 ㅏㅅ용할 것이라고 알려주는 것이다.

 

필요한 정보를 얻기 위해 이제 람버트 디퓨즈를 계산에 이용할 수 있게 됐다.

광원의 색상을 _LightColor0을 통해 얻을 수 있다. LightColor0은 방금 추가한 include 파일에 존재한다. 그리고 월드 공간상의 씬 내에 첫 번째 광원의 위치는 _WorldSpaceLightPos0 변수를 통해 구할 수 있다. 

 

변환을 거치면 벡터의 크기가 1이 아닐 수도 있기 때문에 프레그먼트 셰이더에서는 우선 worldNormal값을 정규화해야 한다. 그런 후 노멀 값과 빛의 위치 벡터의 내적을 계산한다. 계산 결과가 음수 값이 되지 않도록 주의해야 한다. max 함수에서 이것을 담당한다.

 

            fixed4 frag(v2f i) : SV_Target
            {
                float3 normalDirection = normalize(i.worldNormal);
                
                //WorldSpaceLightPos0 : 월드 공간상의 씬 내에 처 번째 광원의 위치
                float nl = max(0.0, dot(normalDirection,_WorldSpaceLightPos0.xyz)); //변환후 벡터의 크기가 1이 아닐 수도 있기 때문에 정규화
                float4 diffuseTerm = nl * _Color * _LightColor0; //광원의 색상을 얻을수 있다. (UnityLightingCommon.cginc)

                return diffuseTerm;
            }

 

내적 값과 함께 표면의 색상값과 광원의 색상값을 모두 곱한다. 이것이 끝이다.

 

Shader "Custom/DiffuseShader"
{
    Properties
    {
        _Color("Color", Color) = (1,0,0,1)
    }

        SubShader
    {
        Tags { "LightMode" = "ForwardBase"}

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            //CGPROGRAM문 뒤쪽 어딘가에 선언을 추가
            fixed4 _Color;


            #include "UnityCG.cginc"
            #include "UnityLightingCommon.cginc"


            struct appdata
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float3 worldNormal : TEXCOORD0; //추가 , 출력 구조처에 결과 값을 할당해야 한다.
            };

            v2f vert(appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                float3 worldNormal = UnityObjectToWorldNormal(v.normal); //추가 , 월드 노멀 벡터 계산
                o.worldNormal = worldNormal; //추가 , 출력 데이터 구조체에 할당
                return o;
            }
            fixed4 frag(v2f i) : SV_Target
            {
                float3 normalDirection = normalize(i.worldNormal);
                
                //WorldSpaceLightPos0 : 월드 공간상의 씬 내에 처 번째 광원의 위치
                float nl = max(0.0, dot(normalDirection,_WorldSpaceLightPos0.xyz)); //변환후 벡터의 크기가 1이 아닐 수도 있기 때문에 정규화
                float4 diffuseTerm = nl * _Color * _LightColor0; //광원의 색상을 얻을수 있다. (UnityLightingCommon.cginc)

                return diffuseTerm;
            }
            ENDCG
        }
    }
}

람버트 디퓨즈로 셰이딩한 미니언즈

'Public > Shader' 카테고리의 다른 글

Alpha Blend  (0) 2022.07.25
Cubemap Reflection  (0) 2022.07.25
커스텀 라이팅  (0) 2022.07.17
좌표 공간  (0) 2022.07.10
정점 색상 지원  (0) 2022.07.10