프로그래밍 언어 입문서가 아닌 프로그래밍 기초 개념 입문서
문과생, 비전공자를 위한 프로그래밍 입문책입니다.
jobGuid 꽃미남 프로그래머 "Pope Kim"님의 이론이나 수학에 치우치지 않고 실무에 곧바로 쓸 수 있는 실용적인 셰이더 프로그래밍 입문서 #겁나친절 jobGuid "1판의내용"에 "새로바뀐북미게임업계분위기"와 "비자관련정보", "1판을 기반으로 북미취업에 성공하신 분들의 생생한 경험담"을 담았습니다.

Wrapped Diffuse

프로그래밍 2012.04.03 17:25
Posted by cagetu

오랜만이네요. 한 동안 멘탈이 붕괴되어서, 방황하다가 우리 아가랑 신나게 놀다가 정신차리고 돌아왔습니다. ㅎㅎ

슬슬 GDC12의 기술문서들이 올라오네요.. ㅎㅎㅎ.. 비록 GDC는 못 갔지만, 대충 어떤 흐름으로 전개가 되고 있는지는 대충 파악할 수 있겠군요. 공부할 것들이 태산이네요.. 하악 하악... 이 넘의 게임개발자란 직업은 정말이쥐.. ㅎㅎㅎ

하지만, 오늘은 조금 간단한 내용을 다루어 볼까 합니다. 바로 Diffuse 라이팅!!!! 


1. Lambert 라이팅 모델

가장 일반적으로 Diffuse 라이팅에 사용되는 공식이 바로 Lambert 공식입니다. 

float lambert_term = max(0, dot(normal, light_direction));

특별히 설명할 것이 없지만, Lambert 공식에 대한 특징은 "퐁퐁퐁"님의 Oren-Nayar Reflectance Lighting Model 를 보시면 잘 설명이 되어 있으니, 참고하시면 될 듯 합니다.

위의 내용에도 잘 나와 있지만, Lambert 모델은 플라스틱 같은 느낌의 표현이 됩니다. 


2. Half Lambert 라이팅 모델

Half Lambert 공식은 Value 사에서 Half-Life에서 처음 소개된 방식으로 오브젝트가 너무 어둡게 나오는 것을 방지하기 위한 목적으로 사용되었습니다. (https://developer.valvesoftware.com/wiki/Half_Lambert)








내용은 굉장히 간단합니다.

float halflambert_term = dot(normal, lightdirection) * 0.5f + 0.5f

float halflambert_pow_term = pow(dot(normal, lightdirection) * 0.5f + 0.5f, power);

계수에 의한 변화에 대한 결과는 대마왕J님의 블로그에 실험 결과가 올라와 있네요. (http://chulin28ho.egloos.com/5099713) 참고하면 될 듯 합니다.

Half Lambert는 물리적으로 올바르지는 않지만, 일반적으로 피부와 같이 약간 투과되는 느낌의 질감을 표현할 때, 꽤 효과가 좋습니다. 또 간단하게 셰이딩을 할 때에는 은근히 간접광을 받는 듯한 느낌도 있어서, 비교적 저렴하게 꽤 화사한 느낌을 만들어 낼 수 있습니다. 하지만, 결과적으로 너무 밝은 결과가 나오기 때문에, 사실적인 느낌의 게임 렌더링에서는 잘 맞습니다. 


3. Wrapped Diffuse 라이팅 모델

오늘의 주제인 Wrapped Diffuse 입니다. 제가 처음으로 Wrapped Diffuse 에 대해서 들어본 것은 몇 년 전 Valve에서 출시한 팀포트리스2 라는 게임에 대한 렌더링 기술문서에서 입니다. Diffuse 렌더링을 위해서 Wrapped Diffuse를 사용했다고 하는데, 그 때에는 이것이 무엇인지 정확하게 이해를 하지 못했습니다. 

(참고로 팀포트리스의 Wrapped Function은 Half Lambert를 이용해서, 1D Wrapped Diffuse Texture에서 값을 얻어오는 것이었습니다.)

시간이 지나서, Wrapped Diffuse가 일반적으로 많이 사용되지 않기 때문에, 그냥 잊고 지냈는데, 최근 들어서, 여러가지 기술문서들에서 Wrapped Diffuse 라는 용어가 등장합니다. 그럼 Wrapped Diffuse는 뭐하는 것일까요?


Wrapped Diffuse는 subsurface scattering, area light source, 더 부드러운 reflectance 를 표현하기 위해서 Hemisphere(반구)를 감싸는 셰이딩 모델입니다.

[Lambert(좌)와 Wrapped Diffuse(우) [2]]

Wrapped Diffuse 공식은 다음과 같습니다.

float wrapped_diffuse_term = (dot(normal, lightdirection) + w) / (1+w);

그런데 가만보니까 Half Lambert 정의와 유사하네요? 그렇습니다. Half Lambert 공식도 바로 Wrapped Diffuse 라이팅 공식을 간략화 한 내용입니다. 그러니, Half Lambert 특징과 유사하다고 생각하면 틀리지 않습니다. (W=1이면, Half Lambert 공식이 됩니다.)

Wrapped Diffuse는 Half Lambert와 유사하게 투과되는 느낌을 표현하는데 많이 사용되는데요, 피부, 나뭇잎, 파티클 라이팅에 주로 사용됩니다. 여기 유니티 3D의 SkinShader 샘플을 보시면 사용예를 보실 수 있을 것입니다. (http://unifycommunity.com/wiki/index.php?title=SkinShader)


하지만, Wrapped Diffuse 모델은 너무 밝은 결과를 나타냅니다. 그래서 일반적으로 사용하기는 조금 부담감이 있습니다. 최근 본 내용 중에 이를 해결할 수 있는 좋은 아티클(Energy-Conserving Wrapped Diffuse)이 올라와서 소개합니다.

최근에는 Physically Based Lighting 이 주목을 받고 있습니다. 그 중심에는 "에너지 보존"이 기반이 되는데요. 이 아티클도 "에너지 보존"에 중심을 두고 있습니다. 즉, Lambert Diffuse 모델에 대한 결과를 1로 봤을 때, Wrapped Diffuse 모델의 총 에너지도 1로 만들어 주는 것이지요. 그렇게 되면, 너무 밝지 않은 Wrapped Diffuse 결과를 얻을 수 있습니다.

// w is between 0 and 1
float3 wrappedDiffuse = LightColour * saturate((dot(N, L) + w) / ((1 + w) * (1 + w)));

결과

이 그림을 보고, 뭐가 좋아졌나 싶죠? 하지만, 실제로 적용을 해보시고 테스트를 해보시면, 대충 어떤 느낌이신지 아실 것입니다. w값에 따라서, 전체 에너지량은 그대로이면서, 음영만 조절되는 느낌이거든요. (이전의 Wrappped Diffuse 모델은 그냥 밝아져버리죠!)


4. 결론

Wrapped Diffuse에 대해서 알아보았습니다. 앞에서 "퐁퐁퐁"님의 Oren-Nayar Reflectance Lighting Model 에서도 보셨듯이 Diffuse Lighting 모델은 Lambert Model 하나만 있는 것은 아닙니다(Oren-Nayar 비싸요. ㅜㅜ). Diffuse 라이팅을 할 때에도 표면의 성질에 따라서 라이팅 모델을 선택해서 적절하게 선택해서 사용을 한다면, 좀 더 정밀한 재질 느낌을 낼 수 있을 것입니다. (물론, Diffuse 보다는 Specular가 더 중요하겠죠!? ㅎ)

- 좀 더 거친 표면의 Diffuse 표현 -> Oren-Nayar Model
- 일반적인 표면의 Diffuse 표현 -> Lambert Model
- 좀 더 부드러운 표면의 Diffuse 표현 -> Wrapped Diffuse Model

(Physically Based Lighting의 세계는 재밌어요!!! ㅎㅎㅎ)


5. 참고자료

[1] Wrap Shading : http://www.iro.umontreal.ca/~derek/publication8.html
[2] Energy-Conserving Wrapped Diffuse 
[3] Wrapped Diffuse와 팀포트리스 셰이딩 : http://cagetu.egloos.com/5621806
[4] 팀포트리스 셰이딩 따라해보기 : http://cagetu.egloos.com/4212681 
[5] Energy Conservation in Games : http://www.rorydriscoll.com/2009/01/25/energy-conservation-in-games/

댓글을 달아 주세요

  1. Favicon of https://gamedevforever.com 대마왕J 2012.04.03 23:27 신고  댓글주소  수정/삭제  댓글쓰기

    어헉!!! 이거 나중에 shderFX로 하려고 했던 내용인데, 그대로 공개하셨네용 ㅋㅋㅋ
    팀 포트리스에서 사용했던 Wrapped Diffuse 방식은 지역마다 texture를 보관해야 하는 점이 귀찮더군요. 그 외의 Wrapped Diffuse 는 제대로 챙겨 보지 못하던 방식이네요!!! 잘 보겠습니다!!!
    근데 디퍼드에서는 안돼 ... 제길...

    • Favicon of https://gamedevforever.com cagetu 2012.04.04 01:11 신고  댓글주소  수정/삭제

      디퍼드에서도 G-Buffer의 한 채널을 할당해서, 재질별로 w값을 저장해서 사용하면 할 수는 있을 것 같기는 한데요??
      좀 잉여스럽긴하네요. ㅎㅎ

      나중에 다시 다루셔도 될 듯 한데요?? ㅎㅎ

    • Favicon of https://gamedevforever.com 대마왕J 2012.04.04 01:39 신고  댓글주소  수정/삭제

      넵 나중에 shaderFX로 이 내용 꼭 만들겠습니다. 디퍼드에서 채널 할당해서 재질 값을 넣는건 알긴 아는데... 흑흑흑 유니티를 다루는 저로써는 렌더러까지 건드리기에는 좀.. .

  2. 김용준 2012.04.05 11:42  댓글주소  수정/삭제  댓글쓰기

    아아~ 조으다