본 포스팅에서는

1. RimLight가 무엇인지

2. RimLight를 통해 어떤 효과를 기대 할 수 있는지

3. RimLight를 구현하기 위한 프레넬 공식

4. RimLight구현하는 방법

에 대해 알아보려 합니다. 

 


1. RimLight가 무엇인가? 

 

RimLight는 "모든 물체는 기울어질수록 반사가 심해진다" 라는 현상에서 부터 시작됩니다. 

 

이때 역광이 있을때 털이나 반투명 재질을 가진 물체들은 이 현상이 매우 강렬하게 나타납니다. 

 

사진 분야에서 이 현상을 RimLight 라고 합니다. 

 

림 라이트 예제 이미지1

 

림 라이트 예제 이미지 2

두 예제 이미지를 보면 머리카락이나 옷 부분을 보면 역광에 반사가 심해져 윤곽선 같은 느낌이 나는걸 볼 수 있습니다.

 

이것이 RimLight 입니다. 

 


 

2. RimLight를 통해 어떤 효과를 기대 할 수 있는지

기본적으로 게임에서는

1. 배경과 캐릭터의 분리나 강조 효과

2. 캐릭터가 선택 되었을 때나 특정 상태를 표현하기 위한 이펙트

3. 셀 세이딩 효과 같은 특수한 효과를 위해

과장되도록 사용합니다. 

 

 

RimLight 효과가 적용 되기 전 

 

RimLight가 적용된 이후

RimLight 예제 이미지 처럼 외곽선 부분이 강조된걸 볼 수 있습니다.

이 때문에 배경과 캐릭터가 구분 되는 효과를 볼 수 있습니다.

 

 


 

3. RimLight를 구현하기 위한 프레넬 공식

 

프레넬?

 

프레넬 방정식(Fresnel equations) 또는 프레넬 공식(Fresnel's formulas)은 반사계수와 투과계수에 관한것으로 한 매질과 광학적 특성 즉, 굴절률이 다른 매질의 계면에서 반사 또는 투과 진폭을 입사진폭으로 나눈 값을 말한다. 프랑스의 물리학자 오귀스탱 장 프레넬이 유도하였다.

( 위키백과 )

 

라고 하는데

 

프레넬은 아주 쉽게 말해서 각 재질에 따른 반사 정도를 나타냈다고 이해합시다...

실제로 프레넬은 프로그램에서 대체로 빛을 반사하는 값의 정도를 조절하는 값인 경우가 많다.

 

 

근데 RimLight를 구현하는데 왜 갑자기 프레넬이 튀어 나오냐구요?

 

 

왜냐면 RimLight는 결국 역광에서 나온 빛이 반사가 되어 생긴 현상이기 때문입니다. ( 글쓴이의 얕은 추론의 결론... )

따라서 반사와 투과에 대한 공식인 프레넬은 림라이트를 포함하는 개념입니다. ( 이것은 아래 레퍼런스 참고..!)

 

 

 

 


3. RimLight 구현

RimLight를 구현하는 과정을 간략하게 정리해보려합니다.

 

 

 

a. RimLight은 Lembert 공식(  N Dot L ) 에서 L을 V로 바꾼것

b. 그 결과값을 1 - 결과값 으로 뒤집어 버린다.

c. 그리고 POW를 통해 값을 급격하게 높혀버린다. 이를 통해 외곽선이 뚜렷하게 보이는 것

 

 


 

테스트 모델은 이 에셋을 이용합니다.

https://assetstore.unity.com/packages/essentials/asset-packs/the-blacksmith-characters-39941

 

 

The Blacksmith: Characters - Asset Store

This package includes the characters from “The Blacksmith” short film: - The Blacksmith character - The Challenger character - Hair Shader - Wrinkle maps - Unique character shadows - Plane reflections Please visit this blog post for more information: "The

assetstore.unity.com

 

이름 : 빡빡이 아조씨

캐릭터에 메테리얼이 많이 붙어있기 때문에 머리만 남겨두고 진행합니다. 

1. 프레넬 공식 기본 코드

 

유니티에서 Standard Shader로 생성을 한 후 

라이팅을 Lambert로 하고 환경광을 제거해줍시다.

그리고 쓸데 없는 부분들은 싹 정리 해줍시다. ( 코드 1 )

 

코드 1 : 라이팅을 Lambert로 만들어줬다.

 

아 참고로 더이상 스탠다드 라이팅이 아니기 때문에 Inout에서

SurfaceOutputStandard 쪽에 문제가 생길겁니다. 이것을 SurfaceOutput로 바꿔줘야 합니다.

 

 


그 다음

 

 알베도를 0으로 만들어서 검정색으로 만들어 봅시다. 

왜 검정색으로 만드냐면 라이팅 효과를 제대로 보면서 하고 싶기 때문입니다.

나중에 다시 rgb를 넣어줘서 피부를 되찾아줄겁니다. 

 

위 코드의 결과값입니다.

 

 

마치 코난의 범인 실루엣 같습니다.

이 대머리 아조씨는 어떤 사연을 가지고 살인을 저질렀을까요.

코난의 추리로 사건의 전말이 모두 까발려지고 울먹이면서 어떤 구구절절한 사연을 이야기할지 기대가 됩니다. 

 

 


 

 

RimLight는 Lambert 공식 ( N Dot L ) 에서  L을 V로 바꿔 카메라 벡터를 빛 처럼 받게 합니다. 

 

Lambert 라이트 기본 개념

여기서 L (라이트벡터) 대신 V (뷰 벡터)( 카메라 벡터 ) 로 바꾸면 어떻게 될까요?

원래 빛을 무시하고 카메라를 빛처럼 인식하게 됩니다. 

 

따라서 광원에 따라서 빛이 생기는 것이 아닌 카메라에 따라 빛이 생기는 것입니다.

 

그렇다면 카메라 벡터를 가지고 와야겠죠? 

 

Input에 viewdir (뷰벡터)를 추가합니다. ( 코드 2 ) 

 

코드 2 : viewDir 추가 

 

그리고 ( N dot V ) 값을 Emission에 넣어줍니다. ( 코드 3 )

 

 

 

 코드 3 

 

 

결과값을 봅시다. 

코드3의 결과값

코난에게 구구절절하게 사연을 말하고 자신의 죄를 씻어내기 위해 하얀 죄수복을 입게 되었군요. ( 개소리 ) 

 

( N dot V )라서 카메라가 마치 조명인것 처럼 인식을 하고 있습니다. 

 

 


 

 

( N dot V ) 의 결과값을 뒤집어 줍니다. ( 코드 4 )

 

 

 

코드4

 

 

코드4의 결과값 

결과값을 뒤집어 ( 반전 ) 시켜줘 제일 밝은 부분이 어두운 부분이 되어버렸습니다. 

 

이 상태에서 제일 흰 부분의 영역을 좁히면 RimLight 현상을 구현해볼수 있지 않을까요??? 

 


흰 부분의 영역을 좁히려면 어떻게 해야할까요? 

 

바로 제곱을 통해 영역을 좁힐 수 있습니다. 

 

제곱을 하게 되면

 

 

이런 일정한 값을 가지고 있는 그래프를 

 

 

이렇게 휘게 만들 수 있습니다. 

 

 

 

더 자세하게 보자면 

 

 0.5 부분에서는 값의 변화율이 굉장히 적습니다.

하지만 그 이후부터는 엄청난 변화율을 보여주게 됩니다. 

따라서 값이 극단적으로 변하게 된다고 보면 됩니다. 

 

자! 이 지식을 가지고 다음으로 넘어가 봅시다!

 

rim 값을 제곱해봅시다. ( 코드 5 ) 

pow함수를 통해 제곱이 가능합니다.

코드5: 제곱을 해줬다. 

 

값이 균등하게 바뀌는 것이 아니라 극단적으로 확 변하게 되었습니다. 

 

따라서 

 

코드4의 결과값 

 

제곱을 해준 코드 5의 결과값

 

검은색 부분의 영역은 많아 지고 흰색 부분의 영역이 좁아지는 것입니다.

 

 

 

 

 

완성 코드

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
34
35
36
37
38
39
40
41
42
43
44
Shader "Custom/RimLight_Re1"
{
    Properties
    {
        _Color ("Color"Color= (1,1,1,1)
        _MainTex ("Albedo (RGB)"2D= "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
 
        CGPROGRAM
        #pragma surface surf Lambert noambient
        #pragma target 3.0
 
        sampler2D _MainTex;
 
        struct Input
        {
            float2 uv_MainTex;
            float3 viewDir;
        };
 
   
        fixed4 _Color;
 
    
 
        void surf (Input IN, inout SurfaceOutput o)
        {
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;// //  
            o.Albedo = 0;
 
            float rim  = dot(o.Normal , IN.viewDir);
            rim = pow ( 1-rim , 3);
            o.Emission = rim;
            
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}
 
cs

 

 

 

 

 


 

- RimLight를 더 완성해보자 ! 

 

프레넬 기본형에 컬러랑 파워 추가해봅시다. ( 코드 6 )

 

코드 6
코드 6의 메테리얼 설정값

이렇게 해서 인스펙터창에서 값을 설정 할 수 있게 되었습니다. 

컬러도 조절 할 수 있어서 

코드 6 결과값

이렇게 깜직한 핫핑크 빡빡이 아조씨가 되었습니다.

 

핫핑크 아조씨의 피부를 다시 입혀줍시다.

 

피부 텍스처와 노말맵 텍스처를 받아와야 합니다. ( 코드 7 )

 

코드 7 : 

알베도에 값을 0에서 c.rgb로 바꿔주고

노말맵을 받아왔습니다.

 

코드 7 결과값

 

 


 

내적의 값이 -1 ~ 1 까지 되어 나중에 빛 연산을 해도 비정상적으로 어두운 상황을 막기 위해 

saturate 함수로 0~1까지 값을 짤라줍니다. ( 코드 8 )

 

 

코드 8 

 

 

 

- 최종 코드 -

 

 

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
Shader "Custom/RimLight_Re1"
{
    Properties
    {
        _Color ("Color"Color= (1,1,1,1)
        _MainTex ("Albedo (RGB)"2D= "white" {}
        _RimPower("RimPower" , Range(0,10)) = 0 
        _NormalMap ("NormalMap",2D ) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
 
        CGPROGRAM
        #pragma surface surf Lambert noambient
        #pragma target 3.0
 
        struct Input
        {
            float2 uv_MainTex;
            float2 uv_NormalMap;
 
            float3 viewDir;
        };
   
        fixed4 _Color;
        float _RimPower;
        sampler2D _MainTex;
        sampler2D _NormalMap;
 
    
        void surf (Input IN, inout SurfaceOutput o)
        {
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
            o.Albedo = c.rgb;
 
            o.Normal = UnpackNormal(tex2D (_NormalMap, IN.uv_NormalMap));// //
 
            float rim  = saturate(dot(o.Normal , IN.viewDir));
            rim = pow ( 1-rim , _RimPower);
            o.Emission = rim * _Color.rgb;
 
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}
 
cs

 

 

 


다음 포스팅은 RImLight를 활용한 홀로그렘을 제작해보려합니다.

 

 

 

레퍼런스 :

1. 유니티쉐이더 스타트업

2. https://meshmason.tistory.com/9

 

 

[Blender] 프레넬(Fresnel)이란 무엇인가

3D 툴을 다루다 보면 언젠가 한 번쯤은 들어보았거나, 반드시 이해해야만 하는 문제에 봉착할 수 있는 개념이 Fresnel이다. 아무래도 3D 물체에 재질을 입힐 때 여러가지 값을 설정해야만 되는데, 재질이란 것이..

meshmason.tistory.com

3. https://lifeisforu.tistory.com/384

 

[ PBR 이란 무엇인가 ] 17. Fresnel 이란?

주의 : 잘못된 내용이 포함되어 있을 수 있으므로 이상하면 참고자료를 확인하세요. [ PBR 이란 무엇인가 ] Fresnel 이란? 프레넬 공식이란? 앞서 [ [ 번역 ] 모든 것은 프레넬을 가집니다 ] 와 [ Reflection 에..

lifeisforu.tistory.com

 

 

 

 

+ Recent posts