Cubemap Reflection

2022. 7. 25. 14:11Public/Shader

실시간 반사는 다른 연산들보다 상당히 무거운 연산인 것은 사실이다. 
그래서 많이 사용하는 방식은 Cubemap이라는 환경 텍스처를 이용해 주변 이미지를 텍스처로 만든 후 이를 오브젝트에 씌우는 방식을 많이 사용한다.

 

기본 적인 Cubemap을 적용하는 코드는 다음과 같다.

 

Shader "Custom/0725Reflection"
{
    Properties
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}        
        _Cube("CubeMap",Cube) = ""{}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        #pragma surface surf Lambert noambient

        #pragma target 3.0

        sampler2D _MainTex;        
        samplerCUBE _Cube;



        struct Input
        {
            float2 uv_MainTex;            
            float3 worldRefl; //UV가 아닌 반사 벡터를 받아옵니다.
        };

        void surf (Input IN, inout SurfaceOutput o)
        {   
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
            //Cubemap 텍스쳐를 연산하는 함수인 texCUBE를 이용해 텍스처의 컬러를 만듭니다.
            //texCUBE에는 UV 자리에 float3의 반사 벡터가 들어가야 합니다.
            float4 re = texCUBE(_Cube,IN.worldRefl);
            o.Albedo = 0;
            o.Emission = re.rgb;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

쉐이더가 적용된 모습

 

여기에 NormalMap을 적용해 봅시다.

하지만 여기에서 주의할 점은 평범하게 NormalMap을 적용하면 에러가 발생합니다.

 

Shader "Custom/0725Reflection"
{
    Properties
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}   
        _BumpMap("NormalMap",2D) = "bump"{}//추가
        _Cube("CubeMap",Cube) = ""{}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        #pragma surface surf Lambert noambient

        #pragma target 3.0

        sampler2D _MainTex;        
        sampler2D _BumpMap;//추가
        samplerCUBE _Cube;



        struct Input
        {
            float2 uv_MainTex;            
            float2 uv_BumpMap; //추가
            float3 worldRefl;
        };

        void surf (Input IN, inout SurfaceOutput o)
        {   
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
            float4 re = texCUBE(_Cube,IN.worldRefl);
            o.Albedo = 0;
            //에러발생
            o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
            o.Emission = re.rgb;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

 

이러한 에러가 발생하는 이유는 Input에서 float3 worldRefl이나 float3 worldNormal과 같이 '버텍스 월드 노멀'에 관련된 데이터를 받아와서 surf 함수 내부에서 사용하면서, 동시에 '탄젠트 노멀'인 UnpackNormal 함수를 거친 노멀 데이터를 함수 내부에서 같이 사용하면 에러가 발생합니다.

 

그럼 NormalMap에 대응되는 반사 벡터를 원하니 '픽셀 월드 노멀'로 변경해야합니다.

Shader "Custom/0725Reflection"
{
    Properties
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}   
        _BumpMap("NormalMap",2D) = "bump"{}//추가
        _Cube("CubeMap",Cube) = ""{}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        #pragma surface surf Lambert noambient

        #pragma target 3.0

        sampler2D _MainTex;        
        sampler2D _BumpMap;
        samplerCUBE _Cube;



        struct Input
        {
            float2 uv_MainTex;            
            float2 uv_BumpMap; 
            float3 worldRefl;
            //추가
            INTERNAL_DATA
        };

        void surf (Input IN, inout SurfaceOutput o)
        {   
            //변경
            o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));            
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
            //변경
            float4 re = texCUBE(_Cube,WorldReflectionVector(IN,o.Normal));
            o.Albedo = 0;            
            o.Emission = re.rgb;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

 

 

 

 

-정리-

- 버텍스로 받는 반사벡터는 worldRefl이 존재해야함

- INTERNAL_DATA라는 키워드를 추가해야함 (버텍스 노멀 데이터를 픽셀 노멀 데이터로 변환시키기위한 행렬들이 가동됨)

- 위 코드에서 노말연산을 위로 올리는데 그 이유는 o.Normal을 아래에서 사용하기 위함

- WorldReflectionVector(IN,o.Normal) 함수를 이용해 'NormalMap이 적용된 월드 좌표계의 픽셀 노멀'을 뽑아서 큐브맵의 UV로 사용

 

 

 

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

알파 테스팅과 컷아웃  (0) 2022.07.26
Alpha Blend  (0) 2022.07.25
커스텀 라이팅2  (0) 2022.07.17
커스텀 라이팅  (0) 2022.07.17
좌표 공간  (0) 2022.07.10