ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Fresnel(프레넬) & Rim 라이트
    유니티/게임그래픽 2024. 2. 22. 15:38

    Rim 라이트 : 역광이 있을때 털이나 반투명 재질을 가진 물체들이 반사율에 따라 반사가 나타나는것

    몸 윤곽선에 보이는 얇은 하얀색 부분을 Rim 라이트라고 이해하면 쉽다

     

    유니티에 물리기반 쉐이더는 BRDF라는 함수를 이용해 구현되어 있다.

    현실에서 그렇듯 유니티에서도 물질의 재질에 따라 반사율이 달라진다. 그리고 이러한 반사공식을 Fresnel이라고 한다

    원래 Fresnel은 빛 방향과 연관되어 만들수 있겠지만 주로 게임안에서는 캐릭터의 분리와 강조를 위한 수단으로 사용한다

    이제 Rim 라이트와 Fresnel에 대해서 알아봤으니 먼저 Fresnel 공식부터 구현해보자

     

    Shader "Custom/NewSurfaceShader"
    {
        Properties
        {
            _MainTex ("Albedo (RGB)", 2D) = "white" {}
        
        }
        SubShader
        {
            Tags { "RenderType"="Opaque" }
            CGPROGRAM
            #pragma surface surf Standard fullforwardshadows
            sampler2D _MainTex;
    
            struct Input
            {
                float2 uv_MainTex;
            };
    
            void surf (Input IN, inout SurfaceOutputStandard o)
            {
                fixed4 c = tex2D(_MainTex, IN.uv_MainTex);
                o.Emission = 0;
            }
            ENDCG
        }
        FallBack "Diffuse"
    }

    우선 색은 기본적인 검정색을 출력하도록 한다

    이제 새로운 무언가를 받아보자. 우선 struct Input 구조체 안에 있는 변수라면 엔진에서 받을 수 있는 데이터라는 의미이다

     

    이번에 받을 데이터는 viewDir이라는 이름의 뷰 벡터이다

    float3 lightDir이 버텍스에서 바라보는 조명의 방향을을 나타내는 길이가 1인 벡터를 의미 했다면

    float3 viewDir은 버텍스에서 바라보는 카메라의 방향을 나타낸다

     

    둘은 무엇을 바라보냐만 다를뿐, 조명 대신 뷰 벡터를 넣어 계산한다면 뷰 벡터는 라이팅처럼 연산이 될 것이다

    즉 내가 바라보는 방향이 계속 밝아진다는 의미이다

     struct Input
     {
         float2 uv_MainTex;
         float3 viewDir;
     };
    
     void surf (Input IN, inout SurfaceOutputStandard o)
     {
         fixed4 c = tex2D(_MainTex, IN.uv_MainTex);
         o.Albedo = 0;
         // 추가
         float rim = dot(o.Normal, IN.viewDir);
         o.Emission = rim;
     }

    어느 쪽에서 바라보던 마치 카메라에서 빛이 나듯 내 시점에서는 항상 밝아진다

     

                o.Emission = 1-rim;

    그리고 이제 이 결과를 뒤집어주자

    이제 우리가 알고 있던 rim 라이트처럼 보이기 시작한다. 하지만 좀 더 현실감있게 만들기 위해서는

    좀더 흰 테두리를 얇게 만들어줄 필요가 있다

     

                o.Emission = pow(1-rim,3);

     

    그럴땐 역으로 바꿔준값에 3을 제곱하면 된다

    이제 완성된 Rim 라이트를 내 입맛에 맞게 색상을 변경하고 넓이를 조절할 수 있게 만들어보자

     

    Shader "Custom/NewSurfaceShader"
    {
        Properties
        {
            _MainTex ("Albedo (RGB)", 2D) = "white" {}
            _RimColor ("Rim color", Color) = (1,1,1,1)
            _RimPow ("Rim Pow", Range(1,10)) = 3
        
        }
        SubShader
        {
            Tags { "RenderType"="Opaque" }
            CGPROGRAM
            #pragma surface surf Standard fullforwardshadows
            sampler2D _MainTex;
            float4 _RimColor;
            float _RimPow;
    
            struct Input
            {
                float2 uv_MainTex;
                float3 viewDir;
            };
    
            void surf (Input IN, inout SurfaceOutputStandard o)
            {
                fixed4 c = tex2D(_MainTex, IN.uv_MainTex);
                o.Albedo = 0;
    
                float rim = dot(o.Normal, IN.viewDir);
                o.Emission = pow(1-rim, _RimPow) * _RimColor.rgb;
            }
            ENDCG
        }
        FallBack "Diffuse"
    }

    이건 어렵지 않다. Pow 역할을 해주는 변수를 range 형식으로 만들어준뒤 값안에 3 대신 넣어주면 된다

    색상도 하나 만들어주고 출력값 옆에 rgb를 곱해주면 된다

     

    이제 Normal Map 을 이용하여 rim 라이트가 빛나게 만들어보자

    여기서는 Albedo 와 Emission을 더하면 밝아지는것을 이용하면 된다

     

    Shader "Custom/NewSurfaceShader"
    {
        Properties
        {
            _MainTex ("Albedo (RGB)", 2D) = "white" {}
            _BumpMap ("Albedo (RGB)", 2D) = "white" {}
            _RimColor ("Rim color", Color) = (1,1,1,1)
            _RimPow ("Rim Pow", Range(1,10)) = 3
        
        }
        SubShader
        {
            Tags { "RenderType"="Opaque" }
            CGPROGRAM
            #pragma surface surf Standard fullforwardshadows
            sampler2D _MainTex;
            sampler2D _BumpMap;
            float4 _RimColor;
            float _RimPow;
    
            struct Input
            {
                float2 uv_MainTex;
                float2 uv_BumpMap;
                float3 viewDir;
            };
    
            void surf (Input IN, inout SurfaceOutputStandard o)
            {
                fixed4 c = tex2D(_MainTex, IN.uv_MainTex);
                o.Albedo = c.rgb;
                
                //Normal Map
                fixed4 d = tex2D(_BumpMap, IN.uv_BumpMap);
                float3 normal = UnpackNormal(d);
                o.Normal = normal;
    
                float rim = dot(o.Normal, IN.viewDir);
                o.Emission = pow(1-rim, _RimPow) * _RimColor.rgb;
            }
            ENDCG
        }
        FallBack "Diffuse"
    }

    텍스쳐가 깨진것같이 보이지만 정확히는 너무 밝아서 깨진것처럼 보이는것이다

     

     

    '유니티 > 게임그래픽' 카테고리의 다른 글

    홀로그램 응용  (0) 2024.02.24
    홀로그램  (0) 2024.02.24
    Half-Lambert  (0) 2024.02.22
    Vertex Color 응용  (0) 2024.02.22
    Lambert 커스텀 라이트  (0) 2024.02.21
Designed by Tistory.