텍스쳐 한 장을 받는 쉐이더 스크립터를 만들어준다.

램버트 라이팅 세팅으로

 

Shader "Custom/Test"
{
    Properties
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        #pragma surface surf Lambert

        sampler2D _MainTex;

        struct Input
        {
            float2 uv_MainTex;
        };

        void surf (Input IN, inout SurfaceOutput o)
        {
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
            o.Albedo = c.rgb;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

 

----

 

큐브맵을 받을수 있는 프로퍼티를 뚫는다 .

 

 

큐브맵을 받는 형식은 Cube로

 

윈도우 - 렌더링 - 라이팅 세팅에 넣어야한다.

 

 

먼저

 

 

메터리얼에 큐브맵을 넣어준다.

 

 

메터리얼을 스카이박스메터리얼에 넣어준다.

★ 책에서 나온게 버전업 되면서 바뀌었다.

우리가 만든 메테리얼을 넣는게 아니라 검색해서 넣어야한다.

 

우리가 만든 메테리얼은 로봇에다가 넣을 것 이기 때문에

 

로봇 켈리 넣고,

메터리얼 넣고

 

 

sky박스가 반사되도록 만들것이다.

 

 

Input 에

 

 

 

월드 리플렉션이 있음 이걸 사용

 

이걸 똑같이 안쓰면 하드한 리플렉션 공식을 넣어야함

 

 

texCUBE (엔디비아 CG 용어)를 사용해서 이미지를 넣어야한다.

 

 

texCUBE(큐브텍스트 이미지 , 월드 리플렉션) = float4 로 반한

 

 

이미지션에 넣어서 테스트 하기

 

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

        CGPROGRAM
        #pragma surface surf Lambert

        sampler2D _MainTex;
        samplerCUBE _Cube;

        struct Input
        {
            float2 uv_MainTex;
            float3 worldRefl;
        };

        void surf (Input IN, inout SurfaceOutput o)
        {
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
            float4 ref =  texCUBE(_Cube, IN.worldRefl);
            o.Albedo = c.rgb;
            o.Emission = ref.rgb;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

 

 

 

 

반사되는걸 확인 가능

 

이미션에 넣는 이유, 밝고 어두움을 반사하는데 빛을 넣는다고 밝아 지는게 아니기 때문에 (거울 예제)

 

지금은 흰색인 이유는 알베도에 흰색에 있고, 이미션에도 있어서 1이 넘어서 그럼

 

// 알베도랑 이미션을 같이 쓰면 밝아진다.

 

그래서 알베도를 0으로 만들고, 이미션에 반사된 값을 출력해보자

 

 

---

 

노멀을 넣으면 오류가 생긴다 .

 

 

 

 

이터널 데이터를 써줘야한다

 

 

이터널 데이터를 써주지 않으면

 

★ 월드 리플렉션이랑 월드 노멀을 같이 쓸수가 없다.

 

인풋에 넣어주고

 

 

 

노멀을 넣으면 월드 노멀을 넣ㅇ어줘야한다

 

 

 

노멀에 해당하는 반사벡터를 얻을려면 WorldReflctionVector 써줘야함

노멀을 먼저 쓰고 그걸 받아서 써주는 것이다 !

float4 ref = texCUBE(_Cube, WorldReflectionVector(IN, o.Normal));

 

 

----

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

        CGPROGRAM
        #pragma surface surf Lambert

        sampler2D _MainTex;
        samplerCUBE _Cube;
        sampler2D _Normal;
        struct Input
        {
            float2 uv_MainTex;
            float3 worldRefl;
            float2 uv_Normal;
            INTERNAL_DATA
        };

        void surf (Input IN, inout SurfaceOutput o)
        {
            o.Normal = UnpackNormal(tex2D(_Normal, IN.uv_Normal));
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
            float4 ref =  texCUBE(_Cube, WorldReflectionVector(IN, o.Normal));

            o.Albedo = 0;
            o.Emission = ref.rgb;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

 

 

 

 

 

 

----

 

총 과정

 

메터리얼 하나 받는 쉐이더 작성

기본 Lambert 라이트 모델 적용

큐브맵을 받게 프로퍼티 작성

타입을 Cube

변수선언시 타입을 samplerCUBE로

Input 구조체에 worldRefl 정의

texCUBE 함수를 사용해 큐브맵 적용 (_Cube, IN.worldRefl)

결과값이 re 값을 확인(Emission에서)

범프 텍스쳐 넣을 수 있게 속성정의

노멀이 적용된 반사벡터를 구하기 위해서 WorldReflectionVector함수 사용

결과 확인 (Emission)


노말맵을 추가시켰더니 에러가 난다. 에러 내용을 대충 훑어보면

 

Shader error in 'Custom/Post_Work1': Surface shader Input structure needs

INTERNAL_DATA for this WorldNormalVector or WorldReflectionVector usage at

line 200 (on d3d11)

 

INTERNAL_DATA , WorldNormalVector, WorldReflectionVector 관련해서

키워드를 얻을 수 있어서 유니티 홈페이지에서 찾아보았다.

 

정확히는 무슨 말인지는 모르겠지만 worldRefl을 사용할 때 노말 맵을 쓸 경우

WorldReflectionVector를 사용하는데, 픽셀당 반사 벡터를 사용하기 위해

Input구조체에서 INTERNAL_DATA를 선언해서 뭔가 컴파일해주는 듯..?

 

좀 더 쉽게 설명하면 탄젠트 좌표계를 월드 좌표계로 변환시켜주어야 하는데

그 과정에서 변환이 되지 않아 에러가 났던 것이고 INTERNAL_DATA를 통해서

변환해주는 듯하다. (자세한 것은 모르겠다..)

 

유니티가 PBR로 바뀌면서 이런 식으로 큐브 맵 사용이 변경되었다 한다.

그러면 일단 한번 수정해보자.

struct Input { float2 uv_MainTex, uv_NormalMap; float3 worldRefl; INTERNAL_DATA }; void surf (Input IN, inout SurfaceOutput o) { fixed4 c = tex2D (_MainTex, IN.uv_MainTex); o.Normal = UnpackNormal(tex2D(_NormalMap, IN.uv_NormalMap)); o.Emission = texCUBE(_CubeMap, WorldReflectionVector(IN, o.Normal)); o.Albedo = c.rgb; o.Alpha = c.a; }

헬멧 MaskMap 추가

만들었던 큐브맵 머티리얼을 헬멧 모델에 적용하여

금속 재질인 것처럼 표현하고 마스크 맵을 적용하여 부분적으로 적용되도록 해보겠다.

Shader "Custom/Post_Work1"
{
    Properties
    {
        _MainTex("Albedo (RGB)", 2D) = "white" {}
        _NormalMap("NormalMap", 2D) = "bump" {}
        _MaskMap("MaskMap", 2D) = "bump" {}    
        _CubeMap("CubeMap", cube) = "" {}
 
        [HDR]_Color("Color", color) = (1,1,1,1)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
 
        CGPROGRAM
        #pragma surface surf Lambert 
        #pragma target 3.0
 
        sampler2D _MainTex, _NormalMap, _MaskMap;
        samplerCUBE _CubeMap;
 
        struct Input
        {
            float2 uv_MainTex, uv_NormalMap, uv_MaskMap;
            float3 worldRefl;
            INTERNAL_DATA
        };
 
        float4 _Color;
 
        void surf (Input IN, inout SurfaceOutput o)
        {
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
            fixed4 m = tex2D(_MaskMap, IN.uv_MaskMap);
 
            o.Normal = UnpackNormal(tex2D(_NormalMap, IN.uv_NormalMap));
            o.Emission = texCUBE(_CubeMap, WorldReflectionVector(IN, o.Normal)) * m.a * _Color;
            o.Albedo = c.rgb;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

Reflection Probe 사용하기

리플렉션 프로브란 해당 오브젝트를 배치하여 구역 내에 주변 static오브젝트들을

캡처하여 큐브 맵 데이터로 저장하는 기능이다.

 

 


void surf (Input IN, inout SurfaceOutput o)

{

fixed4 c = tex2D (_MainTex, IN.uv_MainTex);

fixed4 m = tex2D(_MaskMap, IN.uv_MaskMap);


o.Normal = UnpackNormal(tex2D(_NormalMap, IN.uv_NormalMap));


fixed3 wr = WorldReflectionVector(IN, o.Normal);

//fixed3 p = texCUBE(_CubeMap, wr);

fixed3 r = UNITY_SAMPLE_TEXCUBE(unity_SpecCube0, wr) * unity_SpecCube0_HDR.r;


o.Emission = r * m.a;

o.Albedo = c.rgb;

o.Alpha = c.a;

}

유니티에서 리플렉션 프로브로 큐브 맵을 받기 위해서는 UNITY_SAMPLE_TEXCUBE()를 사용해야 한다.

unity_SpecCube0, unity_SpecCube0_HDR은 리플렉션 프로브 데이터를 가지고 있으며,

unity_SpecCube가 아니라 unity_SpecCube0이 붙은걸 보면 뒤에 1도 존재한다는 것도 알 수 있고

HDR도 1이 존재한다.

 

이를 설명하기 위해서 오브젝트 Mesh Renderer 인스펙터 부분을 보면 Light Probes에

Blend Probes라는 항목이 존재하는데, 리플렉션 프로브 영역으로 이동할 때 리플렉션 이미지가 갑자기 바뀌는 것을 방지하기 위해 블렌딩 해주는 것이라고 한다.

 

 

 

 

 

ref : https://minquu.tistory.com/161

ref : https://bornsoul.tistory.com/15

반응형

+ Recent posts