336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

이 글은 2013년도에 작성한 글 복붙임

--------------------------------------------------------------------------------------------------------------------------------


저는 COCOS 2D-X로 개발을 하고 있습니다만, 유니티는 교양(?)으로 알아두어야 할 것 같아서 만지작거려볼까 하는 중입니다. 그래서 유니티 포럼이나 웹을 돌아다니다보니 라이팅에 관한 질문이 가끔 보이더군요.

유니티의 라이팅이 안이뻐요.

유니티의 라이팅이 딱딱해요.

유니티의 라이팅이 입체감이 없어요.


이번 포스팅에서는 이에 대한 이야기를 해볼까 합니다. 사실 이 주제가 유니티에만 국한되어 하는 이야기는 아닙니다. (제목 낚시 ㅈㅅ) CG 특히 게임같은 실시간렌더링(real-time rendering)은 은 자연 그대로의 빛을 표현하는 것을 불가능하기때문에 어느정도 간략화하여 묘사하는 알고리즘을 쓰고 있고, 많은 엔진들이 제공하는 기법들은 비슷비슷합니다. 동네 표준이란게 있어서;; 그렇기때문에 본 포스팅에서 언급되는 이야기는 Unity 3D에만 국한 된 것이 아니라 통상적인 실시간 렌더링에 관한 이야기이며, 보여드리는 자료도 Unity 3D에만 국한되지 않음을 미리 말씀드립니다.

또한 직접조명(direct light)에 관해서만 다룰것이며 구면조화함수(spherical harmonics)나 앰비언트큐브(ambient cube)등의 라이트프로브(light probe)를 이용한 지역조명(local light)에 관해서는 다루지 않을 것입니다. 당연히 실시간 GI(global illumination) 역시 마찬가지이구요. 이미 그걸 찾으시려는 분은 이 글을 읽을 필요가 없어요.



Default Directional Light

일반적으로 엔진들에서 기본적으로 제공되는 디렉셔널 라이팅은 모두 딱딱해보이고 입체감이 부족해보입니다. 기본 라이팅이 너무 간략화되서 표현 된 라이팅이기 때문이죠. 일단 다음 그림을 보시죠.

빛은 보시는바와 같이 단순하지가 않습니다. 기본적인 음영 외에도 반사광, 역광, 강세 등등 다양한 빛의 요소가 존재합니다. 하지만 엔진의 기본적인 디렉셔널라이트에는 그러한 것이 생략되어 있습니다. 단순히 빛의 방향을 보는 면은 밝고 그 반대 방향 즉 빛을 등지는 부분은 어둡게 표현하는게 다입니다. 그렇기때문에 빛이 “딱딱하게” 보이는 것 입니다.

거기다가 문제가 더 있습니다. 빛의 반대면은 단순히 어둡기만 한 것이 아니라 어두운 부분은 명암이 아예 사라진다는 것입니다.

빛의 명암은 빛 벡터와 면의 노말 벡터와의 내적값을 사용합니다. 정확히는 물체에서 빛을 보는 방향의 벡터와 면의 노말 벡터를 내적하는 값이죠. (벡터와 내적에 대한 개념을 모르신다면 대마왕님의 시리즈 글을 읽어보시길 권장합니다. 아티스트 프로그래머 모두에게 도움이 될 것입니다. 프로그래머시면 맥스의 디테일한 내용은 건너 뛰고 설명만 보세요. 시작! http://www.gamedevforever.com/228)

음영값 = N(면의 노말) dot L(면에서 태양으로의 방향)

두 벡터가 같은 방향을 보고 있으면 1이 나오고, 직각을 이루고 있으면 0이 나오고, 반대방향을 보고 있으면 -1이 나옵니다. 따라서 내적 값을 음영값으로 사용하게 되면 빛을 보는 면은 1의 값 즉 제일 밝은면이 됩니다. 근데 빛의 정 반대면은 -1이 나오게 됩니다. 이런 경우에는 음수 조명은 존재하지 않으므로 0 이하의 값은 그냥 0으로 취급해버립니다.

diffuse = max(0, dot(L, N));

그러다보니 빛의 반대 영역은 음영이 존재하지 않고 죄다 까맣게 되어버리는 것이지요. 그러다보니 어두운 영역의 입체감이 존재하지 않아서 “입체감이 없다”고 느껴지는 것입니다.

하이엔드 PC게임 렌더링에서는 역광, 반사광, AO 등의 간접조명들이 처리되어 이러한 현상이 보완됩니다. 하지만 그러한 성능이 나오지를 못하는 모바일에서는 현실적으로는 디렉셔널라이트같은 직접조명만 처리가 가능하기때문에 다양한 방식이 필요합니다.



Half Lambert

어두운 영역이 죄다 0으로 되어 음영이 죽어버리는 현상은 하프램버트를 적용해줘도 크게 완화됩니다. 빛 벡터와 노말 벡터의 내적 음영값이 1~0~-1로 나와서 0이후부터는 0으로 채워버리니까 애초에 결과 값을 0~0.5~1로 나오게 하면 되는 것이지요. N dot L의 식을 조금만 손봐주면 됩니다.

halflambert_diffuse = max(0, (dot(L, N) + 1) / 2);

렇게 하면 암부 영역의 음영이 살아나게되서 널리 쓰이곤 합니다.

다만 쉐도우맵 방식의 그림자와는 궁합이 안맞아서 신중히 생각해봐야 한다는 문제는 있지만 모바일에서 아직 쉐도우맵은 사치일테니 우선 당장은 고민거리는 아닐 것 같네요.


참고 자료 :

http://www.valvesoftware.com/publications/2006/SIGGRAPH06_Course_ShadingInValvesSourceEngine_Slides.pdf



Diffuse Wrap

음영을 아티스트가 직접 그려넣는 방식도 있습니다. 음영 스펙트럼을 직접 아티스트가 선택하여 칠한 텍스쳐를 오브젝트에 감싸는 것이지요. 앞서서 언급했듯이 자연상태의 빛은 직접조명만 존재하는 것이 아니라 주변 사물에 빛이 반사되어 들어오는 간접조명들도 존재합니다. 따라서 음영의 스펙트럼이 단순히 선형적인 흰색~검은색만 되는 것이 아닙니다. 텍스쳐로 음영을 표현하면 이러한 색의 스펙트럼을 직접 제어가 가능해져서 아티스트들이 선호합니다.

방식도 간단합니다. 다음과 같은 라이팅 스펙트럼 텍스쳐를 준비해놓습니다. 위의 하프램버트 값을 바로 음영 값으로 사용하는 것이 아니라 스펙트럼 텍스쳐의 U좌표로 사용하면 땡인 것이지요. 큰 노력 들이지 않고도 아티스트느님께 이쁨받을 수 있어요 하앍하앍

더 나아가서 큐브맵(Cube-Map)을 통채로 라이팅 결과로 사용하는 IBL(Image Based Lighting) 방식이 이용되기도 합니다. 큐브맵은 일반적으로 쓰는 2차원 텍스쳐와는 달리 상하좌우앞뒤 6면을 가지고 있는 텍스쳐입니다. 보통 스카이박스가 큐브맵으로 만들어집니다.

이러한 큐브맵에 그림 대신 라이팅을 새겨넣고 오브젝트의 면에 바로 입혀버리는 것이지요.

위의 1차원 방식과는 달리 간접조명을 동서남북위아래 모두 반영할 수 있어서 아티스트의 자유도가 더 높아져서 더 높은 퀄리티를 낼 수 있습니다. 하지만 큐브맵은 추가적인 성능이 요구되니 사양을 고려해서 사용해야 합니다.


참고 자료:

http://www.gamedevforever.com/150

http://www.gamedevforever.com/269

http://www.gamedevforever.com/272

http://www.gdcvault.com/play/1014362/Cinematic-Character-Lighting-in-STAR

http://pds8.egloos.com/pds/200803/05/32/TeamFortress2mitchell.pdf

http://www.slideshare.net/valhashi/2011-03-gametechtadptforpdf



Hemisphere Lighting

다소 저렴한 방법으로 간접조명을 흉내 낼 수 있는 방법으로 반구조명(Hemisphere Lighting) 기법이 존재합니다. 월드를 감싸는 구를 반토막 내서 하늘에서 수직으로 내려오는 및과 땅에서 수직으로 올라오는 빛이 존재한다고 가정하는 것입니다. 수직으로 향하는 각각 다른 컬러를 가지는 라이트를 디렉셔널라이트에 추가적으로 더해주는 것입니다.

그러한 컨셉과 마찬가지로 디렉셔널 라이트를 여러개를 추가해버리는 방법도 가능합니다.


관련 자료:

http://www.slideshare.net/ozlael/deferred-rendering-case-study

http://digitalerr0r.wordpress.com/2009/05/09/xna-shader-programming-tutorial-19-hemispheric-ambient-light/

http://www.gamasutra.com/view/feature/2817/hemisphere_lighting_with_radiosity_.php



Sub-Surface Scattering

아무리 빛을 이래 저래 만지작거려봐도 인간형 케릭터에게는 어색함이 사라지지 않을 수도 있습니다. 얼굴이나 팔 등의 피부가 느낌이 안살아서 그러는 것이지요.

손을 전등이나 태양을 향해 대보세요. 빛이 완전 차단되는 것이 아니라 조금은 반영되어 보일것입니다. 또한 음영을 자세히 살펴보세요. 어두운 영역과 밝은 영역 사이에 붉은 영역이 존재할 것입니다. 피부는 완전 불투명한 재질이 아니라 반투명 재질이 여러겹으로 구성되어 있기때문에 빛이 직선으로 통과되는 것이 아니라 빛이 산란되어 통과됩니다. 그 안에 존재하는 모세혈관들이 산란된 빛을 통해 비춰지면서 특이한 느낌이 나는 것입니다. 그러한 피부 재질을 단순한 방식으로 표현하려니 어색함이 존재하는 것이지요.

이러한 현상을 표면하산란(Sub-Surface Scattering,SSS)라 부르고 비실시간 렌더링에서는 이를 시물레이션해서 표현합니다. 하지만 게임에서는 이를 시뮬레이션하는 수준까지는 못하고 대충 흉내내는 방식을 사용합니다.(fake SSS) 음영 사이에 붉은 빛이 도는 느낌을 표현해주는 것이지요.

이 느낌을 코드 공식으로 만들어 내는 것도 복잡하지는 않습니다만 그냥 텍스쳐로 표현해버리세요. 모바일에서는 텍스쳐로 표현하는게 더 싸게 먹힐꺼예요. 느낌 아니까~


관련 자료:

http://http.developer.nvidia.com/GPUGems/gpugems_ch16.html

http://blog.naver.com/PostView.nhn?blogId=sorkelf&logNo=40146367692&redirect=Dlog&widgetTypeCall=true&topReferer=http%3A%2F%2Fblog.naver.com%2FPostView.nhn%3FblogId%3Dagebreak%26logNo%3D60149081175%26redirect%3DDlog%26widgetTypeCall%3Dtrue%26top

http://www.slideshare.net/ozlael/deferred-rendering-case-study




Color Correction ( or Color Grading)

컬러커렉션(Color Correction) 혹은 컬러그레이딩(Color Grading)으로 화룡정점을 찍어보는 것도 괜챦습니다. 컬러그레이딩은 엄밀히 따지자면 조명 연산이 아니라 색의 톤을 조절하는 방식입니다. 모바일에서는 성능 문제로 무리가 있을 것이라 생각했었는데 기기의 성능들이 좋아지면서 가능해졌습니다.

상단이 컬러그레이딩을 적용하기 전이고 하단이 컬러그레이딩을 적용한 후의 이미지입니다. 적용하고 나니 뭔가 파스텔톤의 느낌이 나고 훨씬 그래픽이 부드러워진 느낌이 납니다. 추가적인 비용 부담도 존재하긴 하지만 시각적인 효과가 뛰어나서 옵션으로 적용하는 등 여건만 된다면 적용해볼 만 합니다. 원리는 간단합니다. 디퓨즈까지 반영 된 최종 픽셀의 값을 스펙트럼 텍스쳐로 매핑해서 보여주면 땡입니다.  


관련 자료:

http://http.developer.nvidia.com/GPUGems/gpugems_ch22.html

http://docs.unity3d.com/Documentation/Components/script-ColorCorrectionEffect.html



마무리

이래 저래 조명 방식들을 설명해드렸습니다만 프로젝트에 적합한 조명 방식을 정하는 것은 쉬은일이 아닙니다. 게다가 한번 정해지면 다시 변경하기란 불가능에 가깝습니다. 조명이 바뀌면 거기에 맞춰서 만들어져왔던 리소스들을 다시 엎어야 하는 상황들이 발생하기 때문이죠. 따라서 프로젝트 초반에 프로그래머와 아티스트가 함께 테스트를 해보며 신중히 결정하여야 할 것입니다. 그럼 모두들 즐삽질~!


지금까지 설명 드린 기능들의 유니티 관련 페이지

http://docs.unity3d.com/Documentation/Components/script-ColorCorrectionEffect.html

http://docs.unity3d.com/Documentation/Components/SL-SurfaceShaderExamples.html

http://docs.unity3d.com/Documentation/Components/SL-SurfaceShaderLightingExamples.html

http://www.unitymanual.com/thread-1272-1-1.html

http://www.farfarer.com/blog/2011/07/25/dynamic-ambient-lighting-in-unity/

http://www.farfarer.com/blog/2013/02/11/pre-integrated-skin-shader-unity-3d/

https://www.youtube.com/watch?v=XBTB17hcbio&feature=related



Posted by ozlael
,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

라이팅 작업 흐름을 비약적으로 개선시켜줄 수 있는 실시간 글로벌 일루미네이션(real-time Global illumination)은 Unity5의 새로운 그래픽 기능 중 하나입니다. 이에 초첨을 맞추어 이야기하고자합니다. 이 글은 유니티 블로그에 있는 "GLOBAL ILLUMINATION IN UNITY 5"글을 번역 및 요약한 글입니다.

글로벌 일루미네이션( Global illumination, 이하 GI)은 물리적인 현상에 기반한 빛의 이동에대한 시물레이션 결과입니다. 즉 3D 공간에서 빛이 면에 부딪혀서 어떻게 이동하는 지를 시물레이션 하는 것입니다. 이로 인해 게임의 사실성을 부각시켜 줄 수 있습니다. GI 알고리즘은 광원으로부터 직접 오는 빛 뿐만 아니라 다른 재질의 면에 반사되서 오는 간접 조명도 취합해서 계산합니다. 하지만 일반적으로는 간접 조명은 게임에서 실시간으로 연산하기에는 무리였습니다.

GI를 식으로 표현하면 다음과 같습니다. 특정 점의 라이팅은 표면 점의 원래 라이팅인 Le과 부수적인 라이팅의 합으로 이루어집니다. Li는 반구 조명을, p는 반사된 조명을 나타냅니다.

이를 처리하기 위하여 쓰이는 대표적인 알고리즘중 하나는 path tracing입니다. 이는 CGI나 영화에서 널리 쓰이고 있습니다. 하지만 화면에 있는 라이팅, 매터리얼 등의 회면 전체의 이미지를 구성하는데 필요한 모든 정보가 매번 연산되어야합니다. 그러다보니 게임같은 실시간 렝더링에서 사용하기에는 적합하지 않습니다. 이에 대한 대안으로, 이미지 전체를 갱신하지 않고 노이즈로 처리해서 성능을 높이는 방법도 존재합니다. 하지만 노이즈가 티나도록 깜빡거림이 생기는 등의 부작용이 존재합니다.

이 외에도 GI를 처리하기 위한 많은 방법들이 연구되어왔지만, 대부분은 하이엔드 데스크탑 수준의 GPU와 많은 용량의 메모리가 필요합니다. 따라서 모바일을 비롯하여 다양한 플랫폼에서 사용될 수 있는 방안이 필요합니다.


Enlighten

Enlighten(이하 인라이튼)은 이미 배틀필드4, 메달 오브 아너 워파이터 등 여러 AAA급 게임에서 사용되어 검증이된 뿐만 아니라 모바일에서까지 GI를 가능케해주는 훌륭한 솔루션입니다. 기본적인 시각적 정보들(예를 들어 위의 식에서 우항의 적분 부분)이 미리 연산되어 있으면 실시간 으로 라이팅 소스를 변경 처리하는 것이 가능해집니다.

인라이튼은 다음 사항들을 동적으로 변경하는 것을 가능케 합니다.

  • 라이트 소스
  • 환경 라이팅
  • 머티리얼 속성

GI가 사뮬레이션되는 지오메트리는 정적이어야합니다. 하지만 동적 오브젝트는 라이트프로브에 의해서 동적으로 라이팅이 변경 될 수 있습니다. 이 라이트프로브는 실시간으로 정적인 오브젝트의 GI를 업데이트 할 수 있습니다. 이를 위해 인라이튼은 실시간으로 GI를 시뮬레이션 하기 위한 데이터를 미리 연산해놓습니다. 이 데이터는 OSX, Windows, Linus, iOS, 안드로이드, iOS 등등의 다양한 플랫폼의 런타임 모듈에서 사용됩니다.

인라이튼은 다음 사항들을 만들어냅니다.

  • 실시간 라이트맵
  • 실시간 라이트프로브
  • 실시간 큐브맵

다음 예시 이미지들은 Enlighten을 이용하여 그려진 화면입니다. 라이팅들은 완벽한 동적 라이팅으로 셋팅되어있고 변화가 즉각적으로 이루어집니다. 

이 이미지는 밝은 낮을 나타냅니다. 태양이 더 강하고 높이 위치합니다.하늘은 더 푸르고 밝습니다.

흐린 날씨의 경우에는 환경 라이팅이 우중충하고 채도가 낮습니다. 태양의 세기는 약해졌습니다. 앰비언트 라이팅 위주입니다.

마지막으로 해질녘 노을빛의 느낌을 내는 모습입니다. 

이 테크닉을 사용함으로써 하루 동안의 시간 흐름을 표현할 수 있습니다. 이로 인해 게임이 매우 사실적이게 보여 줄 수 있습니다.


인라이튼 사전 연산 (precompute)

정적인 지오메트리는 GI 솔루션 시스템에서 효과적으로 관리됩니다. 사전 연산(precompute) 단계에서 인라이튼은 씬을 여러 시스템 태스크로 쪼갠 후 이를 방대한 병렬 파이프라인에서 나누어 연산합니다. 사전 연산 과정을 거친 후 시스템 태스크간의 지오메트리 연결 정보가 구성됩니다. 이 정보들은 실시간으로 간접광을 제어하는데 사용 될 수 있습니다. 이어한 덕에 벽의 파괴나 문이 열리는 상황 등 라이팅이 변화되는 상황이 반영 될 수 있습니다.

인라이튼 런타임 

인라이튼은 데스크탑PC나 차세대콘솔 뿐만 아니라 하이엔드 모바일 장치에서도 작동합니다. 이는 CPU 스레드에서 비동기적 연산으로 돕니다만, 모바일에선 동적 라이팅과 그림자의 GPU 연산이 이슈다보니 모바일에서는 처리 가능한 동적 라이팅의 갯수가 제한됩니다. 하지만 발광색(emissive) 변경은 자유롭습니다. 발광색의 정보는 비록 저해상도이긴 하나 인라이튼에 인코딩된 정보로 연산을 하기 때문입니다.

모바일 장치(ARM 태블릿)에서 작동하는 영상:


베이킹(Baking)

어떤 게임들은 라이팅을 미리 굽는(baking) 과정이 매우 적절한 선택이 될 수 있을 것입니다. 유니티5에서는 라이트소스, 발광 재질, 환경 라이팅 등이 baked 및 리얼타임으로 태그 될 수 있습니다. baked는 이전버젼(4.x)와 같은 방식으로 베이킹 되는 것 의미합니다. 동적 라이트는 인라이튼 런타임에서 처리합니다. baked와 real-time은 이질감 없이 합성됩니다.

유니티5의 라이트맵은 여러 컴포넌트로 나뉩니다. 직접광, 간접광, 직접광 지향성, 간접광 지향성, AO 등 5개의 라이트맵으로 나뉘어집니다. 이 라이트맵 컴포넌트들은 실시간으로 합성하게 됩니다. 또한, 이는 에디터에서 컨트롤 가능합니다. 예를 들어 간접광만 증가시키는 것이 불과 몇 초 안에 이루어질 수 있습니다.


라이팅 워크플로우(workflow)

인라이튼은 실행중인 게임안에서만 실시간 GI를 제공하는 것은 아닙니다. 에디터에서 작업하는 과정에서도 실시간 GI가 이루어집니다. 인라이튼의 주요 장점 중 하나는 아티스트에게 엄청나게 개선된 워크플로우를 제공해준다는 것입니다. 이는 라이팅 작업이빠른 이터레이션으로 이루어 질 수 있기 때문입니다. iterative모드가 추가됨으로써 명시적으로 굽는 과정 필요가 없어졌습니다. 씬의 사전 연산 정보들이 실시간으로 구워지고, 사용자가 이 과정중에 일일이 개입할 필요가 없습니다. 에디터는 지속적으로 씬의 변경 사항 확인하여 자동적으로 라이팅 정보를 반영해주는 작업을 수행합니다. 대부분의 작업은 즉각적으로 반영됩니다.

라이팅 워크 플로우 영상 :





Posted by ozlael
,