Rim Light in Unity / 림라이트

 

캐릭터가 배경과 살짝 구분되게 라이팅을 먹여주는 셰이더를 만들 수 없을까? 뒷쪽에서 비치는 빛을 구현해주면 캐릭터의 외곽 라인이 빛나면서 배경과는 돋보이게 할 수 있지 않을까? 림라이트의 고민은 바로 여기서 시작한다. Back Light, Edge  Light라고도 불리는 이 라이팅 기법을 살펴보자.

rabbitrim1_

Valve가 공개한 reference 중에서 “Illustrative Rendering in Team Fortress 2” 를 보면
Albedo + Warped Diffuse + Ambient Cube + Specular + Rim Lighting 을 더해서 최종 색상을 결정한다. 이 때 어두운 부분의 값을 끌어올려 윤곽을 살려주는 Half Lambert, Artist 가 적절히 톤 조절이 가능한 Warped Diffuse, 주변 환경에 따른 Ambient 색상과 더불어 Rim Lighting 기능이 핵심 역할을 한다. 아래쪽 페이지 샷을 참고.

 

valve_tf2_rendering

 

Gamasutra에서 WolFire Games 의 David Rosen 이 쓴 아티클에서도 본인의 프로젝트 내부적으로 림라이팅을 커스터마이즈한 방식을 공유하고 있는데, 이 때 사용한 트릭은 Normal Map의 Alpha 값에 Rim Lighting 적용 값을 저장하여 Rim Lighting 적용해서 대상 내에서의 적용 위치와 강도를 정확히 컨트롤 하는 방식을 소개하고 있다. 물론 이 방식으로 갈 경우 Fragment Shader와 Normal Map을 사용을 피할 수 없다.

유니티에서 림라이팅 쉐이더를 구현하는 것은 크게 복잡하지는 않다.
림라이트의 세기, 즉 외곽 라이팅 엣지 부분의 빛의 세기를 결정하는 Core 식은 아래와 같다.

카메라, 혹은 벡터와 오브젝트 표면의 노멀 벡터를 Dot Product(내적) 시키면 된다.  나머지는 일반적인 Vertex, Fragment Shader 처리와 같다. 림라이팅 결과 값을 기존의 Texture Color, Diffuse Color, Specular Color 값들과 합쳐 주어 최종 값을 도출해 . 캐릭터의 외곽쪽은 내적의 값이 0 되고, 중앙으로 수록 1 되는 것을 이용하여 1에서 값을 빼주면, 결과적으로 외곽쪽이 가장 값을 가지게 되고, 중앙쪽이 가장 낮은 값을 가지게 되는 Rim Color 입혀지게 되는 원리이다.

Unity3D 에서 CG를 이용해서 Rim Light Shader 코드를 작성하면 아래와 같다.

위 쉐이더를 붉은 색 Color 물체에 적용하면 아래와 같이 나온다.

rimlight
외곽 라인이 이쁘게 빛난다.  : )
텍스쳐도 입히는 코드를 집어 넣고, 추가로 Rim Lighting 먹이는 부분을 조금더 정교하게 넣고, float을 남발한 부분을 적당히 half 나 fixed로 최적화 시키면 제법 멋진 쉐이더를 만들어 낼 수 있을 것이다.

 

Surface Shader와 내장 UnityCG Include 를 사용해서 작성하면 더 간단해진다.
이번에는 Specular가 빠진 대신 Texture를 입히고, Albedo 값을 텍스쳐에서 가져온다.

 

 

때로 이렇게 공식으로 유도된 림이 예쁘게 빠지지 않고 자글거릴 때가 있다. 이는 캐릭터나 오브젝트가 Low Polygon Modeling 이기 때문인데, 이 경우 Rim 값을 부드럽게 보정해주는 Ramp Texture를 사용하기도 한다.