유니티5 렌더링 파이프라인 확장 기능 : 커맨드 버퍼(Command Buffer) UNITY3D


Unity5에는 스탠타드 셰이더(Standard Shader), 실시간 글로벌 일루미네이션(Real-time Global Illumination), 리플렉션 프로브(Reflection Probe), 향상된 라이트맵(Lightmap) 워크플로우 등 시각적으로 두드러지는 새로운 기능들이 대거 추가가 되었습니다. 뿐만 아니라 성능 및 색공간 등에 관한 내부적인 개선 사항들도 많습니다.

그리고 또 다른 개선사항으로는 기능 확장성에 대한 것을 들 수 있겠습니다. 많은 고민을 통해 커맨드 버퍼(Command Buffer)라는 기능을 추가하였습니다. 이 기능을 사용하면 렌더링 관련 명령 목록을 만듦으로써 렌더링 파이프라인을 확장시킬 수 있습니다.
사실 원래는 그래픽스에서 커맨드 버퍼라는 것은 저수준(low-level)의 컨셉입니다. 어플리케이션에서 DirectX나 OpenGl 같은 그래픽스 API에 명령을 주면 커맨드 버퍼라는 곳에 명령이 쌓이고 GPU는 여기서 정보을 꺼내가서 렌더링을 합니다. 본 포스팅에서 말하는 커맨드 버퍼도 이와 비슷한 개념입니다. 다만 GPU에게 “레지스터 X에게 Y값을 셋팅해”라는 저수준의 명령이 아니라, “이 메시를 저 매터리얼을 사용해서 그려” 등의 명령 목록을 만들 수 있는 고수준(high-level)의 개념인 것입니다.

스크립트에서 커맨드 버퍼를 생성하여 렌더링 명령 설정할 수 있습니다. 이 명령을 카메라 렌더링 과정에서 많은 용도로 사용이 가능합니다. 예를 들자면, 디퍼드 렌더링 과정 중 G버퍼가 끝난 후 추가적인 오브젝트 렌더를 하거나, 일반적인 스카이박스 렌더 후 구름들 추가하는 등 다양한 작업들을 할 수 있게 됩니다. 자세한 내용은 공식 메뉴얼을 참고해주세요.


예시들

그 활용 예로 블러된 굴절 효과를 들 수 있습니다. 스카이박스와 일반적인 불투명 오브젝트가 렌더링 되고나면 현재 렌더된 이미지는 임시적인 렌더 타겟에 저장됩니다. 불투명 오브젝트 앞에 위치한 유리 오브젝트에 설정한 셰이더에서는 이 이미지를 굴절시켜 보여주면 이러한 효과를 얻을 수 있습니다. 이는 shader GrabPass does와 흡사한 개념입니다만 그 보다는 더 많은 커스터마이징 작업을 할 수 있게 됩니다.
또 다른 예로는 커스텀한 디퍼드 라이트(custom deferred light)를 들 수 있습니다. 일반적인 포인트 및 스팟 라이트가 아닌 튜브나 구체 모양 등의 라이트를 표현 할 수 있는 것입니다. 일반적인 디퍼드 셰이딩 라이트 과정이 끝난 후, 커스텀한 라이트를 라이트 버퍼에 그려줄 수 있습니다.
마지막으로 디퍼드 데칼(deferred decal)을 예로 들겠습니다. 전통적인 방식의 데칼은 대상 면의 형태를 그대로 따와서 별도의 메시를 만들어서 얹어주는 방식입니다. 그러다보니 Z파이팅 문제라던가 라이팅 이질감 등의 부작용이 존재합니다. 그러나 디퍼드 데칼은 G버퍼에 박스모양의 볼륨으로 데칼을 직접 그려넣는 방식입니다. 이 과정은 디퍼드 라이팅이 그려지는 방식과 흡사합니다만 라이팅 연산 대신 G버퍼에 텍스쳐만 그려넣는 것입니다. 이렇게 되면 Z파이팅 문제도 사라지고 라이팅도 자연스럽게 적용됩니다.
데모를 다운 받아서 확인해보실 수 있습니다. 코드도 복잡하지 않습니다. 이 행위들을 하는 스크립트는 약 100줄의 코드만으로 이루어져있습니다. 
데모 다운로드 : 

공유하기 버튼

 

물리 기반 셰이딩으로 작업하기 #2 : 재질 세부 예시 UNITY3D

물리 기반 셰이딩으로 작업하기 #1에서 이어지는 글입니다.


재질 예시


바이킹 마을 씬은 많은 적절한 메모리의 텍스쳐를 사용하여 많은 양의 컨텐츠를 나타내고 있습니다. 그 예로 10미터 크기의 나무 크레인 모델을 살펴보겠습니다.


예시 1: 크레인 오브젝트는 2개의 재질을 가집니다. 2개의 디퓨즈 텍스쳐, 1개의 스페큘러-매끄러움 텍스쳐, 2개의 오클루전 텍스쳐, 2개의 디테일 텍스쳐

예시 2: 방패 프랍은 1개의 재질을 가집니다. 1개의 디퓨즈맵 텍스쳐, 1개의 스페큘러(specular)-매끄러움(Smoothness) 텍스쳐, 1개의 오클루전 텍스쳐를 가집니다. 디테일 텍스쳐는 없습니다.

알베도 텍스쳐 : 스페큘러 워크플로우에서는, 알베토 텍스쳐는 표면에 반응하는 디퓨즈 라이트의 색상을 나타냅니다. 왼쪽 이미지 (크레인)에서는 너무 그렇게 높은 디테일을 필요로하지는 않습니다. 반면 오른쪽 텍스쳐 (방패)는 높은 디테일을 포함하고 있습니다.

크레인의 디퓨즈맵은 나무의 색상으로 평범하게 이루어져있습니다. 디테일도 그냥 적당한 정도로만 이루어져있습니다. 반면 오른쪽에 있는 방패의 이미지는 높은 디테일을 가지고 있습니다.

크레인 재질의 디퓨즈 색상 값

스페큘러 : 논-메탈(비전도체)는 비교적 어두운 그레이스케일의 스페큘러 색상을 가집니다. 반면 메탈은 더 밝고 고유 색상을 띄는 스페큘러를 가집니다. ( 녹슬거나 기름때나 먼지가 있는 부분은 메탈릭이 아닙니다.) 

좌측은 메탈을 표현하기 위한 크레인의 스페큘러 맵(메탈릭 셰이더를 사용하지 않음. 스페큘러 워크플로우). 우측은 방패의 스페큘러 텍스쳐

나무의 표면은 전반적으로 스페큘러가 거의 없다시피합니다. 따라서 나무의 스페큘러는 텍스쳐를 사용하는 대신 단순 생삭값으로 대체합니다.

매끄러움(Smoothness)은 PBS 재질의 핵심 속성중 하나입니다. 이는 재질의 상태, 변화, 결점, 디테일 등을 표현하고 물체가 오래되었는 지 등에 대한 시각적인 힌트를 제공해줍니다. 크레인의 경우, 거칠기가 재질 전반적으로 동일하기때문에 따로 텍스쳐로 사용되지 않고 단순한 값으로만 대체될 수 있습니다. 그 덕에 텍스쳐 메모리를 절약할 수 있습니다.


크레인에 있는 나무의 매끄러움. 텍스쳐 대신 단순 값으로 사용함.

메탈의 표현하기 위한 크레인의 매끄러움 맵(메탈릭 셰이더를 사용하지 않음. 스페큘러 워크플로우). 우측 이미지는 방패의 매끄러움 맵을 나타냄. 나무와 메탈 표면이 공존.

오클루전(Occlusion)은 얼마나 표면이 돌출되었는지에 대한 정보를 빛에 반응하여 나타냅니다. 앰비언트 오클루전(Ambient Occlusion)은 표면의 디테일과 높이를 주변광과 반사광 등으로 표현을 해줍니다. SSAO(Screen Space Ambient Occlusion)을 사용하는 것도 염두해두어야합니다. SSAO와 AO를 같이 사용하게되면 배로 어두워지는 경향이 생길 수 있습니다. AO맵으로 크랙이나 접합부 등을 강조하는데 쓰일 수도 있습니다. 게임이 SSAO나 라이트맵의 AO를 쓰는 경우엔 적합한 용도가 될 것입니다.

첫번째 이미지는 라이트맵 AO, 두번째 이미지는 오클루전 텍스쳐, 세번째 이미지는 디퓨즈의 오클루전, 네번째 이미지는 이미지 효과 SSAO를 보여주고 있습니다.



부가 텍스쳐와 해상도


부가(secondary) 텍스쳐는 디테일의 레벨을 증가시켜주거나 재질의 변화를 제공하는데 쓰일 수 있습니다. 디테일 마스크 속성을 사용하는 것으로 마스킹 될 수 있습니다.

크레인의 디퓨즈 텍스쳐는 비교적 낮은 해상도로 이루어져 있습니다. 이러한 경우 부가 텍스쳐로 표면의 디테일을 부여해줄 수 있습니다. 디테일맵은 타일링되어 표면에 전반적으로 반복되어 집니다. 때문에 낮은 해상도로도 높은 디테일을 표현해줘서 메모리를 절약 할 수 있습니다.

부가 알베도맵과 노말맵은 저해상도의 디퓨즈와 노말맵을 보완해줍니다. 아래 이미지는 크레인의 표면 비교. 왼쪽은 부가 텍스쳐 사용. 오른쪽은 사용 안함.


에셋 스토어에서 다운로드 받아서 확인 해보실 수 있습니다. Unity 5.0.0 RC2 버젼에서 작동합니다.

에셋 스토어 링크 : https://www.assetstore.unity3d.com/#!/content/29140

Unity5 링크 : http://unity3d.com/unity/beta/5.0


공유하기 버튼

 

물리 기반 셰이딩으로 작업하기 #1 UNITY3D

본 포스팅은 유니티 공식 블로그의 "Working with Physically Based Shading" a practical approach"를 번역한 것입니다.



유니티5 베타를 사용중이시라면 에셋 스토어에서 바이킹 마을 데모를 다운받아서 확인해보실 수 있습니다. 이 데모에서는 유니티5에서 씬의 조명을 어떻게 구성해야 하는지에 대한 안내를 받을 수 있습니다.


견본 환경 만들기

텍스쳐링과 셰이더 설정을 알맞게 결정하기 위해서는 간단한 신을 다양한 라이팅 셋업으로 테스트해보는 것을 추천합니다. 이는 각기 다른 스카이박스와 라이팅 등 모델의 조명에 연관되는 것 들을 의미합니다. 유니티5를 열면 빈 씬이 기본적으로 절차적으로 생성 된 하늘이 포함 된 것을 확인 가능합니다. 이는 기본 환경광과 반사 셋팅을 포함하고 있습니다. 
템플릿 환경에서는 다음 사항들이 준비되어있어야합니다.
- HDR 카메라 렌더링
- 몇 개의 리플렉션 프로브
- 라이트 프로브의 그룹
- HDR 하늘텍스쳐와 재질(material)들의 셋. 이 프로젝트에 포함된 하늘은 유니티를 위해 커스텀하게 만들어진 것이 사용되었습니다.( 제작자:Dutch Skies 360)
- HDR 하늘 색과 강도가 맞춰진 미색의 방향성 광원(directional light)


스카이 텍스쳐 파라미터 조절

대부분의 하늘 텍스쳐는 이미지 자체에 태양 및 플레어를 포함하고 있습니다. 하지만 이는 다음 이유들로 인해 잠재적인 문제가 됩니다.
- 디렉셔널 라이트의 방향을 잡을 시 텍스쳐에 그려진 태양과 맞춰야만 하는 제약이 생깁니다.
- 강렬한 스페큘라 하이라이트떄문에 반사된 태양과 스페큘러 핫스팟이 겹쳐버립니다. 
- 미리 그려진 태양의 반사가 그림자 영역에서 가려지지 않습니다. 이는 어두운 영역에다 어색한 반짝임을 만들어버립니다.
때문에, 태양의 하이라이트, 플레어, 태양광 및 HDR 값은 하늘 텍스쳐 외부(주로 디렉셔널 라이트)에서 편집되어야합니다. 


물리 기반 셰이딩 재질 

유니티5의 스탠다드 셰이더는 스페큘러 컬러와 메탈릭 워크플로우 둘 다 제공하고 있습니다. 둘 모두 표면에 반사하는 색을 정의하고 있습니다. 스페큘러 워크플로우에서는 색상이 직접적으로 명시됩니다. 반면 메탈릭 워크플로우에서는, 디퓨즈 색상과 메탈릭 값의 조합으로  색상이 만들어집니다. 

에셋 스토어에서 캘리브레이션(Calibration) 씬을 받아보실 수 있습니다. 이 씬은 각종 측정용 차트를 포함하고 있습니다. 바이킹 프로젝트에서는 스페큘러 컬러 워크플로우로 만들어졌는데, 이 차트를 참고하며 진행하였습니다.
스페큘러 워크플로우에서는 반사광의 스페큘러 색상을 직접 선택 할 수 있습니다. 반면 메탈릭 워크플로우에서는 재질이 조명될 때 메탈처럼 작동할 것인지에 대한 선택을 할 수 있습니다. 두 워크플로우 모두 최종적으로는 동일한 결과를 만들어 낼 수 있습니다. 따라서 작업 진행을 스페큘러 워크플로우로 할 것인지 메탈릭 워크 플로우로 할 것인지는 순전히 작업자의 기호에 맞추어 선택하면 됩니다. 

스페큘러 값 차트:

메탈릭 값 차트:


재질 설정하기

재질을 만들 시, 테스트 용도의 깨끗한 재질을 만들어 두면 유용합니다. 이 재질에다 측정용 챠트로부터 색상 등의 값을 적용합니다. 그 후 텍스쳐를 적용한 결과와 비교해보면 재질 본래의 느낌을 확인해볼 수 있습니다.


텍스쳐 제작의 전통적인 방법

바이킹 마을 데모에 쓰인 텍스쳐들은 사진 등의 데이터로부터 스캔한 디퓨즈/알베도, 스페큘러, 노말맵 등을 사용합니다. (제공 : Quixel텍스쳐에 디테일을 추가할 때는 주의할 점이 있습니다. 예를 들자면, 일반적으로는 텍스쳐에 미리 AO나 그림자 등의 라이팅을 적용해서 그려넣기도 합니다. 하지만 물리 기반 렌더링에서는 엔진에서 모든 라이팅을 제공해주기때문에 텍스쳐에 미리 그려넣으면 안됩니다. 사진을 수정하는 작업은 이러한 리터칭이 많이 들어가야해서 PBS 스캐닝 된 데이터보다 부담이 큽니다만 Quixel SuiteAllegorithmic Substance Painter를 이용하면 이러한 과줭이 한결 수월해집니다.


스캔 데이터

PBS 대응하여 스캔된 데이터는 편집하기가 좀 더 편합니다. 알베도, 스페큘러, 매끄러움 등이 이미 분리된 데이터이기때문입니다. PBS 데이터를 만들어 주는 소프트웨어가  유니티 프로필에 대응되어있다면 더욱 좋을것입니다. 



* 글이 길어서 두 편으로 나눕니다.

공유하기 버튼

 

유니티5의 글로벌 일루미네이션 #2 UNITY3D

유니티5의 글로벌 일루미네이션 #1에서 이어지는 글입니다



인라이튼 사전 연산 (precompute)

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


인라이튼 런타임 

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

모바일 장치(ARM 태블릿)에서 작동하는 영상 : http://youtu.be/mfkhSwXtnmo


베이킹(Baking)

어떤 게임들은 라이팅을 미리 굽는(baking) 과정이 매우 적절한 선택이 될 수 있을 것입니다. 유니티5에서는 라이트소스, 발광 재질, 환경 라이팅 등이 baked 및 리얼타임으로 태그 될 수 있습니다. baked는 이전버젼(4.x)와 같은 방식으로 베이킹 되는 것 의미합니다. 동적 라이트는 인라이튼 런타임에서 처리합니다. baked와 real-time은 이질감 없이 합성됩니다.
유니티5의 라이트맵은 여러 컴포넌트로 나뉩니다. 직접광, 간접광, 직접광 지향성, 간접광 지향성, AO 등 5개의 라이트맵으로 나뉘어집니다. 이 라이트맵 컴포넌트들은 실시간으로 합성하게 됩니다. 또한, 이는 에디터에서 컨트롤 가능합니다. 예를 들어 간접광만 증가시키는 것이 불과 몇 초 안에 이루어질 수 있습니다.



라이팅 워크플로우(workflow)

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

라이팅 워크 플로우 영상 : http://youtu.be/D392TitSE4k

공유하기 버튼

 

실시간 그림자를 싸게 그리자! 평면상의 그림자 ( Planar Shadow) UNITY3D



그래픽을 표현하는데 있어서 그림자는 매우 중요합니다. 그림자가 존재함으로써 사물의 공간상 위치를 인지하기 쉽게 만들어주고 입체감을 더해주게됩니다. 그림자는 입체 공간을 구성하는데 있어 거의 필수적인 요소라해도 과언이 아닙니다.

이는 게임에 있어서도 마찬가지입니다. 그런 이유로 모든 3D 게임에는 어떠한 형태로든 그림자가 존재합니다. 그리고 당연히 유니티에서도 그림자 기능을 제공해줍니다. 사용법 역시 체크박스만 몇 번 해주면 되는 식으로 되어있어 손쉽게 그림자를 활성화시킬 수 있습니다. (공식 메뉴얼 : http://docs.unity3d.com/Manual/class-MeshRenderer.html)

유니티에서 제공해주는 그림자는 그림자맵(ShadowMap) 기법을 사용하고있습니다. 이 기법은 모든 굴곡에 대응하고 자기 그림자(self-shadow)가 처리되는 등 높은 퀄리티를 보여주고 있지만 문제는 성능입니다. ShadowMap 기법은 그림자의 깊이를 저장하는 버퍼를 만들고난 뒤 픽셀 셰이더(Pixel Shader)에서 깊이를 비교하는 과정을 거칩니다. 또한, 넓은 영역을 커버하기위해 여러 구역으로 나누기도하고(cascade) 계단 현상을 없애기 위해 여러번 샘플링하여 필터링을 처리하는 등 부가적인 행위들이 추가됩니다. 그러다보니 랜더링 비용 중 그림자가 많은 부분을 차지하게 됩니다. PC에서는 이러한 셰도우맵 기법을 사용하기에 충분한 성능이 나오지만 모바일 장치에서 셰도우맵을 사용하는 것은 무리입니다.

이 글에서는 유니티에서 기본적으로 제공해주는 쉐도우맵 방식을 사용하지 않고 좀 더 저렴한 방식으로 그림자를 표현하는 것에 대하여 이야기하고자 합니다.



원형(circle) 평면 그림자

성능 문제때문에 모바일 장치에서는 그림자를 동그라미로 간단하게 표현하는 것이 일반적입니다. 원형의 텍스쳐를 사용하는 평면을 만들고 그걸 케릭터 밑에 배치하는 것이지요. 형태는 너무나도 간단하긴하지만 이 마저도 없는것과 있는것의 차이는 큽니다. 

이미지 : 레이븐

구현도 간단하거니와 비용도 많이 들지 않습니다만 평면이 아니고서는 표현이 불가능하다는 단점은 있습니다. 산이나 계단같이 평면이 아닌 구역에서는 그림자가 평면인게 티나기때문에 이질감이 있는 것이지요. 하지만 요즘 대부분의 모바일 게임은 평면상에서 이루어지고, 탑뷰등 카메라가 고정되어있으므로 널리 쓰이고 있습니다.

화면상에 작게만 보이거나 그림자 영역이 티가 많이 나지 않으면 이러한 간단한 동그라미 형태만으로도 충분합니다. 하지만 케릭터가 클로즈업되는 등 그림자의 화면 비중이 커지면 다소 어색해보일수도 있습니다. 이러한 경우는 케릭터 전체 크기의 동그라미가 아닌 발 크기의 동그라미 두개를 각각의 발 위치에 붙여서 이질감을 완화시킬 수도 있긴 합니다.

이미지 : 아직 미출시 데헷

그래도 아직 부족해보이긴 합니다. 엄밀히 말하자면 바닥과 발 사이의 AO를 표현해준 것이지 케릭터 전체의 그림자를 표현해준 것이 아니기 때문입니다. 완벽해보이려면 케릭터의 형태 그대로를 따라서 바닥에 그림자가 맺혀야합니다. 즉, 실시간 그림자가 필요합니다.



렌더 타겟 텍스쳐(Render Target Texture)

렌더 텍스쳐를 활용하면 손쉽게 이를 해결할 수 있습니다.렌더 텍스쳐는 카메라가 바라보는 장면을 화면에 바로 그려주는 것이 아니라 텍스쳐로 그려주는 기능을 제공해줍니다. ( 공식 메뉴얼 : http://docs.unity3d.com/Manual/class-RenderTexture.html그러기 위해서는 오브젝트에 정상적으로 그리는 메시 오브젝트 외에도 그림자로 그릴 용도의 메시 오브젝트를 추가해서 그림자로 그려줘야합니다.

우선 메인 카메라 외에 그림자용 카메라를 생성합니다. 그림자용 레이어를 추가해서 그림자용 메시만 그리도록 설정해놓고 Target Texture를 하나 생성하여 설정해줍니다. 그림자용으로 추가한 메시 역시 레이어를 설정해놓고 검은색으로 드리도록 매터리얼을 설정해줍니다. 그러면 Target Texture에는 다음과 같이 그림자 오브젝트가 그려집니다. 

 케릭터 주변의 적절한 위치에 평면을 설치한 후, 그림자용으로 만든 Target Texture를 평면에 셋팅해주면 그림자가 완성됩니다.

Target Texture의 해상도만 높으면 텍스쳐 필터링덕에 자연스레 부드러운 그림자(soft shadow)도 가능해진다는 이점이 있습니다. 하지만 현실적으로는 메모리 문제 때문에 해상도를 높게 잡을 수가 없습니다. 그러다보니 타겟 텍스쳐의 해상도문제로 그림자에 계단 현상이 발생하게 됩니다. 또한, 케릭터가 점프하는 등 에니메이션에 따라 일부 영역을 벗어나면 그림자가 잘려나가는 등 부작용이 많으므로 완벽한 해결책이 되지는 못합니다.



메시 평면 그림자

여기서 잠깐 그림자가 무엇인지에 대해 짚고 넘어가고자 합니다. 우리가 일반적으로 생각하는 그림자라는 것은 어떤 사물에 의해서 빛이 차폐되는 현상을 뜻합니다. 즉, 빛이 사물에 닿으면 그 사물 뒤의 영역에는 빛이 닿지 않는 것이지요. 

이미지 출처 : http://news.mynavi.jp/column/graphics/020/?route=blog

그 말인 즉슨, 어떤 캐릭터의 그림자를 평면에 표현하기위해서는 케릭터의 형태를 빛의 방향으로 평면에 투영시켜서 그리면 된다는 것입니다. 이 경우 메시의 원형으로 그대로 그리는 것이 아니라 빝의 방향으로 평면에 투영시켜주는 버텍스 변형이 필요합니다. 따라서, 이 메시는 유니티에서 기본적으로 제공해주는 셰이더 말고 커스텀한 셰이더를 사용하여야 합니다. 이 그림자를 표현해주기 위한 셰이더를 만들기 위해서는 약간의 수학을 끼얹어야 합니만 복잡한 수학은 아니므로 큰 걱정은 안하셔도 됩니다. 

일단, 다음과 같이 어느 한 점 P가 있고 광원 방향이 L이라고 하였을 때, 평면에 점P가 투영되는 위치는 점P'입니다. 점P와점P'을 이으는 선을 H라 하고 점P를 평면과 수직으로 이으는 선을 O라고 합니다. 선분 H와 O의 각을 θ라고 하였을 때 cosθ는 L과 단위화된(normalized)O의 내적입니다(L은 이미 단위화 되어있음). 이미 O는 평면과 수직인 상태이므로 최종적으로 cosθ와 L.y는 동일합니다. 그러면 아래 그림과 같이 빗변을 L, 맞변을 L.y로 삼는 빨간 삼각형을 이룰 수 있습니다. 

그러면 삼각비에 의해서 L:Ly = H:O가 되고 L은 단위화되어 길이가 1이므로 H = O/L.y 입니다. 즉, P'= P + O/L.y입니다. 이를 셰이더 코드로 표현하면 다음과 같습니다.

float4 vPosWorld = mul( _Object2World, v.vertex);

float4 lightDirection = -normalize(_WorldSpaceLightPos0); 

float opposite = vPosWorld.y - _PlaneHeight;

float cosTheta = -lightDirection.y; // = lightDirection dot (0,-1,0)

float hypotenuse = opposite / cosTheta;

float3 vPos = vPosWorld.xyz + ( lightDirection * hypotenuse );

o.pos = mul (UNITY_MATRIX_VP, float4(vPos.x, _PlaneHeight, vPos.z ,1));  

이 셰이더를 적용하여 검은색으로 그리면 오브젝트의 실루엣을 따르는 그림자가 평면에 나타나게됩니다. 확실히 단순한 동그라미로만 그리는 것 보다는 자연스러운 그림자에 가깝게 보입니다. 

케릭터 모델 : https://www.assetstore.unity3d.com/kr/#!/content/22840


보완

그러나 현 상태만으로는 한가지 문제가 있습니다. 그림자를 좀 더 자연스럽게 보이게 하기 위해 알파블렌딩(alpha blending)을 적용하면 다음과 같이 그림자 내부에 아티팩트가 생깁니다. 평면에 오브젝트를 블렌딩하여 그릴 때 같은 위치에 여러 면이 겹쳐져서 그려지기 때문입니다. 아래 그림에서는 몸통이나 머리 위에 팔이 덧그려지면서 실루엣 내 그림자 농도가 달라지는 현상이 생겨버립니다.

이러한 형상을 없애려면 이미 그림자가 그려진 픽셀에는 덧 그려지지 않게 하는 작업이 필요합니다. 이를 위해서는 스텐실(stencil) 버퍼를 활용하면 됩니다. 스텐실 버퍼는 일종의 마스킹(masking)의 개념입니다. 이미 그려진 픽셀은 또 그려지지 않도록 마스킹처리하는 것입니다. ( 공식 메뉴얼 : http://docs.unity3d.com/Manual/SL-Stencil.html) 그림자를 그리는 셰이더의 pass에 다음과 같이 스텐실을 사용하도록 선언해주면 중복된 픽셀에 그리지 않게 됩니다.

Stencil {

Ref 0

Comp Equal

Pass IncrWrap

ZFail Keep

}

스텐실을 적용하고나면 다음과 같이 블렌딩을 적용해도 아티팩트 없이 동일한 농도의 그림자를 그릴 수 있게됩니다.


주의사항

이토록 평면이라는 전제만 존재한다면 그림자를 비교적 좋은 성능을 보장하면서도 손쉽게 표현 할 수 있는 방법들이 많습니다. 다만, 메시 그림자같은 경우는 메시를 한번 더 그리게 되므로 폴리곤이 적은 그림자용 메시를 별도로 마련하는 것이 좋을 것입니다. LOD를 사용한다면 LOD용 모델을 사용하면 되므로 추가적인 작업의 부담은 생기지 않을 것입니다. 또 다른 주의점으로는, 자기 그림자(self shadow)가 처리되지 않는다는 단점은 존재합니다만 어짜피 라이팅이 간단한 모바일에서는 대부분 자기 그림자를 원치 않을 것입니다. 




공유하기 버튼

 

1 2 3 4 5 6 7 8 9 10 다음


smallBanner

longBanner

rightSmallBanner

mobile

트위터큰거