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

"모바일 기기의 Tile Based Rendering(타일 기반 렌더링)과 유니티에서의 주의 사항 #1 : TBR의 이해"에서 이어지는 글입니다. 


앞선 글에서 설명드린 바와 같이 모바일에서는 타일 단위로 쪼개서 렌더링하는 방식을 사합니다. 그러다보니 전통적인 렌더링 방식에서와는 조금 다른 주의 사항이 몇 가지 존재합니다. 


알파블렌딩(Alpha Blending) VS 알파테스트(Alpha Test)

전통적으로 데스크톱 게임의 리소스에는 알파블렌딩보다 알파테스트의 사용이 권장되어왔습니다. 불투명한 철망이라든가 찢어진 옷감같은 경우는 불투명하기때문에 비싼 블렌딩 연산을 사용하기보다는 알파테스트를 사용함으로써 픽셀 연산도 절약하자는 의도였습니다. 하지만 모바일의 TBR(Tile Based Rendering, 타일 기반 렌더링)에서는 정반대로 알파테스트보다는 알파블렌딩의 사용이 권장됩니다. 

알파테스트처리를 하기 위해서는 픽셀쉐이더에서 동적분기(if문)가 사용됩니다. 데스크톱에서는 쉐이더의 동적 분기가 고속으로 처리되지만, 모바일에서는 동적 분기 성능이 취약합니다. 때문에 알파테스트는 쉐이더의 성능윽 하락시키는 원인이 됩니다.

게다가, TBDR(Tile Based Deferred Rendering, 타일 기반 지연 렌더링)에서는 픽셀 차폐의 고속 처리를 깨트립니다. 앞서 언급했다시피 TBDR에서는 여러 드로우콜의 버텍스 쉐이더 결과를 모아두었다가 은면 제거(Hidden Surface Removal)를 거친 뒤 실제 보이는 픽셀만 처리합니다. 하지만 이는 알파테스트를 사용하지 않는 완전한 불투명메시일 경우에만 해당됩니다. 알파테스트를 사용하면 버텍스 처리 단계에서는 해당 폴리곤이 차폐 되는지의 여부를 판단할 수 없기때문에 Deferred 처리를 깨트릴 수 밖에 없게됩니다.

유니티에서는 이를 방지하기위해서 완전 불투명 오브젝트들을 모두 렌더링처리한 후에 알파테스트 오브젝트들을 렌더링합니다. 따라서 알파 테스트를 제한적으로만 사용한다면 그렇게 치명적이지는 않습니다. 하지만 애초에 TBDR 칩셋의 구조가 알파테스트 처리에 적합하지 않기 때문에 알파테스트를 사용하지 않는 것이 좋습니다. 그런 이유로, 유니티의 내장 쉐이더 중 Mobile 카테고리에는 알파 테스트 쉐이더가 존재하지 않습니다.

반면에, 알파블렌딩은 데스크톱에 비해서 고속으로 처리가됩니다. 알파블렌딩과정은 출력 내부적으로 대상 버퍼의 읽기/쓰기가 발생합니다. 데스크톱에서는 DRAM에 존재하는 프레임버퍼 전체에 접근해야하기때문에 높은 대역폭을 잡아먹게됩니다. 하지만 TBR에서는 이 처리가 타일 단위로 이루어지고 칩 내부에 존재하는 메모리에서 이루어지므로 고속으로 처리됩니다.


오버드로우

다만 명심해야 할 것은 알파 블렌딩 처리 자체가 빠르다는 것일 뿐이지 오버드로우에서 자유로와진다는 것은 아닙니다. 예를 들어서 넓은 영역의 파티클을 높은 밀도로 뿌리는 것은 여전히 오버드로우 문제를 일으켜서 성능 저하로 직결됩니다. 모바일은 쉐이더 성능이 기종에 따라 천차만별이므로 오버드로우로 인해서 쉐이더 싸이클이 낭비되는 것은 치명적인 문제가 됩니다. 웬만하면 불투명 오브젝트 위주로 리소스를 만들기를 권장합니다. 알파 블렌딩 오브젝트 또는 파티클은 오버드로우를 최대한 피해서 사용하시기를 권장합니다.


로우 폴리곤

너무나 당연한 이야기라 뜬금없어 보일수도 있겠지만 많은 폴리곤을 처리하면 성능이 하락합니다. 게다가, TBDR에서는 많은 폴리곤 처리의 부담이 더욱 큽니다. 앞서 설명드린 버텍스 쉐이더의 결과물들을 담아두는 파라미터 버퍼(Parameter Buffer)의 크기는 당연하게도 무한하지 않습니다. 따라서 이 버퍼가 넘쳐버리면 더 이상의 버텍스 쉐이더 결과물을 받아들이지 못하고 버퍼를 비워줘야합니다. 이 버퍼를 비워주기 위해서는 타일의 픽셀 처리 후 프레임버퍼로 출력하는 사이클을 거쳐야합니다. 때문에, 이론상으로는 TBDR에서는 픽셀의 오버드로우가 발생하지 않아야하지만, 현실적으로는 폴리곤이 많을수록 오버드로우가 발생하게 발생하게 됩니다. 그러므로 오브젝트의 렌더링 퀄리티를 높여야한다면 버텍스를 늘리는 것 보다는 픽셀쪽 연산을 늘리는 것이 오히려 이득일 수도 있습니다.


렌더 텍스쳐(Render Texture)

렌더 텍스쳐를 사용하면 유니티 내부적으로 렌더 타겟(Render Target)을 변경하는 행위를 거치게됩니다. 이러한 렌더타겟을 변경하는 행위는 데스크톱에서도 성능을 잡아먹는 행위가 됩니다. 렌더 타겟을 바꾸기위해서는 CPU가 GPU를 대기하는 과정을 거치게되면서 CPU와 GPU의 병렬 관계가 잠기 깨지는 현상이 발생하기 때문입니다. 

게다가, TBDR에서는 더욱 치명적인 행위가 됩니다. 렌더 타겟을 변경할 시에는 현재 파라미터 버퍼에 쌓여있는 데이터들을 모두 처리해주고 프레임버퍼에 출력합니다. 그 후 다음 렌더 타겟을 위해서 파라미터 버퍼를 비워줍니다. 이런식으로 렌더 타겟을 바꿀 시 deferred 사이클을 추가적으로 처리해줘야 합니다. 때문에 유니티의 카메라에서 타겟 텍스쳐(Target Texture)로 렌더 텍스쳐를 사용하는 경우에는 TBDR의 효율이 떨어지게 됩니다.

이미지 후처리 효과(Image post process Effect)

최근 디바이스들은 컬러 그레이딩이나 블룸 효과 등 이미지 후처리들을 사용할 수 있을 만큼 성능이 좋아졌습니다. 하지만 이러한 이미지 후처리들을 너무 남발해서 사용하면 안되고 필요한 것만 선택적으로 사용해야 합니다. 

우선, 이미지 후처리들은 내부적으로 렌더 타겟을 변경하는 행위를 합니다. 하지만, 더 큰 문제는 대역폭입니다.  물론 픽셀 처리 능력도 관건이지만 대역폭이 더욱 큰 문제가 됩니다. 이미지 후처리들은 현재 렌더링 한 결과를 담고있는 렌더 타겟을 픽셀쉐이더의 입력 텍스쳐로 가져옵니다. 이 때 입력받는 텍스쳐는 칩 내부에 있는 타일이 아니라 공용 메모리에 있는 렌더 타겟을 가져오기때문에 엄청난 대역폭을 잡아먹게 됩니다. (예 : 1080p) 그러므로 이미지 후처리는 신중하게 사용해야 합니다.


카메라 클리어(Clear)

예전의 데스크톱 그래픽카드에서는 한 프레임의 렌더링을 시작하기 전 일부러 화면을 클리어해주지 않고 렌더링을 시작하는 경우도 있었습니다. 하지만 현대의 데스크톱 그래픽카드에서는 반드시 클리어를 해주어야만 하드웨어의 고속 처리를 지원받을 수 있습니다. 이는 모바일 기기의 TBR에서도 마찬가지입니다. 클리어를 수행하여 칩 내부의 버퍼들을 비워줘야만 이후 렌더링 과정을 고속으로 처리할 수 있습니다. 따라서, 유니티의 카메라에서 Clear Flag를 Don’t clear로 두는 것은 데스크톱에서나 모바일에서나 웬만해서는 권장되지 않습니다. 


MSAA

데스크톱에서는 MSAA가 매우 큰 부담이 됩니다. 역시 마찬가지로 대역폭이 가장 큰 원인입니다. 예를 들어 1080p해상도의 화면을 MSAA 2X로 처리하려면 2160p만큼의 대역폭이 필요해집니다. DRAM으로부터 그만큼의 대역폭을 요구한 다는 것은 매우 큰 부담이 되는것입니다. 하지만 TBR에서는 이 역시 칩 내부의 타일에서 이루어집니다. 16x16 혹은 32x32정도에 불과한 타일로 MSAA처리해주는 것은 그리 부담이 되지 않습니다. 

유니티에서 MSAA를 사용하기위해서는 퀄리티 셋팅에서 Anti Aliasing을 2 혹은 4로 선택해주면 됩니다. 다만 개인적으로는, 매우 높은 DPI를 자랑하는 대부분의 모바일 기기에서 안티 앨리어싱이 굳이 필요할 지는 모르겠습니다 :)


프로파일링

유니티5부터 프레임 디버거(Frame Debugger)가 추가되어서 프레임 별 렌더링 과정을 디버깅해볼 수 있게 되었습니다. 이를 통해서 오브젝트의 렌더링 과정이나 배칭 현황을 손쉽게 확인 해 볼 수 있게 되었습니다.  

이미지 출처 : http://docs.unity3d.com/Manual/FrameDebugger.html

하지만 애석하게도 유니티의 프레임 디버거만으로는 드로우콜 별 GPU 퍼포먼스나 세부 상태를 확인하기는 힘듭니다. 다행히도, 칩셋 벤더마다 렌더링 과정을 세부적으로 프로파일링을 해볼 수 있는 툴을 제공해주고 있습니다. 아드레노 칩셋은 아드레노 프로파일러를 통해서, 말리 칩셋은 말리 프로파일러나 DS-5를 통해서, 아이폰은 XCODE를 통해서 프로파일링을 해볼 수 있습니다.

이미지 출처 : http://www.slideshare.net/ozlael/graphics-opt-ndc

다만 문제가 하나 있습니다. TBR 방식을 사용하는 칩셋은 콜 별 설능을 확인하는데 어려움이 없습니다. 하지만 TBDR 방식을 사용하는 칩셋은 콜 별 성능을 직관적으로 확인하는게 사실상 불가능하다는 것입니다. TBDR은 앞서 언급했다시피, 드로우콜 발생 시 픽셀 쉐이더를 즉시 처리하는 것이 아니라 파라미터 버퍼에 결과를 담아둡니다. 그 후 모든 드로우콜을 마치고 나면 그때서야 실제 렌더링을 수행하기 때문에 콜 별 성능을 실질적으로 확인해 볼 수가 없는 것입니다. 따라서 X-code에서 아이폰의 렌더링을 프로파일링 해보면 성능 관련 숫자가 0으로 나오게 됩니다. 0이 아닌 숫자가 나오는 경우도 있지만 이 역시 신뢰할 수 없는 숫자입니다. 대신 프레임 전체에 걸린 성능을 확인해보거나 콜 당시의 사용 텍스쳐 등 주변 정보로 유추해보는 수 밖에 없습니다. 이처럼 아이폰의 프로파일링은 좀 까다로운 편입니다.

이미지 출처 : http://www.slideshare.net/ozlael/graphics-opt-ndc


화면 변화율

TBR에서는 렌더링을 칩 내부의 타일에다 하는 과정은 대역폭을 먹지 않지만, DRAM 영역에 존재하는 프레임 버퍼에 타일을 출력하는 과정에서는 어느 정도는 대역폭이 필요할 수 밖에 없게됩니다. 이러한 대역폭을 조금이나마 절약하기 위해서 말리에서는 트랜잭션 엘리미네이션(Transaction Elimination)이라는 기술을 사용합니다. 타일 별로, 이전 프레임과 화면 결과가 달라지지 않은 타일의 영역은 프레임버퍼를 갱신하지 않고 이전 프레임의 결과를 재활용 하는 것입니다. 그렇게 하면 칩 내부 메모리에서 시스템 메모리로 복사하는 양이 줄어드는 효과를 갖게됩니다. 아래 예시 이미지의 파란 글자 타일이 바로 그 부분에 해당합니다. 

이미지 출처 : http://community.arm.com/

따라서, 고정 카메라를 사용한다면 스카이박스 등의 배경에는 최대한 변화를 피하는 것도 좋은 방법이 될 수도 있습니다. 현실적으로는 3D 게임에는 이러한 조건에 해당하는 경우가 많지는 않을 것입니다. 하지만 2D 게임에는 적합하는 부분이 많은 것입니다.


마치며

TBR에 관한 내용이랑 TBDR에 관한 내용을 같이 언급하긴 하였습니다. 하지만 대부분은 아이폰이나 안드로이드폰만 타겟으로 설정하고 개발할 것이고, 플랫폼마다 데이터를 별도로 제작하지는 않을 것이라 예상합니다. 따라서 현실적으로는 TBR, TBDR 모두 고려대상으로 삼고 이러한 사항들을 인지하면서 개발하여야 할 것이라 생각합니다.

감사합니다.


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

본 포스팅은 유니키 공식 블로그 TUESDAYS ARE FOR #UNITYTIPS를 번역한 글입니다.


Unity를 사용하며 얻은 유용한 팁이 있다면 #unitytips 해쉬 태그로 트위터로 트윗하거나 페이스북으로 공유해주세요. 깔끔한 에디터 워크플로우 혹은 성능 최적화를 위한 규칙 등 어떠한 것도 상관 없습니다. 꼭 새로운 기능이거나 최고급 정보일 필요는 없습니다. 무엇이든 공유할 만한 팁이 있다면 공유해주세요. 그 시작을 위해 개인적으로 베스트 10 #unitytips를 공유합니다.

1. 유니티가 플레이모드 중일때 가끔 이를 잊어버리는 경우가 있습니다. ‘Preferences’ > ‘Colors >  Playmode Tint로 기억하기 쉬운 색으로 설정하세요.
2. 쉽게 카메라를 포지셔닝할 수 있습니다. 씬뷰에서 화면 앵글을 원하는 상태로 놓고 메인 카메라를 선택합니다. 그리고 Align With View를 선택하거나 Ctrl/Cmd + Shift + F 를 누르면 씬뷰에서 바라보는 방향 및 위치로 메인 카메라가 셋팅됩니다.

3. 프로젝트 뷰에서 에셋스토어의 에셋을 검색할 수 있습니다. 프로젝트 뷰에서 검색할 단어를 입력한 뒤 Search를 Assets에서 Asset Store로 변경하세요. 그러면 에셋스토어를 열지 않고도 에셋스토어의 에셋을 미리 볼 수 있습니다.
4. 오브젝트를 회전시킬 시 Ctrl/Cmd를 누른채로 조작하면 스냅되어 회전합니다. 이는 오브젝트를 움직일 때도 마찬가지입니다. 스냅 기본값은 Edit 메뉴의 Snap Settings에서 변경할 수 있습니다.

5. 또 다른 스내핑 트릭입니다. 오브젝트를 선택하고 이동 시 V키를 누른채로 조작하면 버텍스 스내핑이 가능합니다. 이는 특히 모듈화된 지오메트리로 레벨을 구축 할 시 유용합니다.

6. 인스팩터 창의 컴포넌트에 있는 파란 물음표 책 버튼을 누르면 해당 컴포넌트의 도움말을 볼 수 있습니다.
7. 플레이모드에서 재생하고 테스트 중 컴포넌트의 완벽한 값을 발견했나요? 컴포는트에 있는 작은 톱니바퀴 모양의 아이콘을 눌러서 Copy Component를 선택하세요. 플레이모드를 빠져나온 후 그 값을 붙여넣을 수 있습니다.

8. Layers 버튼을 이용하여 특정 레이어의 오브젝트들을 보여주거나 숨길 수 있습니다.

9. 프로파일러 창에서 그래프가 너무 난잡한 경우에는 확인하고싶은 데이터(드로우콜, 스크립트, V싱크 등)의 색상이 칠해진 사각형을 끄고 킴으로써 보고싶은 데이터만 확인할 수 있습니다. 
10. 유니티 에디터의 레이아웃 배치를 편집하고 저장할 수 있습니다. Windows > Layouts > Save / Delete Layouts


Posted by ozlael
,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
Draw call을 줄이는 것은 최적화 시 가장 중요한 요소중 하나입니다. Unity의 새로운 UI는 이러한 Draw call을 줄이는 것이 매우 용이하게 되어있습니다. 이 글에서는 new GUI의 Draw call에 대해 다루고자합니다.

new UI는 Button, Image 등 UI 컴포넌트를 추가 시 자동으로 Canvas하위로 배치되게 되어있습니다. 
유니티 UI의 Draw call은 이 Canvas 단위로 이루어집니다. Canvas 하위의 UI 컴포넌트들에 쓰이는 이미지가 SPrite packing되어 있다면 모두 하나의 Draw call로 처리가 가능합니다. 그러므로 유니티의 UI시스템을 이용하면 Draw call을 절약할 수 있어서 성능 향상에 매우 도움이 됩니다. 하지만 유니티의 UI를 이용한다고 해서 무조건 Draw call이 하나만 발생하는 것은 아닙니다. 성능 향상을 위해서 숙지하고 있어야 할 사항을 몇 가지 이야기하고자 합니다.


Draw call

그래픽 최적화를 위해서는 Draw call을 줄이는 것이 중요합니다. 이는 UI 역시 마찬가지입니다. 유니티의 UI에서는 Canvas마다 각자의 Vertex buffer를 가지고 있기때문에 Canvas가 두개면 최소 두번의 Draw call이 일어납니다. 이는 Canvas하위에 Canvas가 존재하는 경우에도 마찬가지입니다. 만일 Canvas안에 Canvas를 추가하는 경우에도, 씬 바로 하위의 Canvas는 하나 뿐이지만, 최소 두 개의 Draw call이 발생합니다.
위에도 언급했지만 하나의 Draw call이 되기 위해서는 사용되는 이미지들이 atlas 처리가 되어있어야합니다. 즉, Sprite packing되어있는 sprite들을 사용해야합니다. 다만, atlas 페이지가 두 개 이상으로 나뉘어져있으면 경우에 따라서 두 개 이상의 Draw call이 일어날 수도 있습니다. 따라서 Packing Tag를 잘 나누는 것이 중요합니다.

다만, Canvas 별로 Draw call이 일어난다고해서 무조건 모든 UI요소들을 하나의 Canvas에 몰아넣는 것이 꼭 좋은 솔루션인것만은 아닙니다. 동적으로 반응하는 버튼이나 Fill Image등을 처리하기위해서는 매 번 갱신 비용이 발생하기 때문입니다. Runtime시에 변경되지 않는 이미지와 실시간으로 변경되는 이미지가 같은 Canvas에 존재하면 변경되는 이미지 하나를 처리하기 위해서 Canvas의 Vertex buffer를 갱신하기때문에 쓸데없는 갱신 비용이 발생합니다. 따라서, Draw call을 하나 희생하더라도 정적인 이미지들은 별도의 canvas로 빼두는 것이 효율적일 수도 있습니다. 


Text

Text는 별도의 Texture를 사용하기때문에 별도의 Draw call로 발생합니다. 이 텍스쳐는 font별로 만들어지므로 font의 종류를 줄이는 것이 Draw call을 줄이는 방법이기도 합니다.

따라서 아래의 씬에서는 UI가 차지하는 Draw call이 3입니다. 아이콘 이미지들은 패킹되어있는 상태라서 모두 합쳐서 1개의 Draw call을 차지합니다. 텍스트는 3개가 존재하지만 사용된 폰트는 2개라서 2개의 Draw call을 차지합니다. 따라서 총 3개의 Draw call이 발생합니다.


Posted by ozlael
,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
많은 분들이 유니티4의 프로젝트를 유니티5로 마이그레이션 하는 것에 대하여 걱정을 하고계십니다. 하지만 업그레이드 과정은 복잡할 게 없습니다. 물론 설정을 좀 건드려줘야 하는 부분들도 생기고 귀챦은 일들도 생기긴 하지만 그리 큰 노력이 들지는 않습니다. 또한, PBS 및 실시간 GI때문에 무조건 느려지는 것이 아닌가 걱정도 하시는 분들도 계십니다. 하지만 PBS가 아닌 기존 레거시 셰이더도 이용 가능하며 실시간 GI도 사용 여부를 선택 가능하므로 성능 하락에 대한 걱정은 안하셔도 됩니다. 
어서와 유니티5는 처음이지?

그래서 제가 개인적으로 유니티 4.6으로 만들고 있던 프로젝트를 유니티5로 업그레이드하고 그 과정을 기술하고자합니다. 물론 매우 작은 프로젝트라서 큰 도움이 되실런지는 모르겠습니다. 다만 참고 자료정도로 생각해주시면 감사하겠습니다. 유니티5로 빌드한 프로젝트를 구글 플레이에 올려두었습니다. 아직 테스트 버젼이므로 게임의 완성도는 신경쓰지 마시고 작동 여부정도만 확인해보시면 될 것 같습니다 :)

우선 유니티5로 업그레이드 하기 전에 반드시 프로젝트를 백업해두시길 바랍니다. 업그레이드를 시작하면 돌이킬 수가 없으므로 혹시 모를 불상사는 항상 대비해두셔야합니다. 백업 후 유니티5를 실행하시면 유니티4와는 다르게 프로젝트를 선택하는 창이 먼저 뜹니다. 
업그레이드하려는 프로젝트를 선택하면 잠시 후 다음과 같이 업그레이드를 진행하겠다는 창이 뜹니다. upgrade버튼을 눌러서 업그레이드를 진행합니다. 

이후 유니티가 업그레이드를 알아선 진행합니다. 시간이 좀 지난 후 다음과 같은 창이 뜹니다. 유니티5로 넘어오면서 스크립트 API들이 변경 된 사항들이 있습니다. 이를 자동으로 바꿔주겠단 소리인데 Go Ahead를 선택하여 진행해줍니다. 
이 과정들이 매우 오랜 시간이 소요됩니다. 침착함을 가지고 커피한잔의 여유를 즐기세요 :)


오류 사항들

업그레이드가 완료되고나면 수 많은 에러 상황들이 발생할 것입니다. 그런것 없이 완벽하게 마이그레이션 되었다면 당장 꿈에서 깨어나세요 용사여! 꿈이 아니라면 축하드립니다. 당장 사표 한장 집어던지고 뛰쳐나가서 로또 한장 사세요 :)

맨 처음 눈에 들어오는 것은 스카이박스일것입니다. 스카이박스의 십중팔구는 이미지가 정상적으로 나오지 않을 것입니다. 유니티5에서는 스카이박스가 HDR로 그려지는데 유니티4에서 설정했던 LDR 스카이박스를 가져오면 아래와 같이 깨집니다. 이는 간단히 수정 가능합니다. 해당 스카이박스를 선택 후 inspector창에 나오는 Fix now 버튼을 누르시면 해결됩니다.

셰이더에 문제가 발생하시는 분도 계실 수 있습니다. 유니티에서 기본적으로 제공하는 셰이더만 이용한다면 문제가 발생하지 않으실겁니다. 하지만 커스텀 셰이더를 이용하는 경우는 라이팅이 정상적으로 그려지지 않을 수 있습니다. 저같은 경우는 다음과 같이 이상하게 셰이더가 망가져 보였습니다. 
이는 셰이더로 넘겨주는 normal값때문에 발생하는 문제입니다. 유니티5에서는 셰이더로 넘어오는 vertex의 normal값이 메시의 스케일링이 적용되서 넘어옵니다. 따라서 항상 길이가 1이라는 보장이 없습니다. 또한, unity_Scale.w가 작동하지 않습니다. 그렇기때문에 셰이더에서 normalize를 해주어야 합니다. 이는 binormal, tangent 모두 동일하게 적용됩니다. 또한, 기존에는 라이트의 atten 값을 두배로 뻥튀기해줘야만 했는데 이제는 그러지 않아도 됩니다. 기타 셰이더 관련 가이드를 참고하여 수정하시면 정상적으로 보입니다. ( 본 포스팅 마지막의 링크들 참고)

오브젝트의 스케일이 틀어져있는 경우도 존재합니다. 기존에는 FBX 익스포트 시 적용 된 스케일이 정상적으로 적용되지 않는 문제가 있었는데 이제는 정상 반영이 됩니다. 따라서 FBX 메시들의 스케일이 변경되는 것 들이 있습니다. FBX import 설정에서 스케일을 변경시켜주면 됩니다.
간혹 skinned mesh가 깨지는 경우도 있습니다. 서로 다른 레거시 에니메이션과 메시를 휴머노이드로 조합한 이루어진 오브젝트가 간혹 깨지는 경우가 있습니다. 아직 정확한 조건은 확인하지 못하였습니다. 이런 경우는 답이 없습니다만 매우 드문 케이스이므로 크게 걱정하지는 않으셔도 될 듯 합니다.
유니티5에서는 라이트맵 솔루션이 비스트에서 인라이튼으로 바뀌었습니다. 따라서 라이트맵 관련 설정을 다시 손봐주셔야합니다. 기존 버젼에서부터 만들던 모바일 프로젝트라면 실시간 GI를 사용하지 않는 경우가 대부분일테니 Baked GI 외 다른 옵션들은 다 꺼주시면 됩니다. 
GI 관련하여 라이팅 타입 속성이 추가되었습니다. 라이팅 오브젝트의 인스펙터창에 Baking 타입을 설정 할 수 있는 콤보 박스가 있습니다. Baked로 설정해두면 실시간 라이팅에는 반영되지 않고 라이트맵에만 반영되는 라이트가 됩니다. 제 프로젝트의 경우에는 실시간 라이팅을 전혀 사용하지 않고 IBL만 사용하므로 모든 라이트를 Baked로 설정해두었습니다.

또한, 오브젝트의 인스펙터 창에서도 속성들이 추가된 것 들이 있으니 이를 건드려줘야 합니다. Cast Shadow, Receive Shadows, Use Light Probes는 기존에도 있는 속성이였으나 기존 설정이 날라갔을 수도 있으니 한번 더 확인해줘야합니다. Reflection Probes는 새로 생긴 속성이므로 체크 해제해주어야 의미없는 성능 소모를 줄일 수 있습니다. 

유니티5 에서는 메카님이 대폭 개선되었습니다. 기존 버젼 호환이 최대한 작업이 되어있긴 하지만 트랜지션이 누락되는 경우도 가끔 존재합니다. 또한 state에 Write Defaults라는 속성이 생김으로 인해서 기존에 예측했던 동작과 다르게 보이는 경우도 존재할 수 있습니다. 그냥 메카님은 전체적으로 한번 검토해보시는 것이 좋을 듯 합니다.


기타

제 프로젝트는 이러한 수정 사항들이 있었습니다만 프로젝트마다 수정 필요 사항들이 각기 다를것입니다. 더 자세한 내용은 아래 업그레이드 가이드들을 참고 바랍니다.

공식 메뉴얼 (영문) :
한글 번역본 :

결론적으로 말씀드리자면, 작은 프로젝트 혹은 개발 초기 단계의 프로젝트들은 유니티5로 업그레이드 시 큰 무리는 없어보입니다. 유니티 직원으로서는 무조건 유니티5로 업그레이드 하라고 말씀드리고 싶지만, 현실적으로는 규모가 크거나 출시 임박인 프로젝트는 한번 검토를 해보시는 것이 좋을 듯 합니다.
뭐 어찌되었든 유니티5의 세계로 오신 것을 환영합니다!


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

RPG든 액션이든 어떠한 장르에서든 스킬 시스템이 있는 게임은 쿨타임이란 것이 존재합니다. 그리고 이러한 쿨타임은 시각적으로 보여 줄 시 다양한 형태로 표현하지만 크게두 가지 형식으로 표현합니다. 시계/반시계 방향의 부채꼴 또는 수직/수평으로 영역을 채우는 이미지로 표현하는 것입니다.

유니티의 이전 버젼에는 이러한 버튼을 표현해주는 기능이 없어서 직접 구현하거나 플러그인을 사용하여야 했습니다. 하지만 유니티 4.6부터 GUI 시스템이 대폭 개선되어 많은 기능들이 추가되었었습니다.

이 새로운 UI 시스템에서는 이미지를 다루는 기능 역시 대폭 향상되었습니다. Filled 타입 이미지가 추가되었고 이로 인해 손쉽게 쿨타임을 표현해줄 수 있게 되었습니다. 


일단 Hierarchy > Create > UI > Button 으로 버튼을 추가하면 Canvas란 것이 생기고 그 아래 Button이 생긴 것을 확인하실 수 있습니다. 이 Button의 Inspector을 확인해보면 Image와 Button 컴포넌트가 있습니다. 이 중 Image컴포넌트의 Source Image를 원하는 이미지로 바꿔줍니다. 이 때 Source Image는 Sprite 타입의 텍스쳐만 사용 가능합니다. 이미지를 설정 후 Image Type을 Filled로 바꾸면 하위 항목 중 Fill Amount 슬라이더가 생깁니다. 이 슬라이더 값을 0에서 1로 조절 시 이미지가 이에 따라 채워지는 영역이 생깁니다. 쿨타임에 맞게 이 값을 업데이트 해주면 쿨타임 버튼이 되는 것입니다.

다만, 보통은 원래 이미지의 색으로 채워지는 영역 배경에 흑백 또는 어두운 이미지가 존재합니다만 Filled image의 배경 기능은 없습니다. 따라서 같은 위치에 배경을 추가해줘야 합니다. 배경은 단순 이미지만 배치하면 되므로 Create > UI > Image로 이미지를 추가하여 Source Image를 설정해준 뒤 Color을 조절하여 어두운 이미지로 만들어줍니다. Hierarchy에서의 순서가 곧 렌더링 되는 순서이므로 이를 변경하면 됩니다. 배경으로 삼을 이미지를 버튼의 위로 배치하시면 버튼이 배경 위에 그려집니다.

이제 버튼 추가는 다 되었으므로 스크립트를 추가해줘야합니다. 스크립트에서는 쿨타임 값에 맞게 Fill Amount를 조정해주는 동작을 합니다. 또한, 쿨타임 중일 시에는 버튼이 동작하지 않도록 해주어야 합니다. 이러한 내용을 스킬 시스템이나 로직 스크립트에서 직접 컨트롤을 해주어도 되지만 쿨타임 버튼만을 담당하는 스크립트를 만들어두면 버튼을 추가할 때 마다 훨씬 개발하기 수월해질 것입니다.

Project 창에서 우클릭 > Create > C# Script로 스크립트를 하나 생성합니다. 저는 이름을 CoolTimeButton이라고 지었습니다. 스크립트의 내용을 다음과 같이 채웁니다.

버튼이 채워지는 값은  쿨타임 값을 0~1로 변환하여 Image.fillAmount로 설정해주면 됩니다. 쿨타임 동안은 버튼이 작동하지 않도록 하는 것은 Button 컴포넌트의 enable을true/false로 설정해두면 됩니다. 이러한 제어를 매 Update()마다 처리해주는 것입니다. 

스크립트를 완성 후 버튼에 스크립트를 추가해줍니다. 

그럼 이제 버튼이 눌렸을 시 CoolTimeButton 스크립트의 메소드를 호출하도록 하면 됩니다. 이를 위해서 버튼의 Button 컴포넌트 하단의 On Click() 에 있는 +버튼을 눌러서 콜백을 추가해줍니다. Realtime Only 콤보박스 하단의 오브젝트 항목에 버튼 오브젝트 스스로를 설정해주면 Realtime Only 콤보박스 옆의 No Function 콤보박스가 활성화됩니다. 그 콤보박스에서 CoolTimeButton.ResetCooltime()을 설정해줍니다. 이리함으로써 버튼이 눌리었을 시 CoolTimeButton의 ResetCooltime()이 호출되어 쿨타임이 다시 카운팅됩니다. 쿨타임중일 시에는 CoolTimeButton.Update()에 의해 비활성화 처리되므로 버튼을 눌러도 아무런 반응을 하지 않습니다. 쿨타임 자체의 처리는 이제 완료가 되었습니다. 버튼에 연결된 스킬이나 아이템의 스크립트는 마찬가지로 On Click()의 +버튼을 한번 더 눌러서 콜백을 연결해주면 됩니다(아래 예시에서는 SkillNotify). 콜백은 이토록 여러개를 설정 할 수 있어서 다양한 작업을 처리할 수 있습니다.

이처럼 유니티의 새로운 UI기능을 사용하면 UI 작업을 훨씬 수월하게 처리할 수 있습니다. 새로운 UI 시스템의 더 많은 것을 알고싶으시면 공식 튜토리얼 및 에셋스토어 예제를 참고 바랍니다. 감사합니다.


Unity New GUI 튜토리얼 : 

http://unity3d.com/learn/tutorials/modules/beginner/ui

에셋스토어 예제 : 

https://www.assetstore.unity3d.com/en/?gclid=CjwKEAiAjsunBRCy3LSlz_PJqCgSJACJY7yKSmdicbryiDMHiOPX-rMfA-bLLkmb7SBsnl0VSAkYLxoCcNTw_wcB#!/content/25468

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

본 포스팅은 유니티 공식 블로그의 "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 Suite Allegorithmic Substance Painter를 이용하면 이러한 과줭이 한결 수월해집니다.


스캔 데이터

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


재질 예시


바이킹 마을 씬은 많은 적절한 메모리의 텍스쳐를 사용하여 많은 양의 컨텐츠를 나타내고 있습니다. 그 예로 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) 텍스쳐는 디테일의 레벨을 증가시켜주거나 재질의 변화를 제공하는데 쓰일 수 있습니다. 디테일 마스크 속성을 사용하는 것으로 마스킹 될 수 있습니다.

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

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


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




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

* 이 글은 Game Development Forever에도 동일하게 기재되었습니다. (http://gamedevforever.com/326)

* 샘플 프로젝트를 받아서 확인해보세요 : https://github.com/ozlael/PlannarShadowForUnity

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

이는 게임에 있어서도 마찬가지입니다. 그런 이유로 모든 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)가 처리되지 않는다는 단점은 존재합니다만 어짜피 라이팅이 간단한 모바일에서는 대부분 자기 그림자를 원치 않을 것입니다. 



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

여러분들도 아시다시피 유니티는 멀티플랫폼 엔진입니다. 그러다보니 당연히 빌드 결과물 외 에디터에서도 OpenGL과 DirectX 둘 다 지원을 합니다. 하지만 유니티를 실행하면 기본적으로는 실행 OS에 맞게 기본적으로 그래픽 API를 설정해줍니다. 즉, MAC이나 Linux로 수행하면 OpenGL모드로, MS Windows에서 수행하면 DirextX모드로 실행됩니다. 


OpenGL 모드 강제 지정

사실, 미미한 차이긴 하지만 OpenGL과 DirectX의 렌더링 결과가 다르긴 합니다. (프로그래머는 몰라요. 아티스트의 매의 눈으로 봐야 알아요;;) 따라서 개발하다보면 에디터에서도 OpenGL모드로 보면서 작업하고 싶을때가 있습니다. Windows에서도 OpenGL 모드로 보여줄 수 있습니다만 유니티 메뉴의 설정 창 어디에서 이를 변환해주는 항목은 존재하지 않습니다. 유니티 수행 시 커맨드라인 실행 인자로 "-force-opengl"을 주면 OpenGL 모드로 수행됩니다. 매번 cmd로 커맨드라인 열어서 수행하실 필요는 없고 바로가기에 인자로 추가해주시면 됩니다. Unity바로가기 아이콘 우클릭하신후, 대상(T) 항목의 맨 뒤에 "-force-opengl"을 붙여주시면 됩니다. 

그러고나서 유니티를 실행하면 상단 타이틀에 OpenGL모드로 수행되는중이라는 표시가 뜹니다.

마찬가지로 DirectX 9이나 DirectX11 모드로 강제 지정이 가능합니다. (자세한 내용은 공식 메뉴얼을 참고해주세요.) 


DX11 on DX9 GPU

그런데 가끔 DirectX 모드로 수행 시 화면의 색이 원래와는 다르게 나오는 경우가 존재합니다. 특히 노말맵을 쓰는 모델이 티가 많이 나는데, 확인해보면 노말맵이 전제적으로 붉은 느낌으로 변해버린 것을 발견하실 수 있습니다.

이러한 경우는 DirectX의 버젼이 맞지 않아서 발생하는 문제입니다, PC는 DirectX 9까지만 지원하는 GPU를 장착하고 있는데, 유니티는 DirectX 11 버젼으로 수행하기때문에 문제가 발생하는 것입니다. 때문에 타이틀바 상단에 DX11 on DX9 GPU라고 표시가 뜹니다.

이는 프로젝트 셋팅에서 DX11을 사용하지 않도록 설정해주면 해결이 됩니다. File > Build Settings > PC, Mac & Linux Standardalone > Player Settings > Other Settings > Use Direct3D 11 체크를 해제해주시면 됩니다.




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
,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

이 글에서는 Unity에서 LOD(Level of Detail)을 사용하는 것에 대한 이야기를 해볼까 합니다 Object LOD에 촛점을 맞추고 있으며 Shader LOD와는 별개의 이야기입니다.


LOD란 무엇인가?

여러분이 게임 광고를 기획한다고 가정해보죠. 아리따운 누나가 대규모의 적들과 전투하는 켄셉을 잡고 모델을 섭외합니다. 역시 게임 광고 모델은 뭐니뭐니해도 아이유지요. 하지만 문제는 예산이네요. 예산을 최대한 절약 할 방법이 없을까 고민해봅시다.

이건 어떨까요? 기본적으로 모델을 아이유를 캐스팅하지만 하지만 굳이 클로즈업을 해도 되지 않는 장면이라면요? 아이유와 똑같이 생겼지만 아이유보다는 몸값이 저렴한 신봉선으로 대체해도 되지 않을까요? 클로즈업이 필요한 씬에서는 아이유를, 그렇지 않은 씬에서는 신봉선을 이용한다면 광고료를 아낄 수 있지 않을까요? (물론 실제로는 말도 안되는 소리입니다 ㅋ ) 이러한 전략이 바로 Level of Detail의 컨셉입니다. 

이미지 : TIG, 마영전

게임같은 Real-time Rendering에서는 최대한 렌더링 비용을 절약하는 것이 중요합니다. 화면에 작게 그려지는 모델을 그리는데 비싼 비용을 지불 할 필요가 없는 것이지요. 때문에, 카메라와 가까이 있거나 큰 오브젝트는 높을 퀄리티로 그리고, 멀리 떨어져 있거나 작은 오브젝트는 낮은 퀄리티로 표현하거나 연산처리하여 퍼포먼스를 향상시킬 수 있습니다. 이러한 기법을 Level of Detail(이하 LOD)이라 부릅니다. 말 그대로 디테일의 단계를 두어서 상황에 맞게 표현하는 것이지요.이러한 컨셉은 Material LOD, Terrain LOD, Mesh LOD, Bone LOD 등 여러 방면에서 쓰입니다. 이 중 Mesh 를 LOD 시키는 것에 대한 이야기를 할까 합니다.

https://www.assetstore.unity3d.com/kr/#!/content/8855


Unity에서의 LOD

LOD는 3D 게임 개발에 있어서 꼭 필요한 기능이고 당연히 Unity에서도 제공을 합니다. 다만 Pro Version에서만 제공이 되고 있어서 Free Version에서는 사용이 불가능합니다.(2015년 1월 기준) 사용법도 간단합니다. 오브젝트에 LOD Group 컴포넌트를 추가하고 LOD 0에는 가까이서 보일 오브젝트를 설정해주고, LOD 1에는 멀리서 보일 오브젝트를 설정해주면서 조절해주면 됩니다. 카메라 아이콘을 슬라이드해가면서 바로바로 확인하면서 편집이 가능합니다. 

자세한 설명은 공식 메뉴얼을 참고해주세요. (공식 메뉴얼 :  http://docs.unity3d.com/Manual/LevelOfDetail.html)


LOD 툴

유니티로 게임을 개발 할 때 에셋스토어를 활용하면 게임 모델을 손쉽게 구할 수 있습니다. 판타지, 레이싱, SF등 다양한 장르의 배경 및 케릭터 오브젝트들이 있어서 다운로드만 받으면 즉시 사용이 가능합니다. 유료는 물론 무료 모델들도 많이 있어서 저도 에셋스토어에서 다운로드받아 게임 제작을 하고 있습니다. 하지만 몇 가지 문제점들이 존재합니다.

첫째, 모든 리소스들이 LOD 시스템을 대응하고 있지는 않다는 것입니다. 이러한 경우는 Low quality 모델을 따로 생성해줘야 하지요. 아티스트팀이 따로 존재한다면 아티스트가 직접 Low quality 모델을 제작해줄 수도 있겠지요. 하지만 아티스트가 아예 없거나 일손이 모자란다면 자동으로 모델을 만들어주는 툴이 필요할겁니다. 

둘째, PC 및 콘솔 대응 리소스들도 많이 있습니다. 모델 하나가 만 단위가 넘는 폴리곤을 가지고 있는 경우도 허다합니다. 타겟이 PC 및 콘솔이라면 케릭터에 그정도를 투자할 수도 있을 것입니다. 하지만 모바일 타겟이라면 거의 불가능에 가까운 무거운 모델들일 것입니다. 이러한 모델들을 모바일에서 사용 할 수 있을 정도로 폴리곤을 줄여주는 툴이 필요할겁니다.

셋째, 파츠가 많이 나뉘어져 있는 모델도 존재합니다. 건물 하나가 문, 지붕 벽 등 몇 파츠로 나뉘어져 있거나, 애초아 드럼통 벽돌 등 다른 오브젝트등을 조합해서 하나의 배경 프랍으로 사용해야 하는 경우도 존재할 것입니다. 이러한 경우 메시 및 매터리얼의 갯수 등 상황에 따라 드로우콜이 늘어나게 됩니다. 드로우콜이 많아지면 성능이 느려지기 때문에 이 오브젝트들을 하나의 메시와 매터리얼로 만들어줘는 툴이 필요할겁니다. (드로우콜이 성능에 왜 영향을 미치는 지는 나중에 따로 설명하는 시간을 갖도록 하겠습니다.) 

이러한 이유들로 많은 LOD 관련 툴들이 존재합니다. 당연히 에셋스토어에도 LOD 툴들이 많이 있습니다.


Simplygon

그 중 Simplygon(심폴리곤이 아니라 심플리곤입니다 ㅋ)을 소개할까 합니다. Simplygon은 무료입니다. 몇 가지 제약이 있긴 합니다만 기본적으로는 무료입니다. 일단 에셋스토어에서 다운로드후 Import하시면 Unity 메뉴 Window에 Simplygon 항목이 생깁니다.(https://www.assetstore.unity3d.com/kr/#!/content/10144)


이제 실제로 사용하는 예를 보여드릴까 합니다. 우선 에셋스토어에서 모델을 하나 받습니다. 

https://www.assetstore.unity3d.com/kr/#!/content/10739

언니가 무섭고 이쁘긴 한데 폴리곤이 너무 많습니다. 세상에나 2만7천 폴리곤이라니 모바일에서는 전혀 써먹지를 못하겠네요.

이제 이 모델을 Simplygon으로 폴리곤을 반토막 내볼까 합니다. 모델을 선택 후 Simplygon 창을 클릭하면 다음과 같이 네개의 하위 탭이 존재합니다. (가입이 안되어있으시면 계정 등록을 하시면 됩니다. 일단 무료 계정으로 가입하셔도 충분합니다.) 반토막낼거니 Quick Start탭의 Reduction 항목에 50으로 입력사고 아래의 노란색 마크 버튼을 클릭합니다.

그러면 모델 데이터를 Simplygon서버에 보내고 받아오는 과정이 이루어지면서 Manage Jobs 탭의 톱니바퀴 아이콘이 움직입니다. Manage Jobs 탭을 열어 Download Assets Automatically를 체크해줍니다.

 그리고나서 status 상태가 100%이 되면 처리된 에셋을 자동으로 import하고 LODs 폴더에 처리된 모델이 생깁니다. 

확인해볼까요? 일단 육안으로는 큰 차이를 모르겠네요.

하지만 폴리곤 수를 보면 2만7천 폴리곤이였던 모델이 1만3천 폴리곤으로 확 줄었습니다. RPG처럼 케릭터가 많이 나오는 게임에서는 사용이 불가능하겠지만 대전격투게임처럼 케릭터가 적게 나오는 게임에서는 쓸만하겠네요.

한번 더 줄여볼까요? 이번엔 원본에서 3%로 설정해서 돌려본 결과입니다. 원본과 비교해보면 얼굴이 많이 못생겨지긴 했지만 전체적인 실루엣은 어느정도 유지해주고 있습니다.

하지만 폴리곤은 540여개로 대폭 줄었습니다.

멀리 두고 비교해보면 두 모델 간의 차이는 눈에 띄지 않을 정도입니다.

이번엔 다른 모델도 한번 살펴볼까요? 이 두 골렘은 작게 해서 보면 차이는 없어보입니다.

https://www.assetstore.unity3d.com/kr/#!/content/13631

하지만 폴리곤은 3배 이상 차이가 납니다.

이런 식으로 SImplygon같은 툴을 이용하면 LOD에 필요한 데이터를 쉽게 생성 할 수 있습니다. 더 나아가서는 PC 및 콘솔을 타겟으로 만들어진 데이터를 모바일에서 사용 할 수 있도록 폴리곤을 줄이는 용도로도 사용이 가능합니다. 물론 툴로 줄이는 것 보다는 아티스트가 이태리 장인정신으로 한땀 한땀 줄여주는 것이 가장 퀄리티는 좋습니다. 하지만 그렇지 못하는 상황이라면 툴의 도움이 정말 요긴하게 쓰일 것입니다. 

SImplygon의 추가적인 사용법은 공식 튜토리얼을 참고해주세요. (https://www.youtube.com/watch?v=qEyPVNGxGb8)


케릭터 LOD

이제 메시는 생성했으니 실제 LOD가 작동하는 케릭터를 만들어보도록 하죠. non-skinned mesh를 이용하는 오브젝트(예를 들면 건물이나 배경 프랍들)의 LOD 처리는 어려울게 없습니다. 하지만, 에니메이션 처리 되는 skinned mesh 케릭터에게 LOD 처리하는 것은 조금 귀챦습니다. 일단 Simplygon으로 생성하기 이전의 원본 mesh와 Simplygon 처리 후의 LOD 메시간의 본 에니메이션 정보는 공유되지 않습니다.

우선, Simplygon으로 생성 한 케릭터 중 Level 0 즉 가까이 있을 때 그릴 용도로 사용 할 케릭터를 씬에 올려놓습니다. 그러면 케릭터 오브젝트 바로 하위에는 본 계층구조 오브젝트와 skinned mesh 오브젝트가 있습니다. 이 메시 오브젝트를 Duplicate하여 사본을 만듭니다. 다른 오브젝트나 prefab에 있는 메시를 가져오면 안됩니다.

 그 후, 새로 만들어진 사본의 Skinned Mesh Renderer의 Mesh를 Level 1 즉 멀리 있을 때 그릴 용도로 사용 할 메시로 바꿔치기해줍니다.

이제 케릭터 오브젝트에 LOD Group 컴포넌트를 추가해주고 LOD 0, LOD 1 각각 메시를 설정해줍니다.

이제 케릭터가 하나의 에니메이터로 에니메이션하면서 거리에 따라 LOD 메시가 바뀌는 것을 확인 가능합니다.


마치며

게임 개발 시 얼마나 최적화를 시키느냐가 중요한 과제중 하나입니다. LOD 처리를 하는 것은 쉬우면서도 효과적인 최적화 방법중 하나입니다. 유니티는 이 기능을 쉽게 사용 가능하도록 제공해주고 있고 에셋스토어에는 보조장치들이 많이 존재합니다.SImplygon은 그 중 하나일 뿐이지 반드시 이것을 사용해야한다는 것은 아닙니다. 다만 LOD를 처리하는 예를 보여주기 위한 수단으로 소개해드린 것일 뿐입니다. 물론, 카메라가 고정되어있는 탑뷰(및 쿼터뷰)에서는 LOD 처리가 필요 없을 수도 있습니다. 하지만 요즘은 모바일 게임들도 탑뷰에서 탈피하는 게임도 많이 있어서 LOD의 필요성이 많아지게 될 것입니다. 

감사합니다.

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

* 아직 테스트 단계라 원활한 접속이 되지 않을 수 있습니다.


만일 여러분이 게임을 출시했는데 난이도가 넘 어렵다는 평이 많다고 가정해봅시다. 그래서 주인공의 공격력과 방어력을 조절해야 합니다. 근데 로직은 변한 것 하나 없고 단순히 수치만 변경했는데도 빌드를 새로하고 다시 업로드를 해야하네요. 안드로이드는 업로드하면 그나마 몇시간 후면 반영되는데 아이폰은 일주일을 꼬박 기다려야하네요. 뭐 별수 있나요 눈물을 머금고 기다려서 난이도 패치를 끝냈습니다. 그 기념으로 일시적으로 아이템 드랍률을 올려주는 이벤트를 하려고 합니다. 이번에도 로직은 바뀌는 것 없이 단순 데이터 수치만 바뀌는건데도 빌드를 다시 해야하네요. 안드로이드와 아이폰간의 빌드 반영 딜레이 뿐만 아니라 업데이트 받은 유저와 아닌 유저의 차이도 골치아프겠네요.

물론 클라이언트-서버 구조로 되어 있는 게임은 이런 고민이 필요 없습니다. 애초에 중요 로직과 데이터들이 다 서버에 있으니까요. 하지만 보통 로직 서버를 따로 두지 않는 캐쥬얼 인디 게임들이라면 이런 고민이 절실합니다. 


Unity Cloud Data(https://data.cloud.unity3d.com)

이번 글에서는 그러한 고민을 해결해 줄 수 있는 Unity Cloud Data 서비스를 소개하려고 합니다. Unity Cloud Data (이하 UCD)는 서버-클라이언트 구조가 아닌 게임도 중요 데이터들을 서버에 둘 수 있도록 해주는 서비스입니다. 데이터만 서버에서 제어하면 클라이언트에서는 그 값을 가져다 사용하기때문에 따로 추가적인 패치가 필요가 없습니다. 그렇게되면 앞서 언급한 공격력 방어력 아이템 드랍률 등의 단순 수치들을 수정해주는 문제가 아주 간결해지는 것이지요. 데이터 연동 서버도 유니티에서 제공해주고 있으므로 따로 따로 서버를 마련할 필요도 없습니다. 


실습 ㄱㄱ !

그럼 간단히 같이 실습해보면서 확인해볼까요? 유니티 튜토리얼중에 Space Shooter라는 샘플 게임이 있습니다. 우선 이 샘플을 다운로드받아주세요. (https://www.assetstore.unity3d.com/kr/#!/content/13866)

튜토리얼 영상도 있어요 : http://unity3d.com/learn/tutorials/projects/space-shooter


게임 자체는 매우 간단해요. 운석과 적 비행기가 계속 나오고 플레이어 비행기를 움직이면서 총알을 발사하는 간단한 룰입니다. WASD로 이동하고 마우스 버튼으로 발사합니다. Space Shooter 에셋을 import한 후 Assets/Done/Done_Scenes에 있는 Done_Main Scene을 열어주세요. Game Controller 오브젝트에 있는 Done_Game Controller script에서 적들이 등장하는 갯수와 주기 등등을 제어하고 있습니다. 이 값들을 서버에 연동하여 변경하는 작업을 확인해볼까 합니다.


UCD 페이지 설정

우선은 UCD 게임 프로젝트 별로 서버를 설정해줘야 합니다. UCD(https://data.cloud.unity3d.com)에 가서 로그인 후 다음과 같은 절차를 따라주세요.

  1. 우선, Create New Project 버튼을 클릭해서 새 프로젝트를 생성합니다. 이 프로젝트는 게임 별로 따로 존재하여야합니다. 일단은 Test01이라고 이름 지었습니다. 
  2. 프로젝트를 생성하고나면 데이터 시트를 생성해줘야 합니다. 방금 만든 Test01 프로젝트로 들어가서 페이지 상단에 있는 Create New Mesater Sheet라고 적혀있는 녹색 버튼을 눌러서 시트를 생성해줍니다. 저는 gamectrl이라고 이름을 지었습니다.
  3. 그 후, Access Token을 발급해줘야합니다. Test01 프로젝트로 페이지 하단에 있는 Create New Editor Token이라고 적혀있는 녹색 버튼을  클릭해서 새 토큰을 생성해줍니다.
이제 Organization ID, Project ID, Editor Token, Sheet 등 서버 페이지에서 필요한 셋팅은 모두 완료하였습니다. 

이제 Unity Cloud Data Plugin 다운로드받읍시다. 다운로드 페이지(https://data.cloud.unity3d.com/#/download)로가서 다운로드를 받고 패키지를 import합니다. UCD를 import하고나면 Assets/UnityCloudData가 생긴것을 확인 가능합니다.


유니티 에디터 작업

이제 Hierarchy에서 Create > Create Empty를 수행해서 빈 오브젝트를 만듭니다. 저는 이 오브젝트 이름을 UCD로 지었습니다. 이 오브젝트에 Add Component를 수행해서 Unity Cloud Data > Cloud Data Manager 컴포넌트를 추가해줍니다. 앞서 생성했던 Organization ID, Project ID, Access Token등을 기입해주시면 됩니다. Access Token 바로 아래 있는 Create New Sheet 버튼을 수행하여 Cloud Data Sheet 컴포넌트를 생성하고 Path에는 앞서 생성한 시트의 이름을 적어줍니다. 그 후 Refresh from Unity Cloud Data를 수행하여 이상이 없는 지 확인합니다.

이제 본격적으로 수치를 연동해봅니다. Hierarchy에서 Game Controller 오브젝트를 선택합니다. Done_GameController의 Hazard Count, Spawn Wait, Wave Wait를 연동하고자 합니다. 스크립트를 열고 아래 표시한 부분을 수정 및 추가해줍니다. 코드 변경은 이게 끝입니다. MonoBehaviour대신 UCD 기능이 있는 CloudDataMonoBehaviour를 상속받도록 수정하고, 서버와 연동하고싶은 변수에 CloudDataField 태그를 붙여줍니다. sheetPath는 앞서 생성한 gamectrl로 설정해줍니다만 생략할 수도 있습니다.

그 후 Game Controller의 Inspector를 확인해보면 변수들이 Cloud Data Fields로 바뀌어 있습니다. 그 아래 있는 Save to Cloud Data Sheet를 클릭하면 Saving new fields 라는 메시지로 바뀌며 UCD 서버로 데이터가 연동됩니다. 

다시 UCD의 test01>gamectrl 페이지를 새로고침하면 데이터가 연동되어있는 것이 보입니다.

이제 모든 것이 완료되었습니다. 유니티로 돌아가서 게임을 수행시킵니다. 그 후 gamectrl페이지의 수치를 변경(hazardcount:50, spawnwait:0.01, wavewait:0.5) 후 Save Changes를 눌러 값을 저장해줍니다. 다시 유니티로 돌아가서 게임오버 후 R키를 눌러서 Scene이 re-load되면 적들의 빈도 및 밀도가 변경되는 것을 확인 가능합니다. 



마치며

앞서 언급했듯이, MMORPG 등, 중요 로직은 이미 서버에서 처리되고 있는  서버-클라이언트 구조의 게임에서는 UCD가 필요는 없습니다. 하지만 따로 서버가 없는 게임에서는 매우 유용하게 쓰일 것 같습니다.다만, 아직은 Alpha 서비스 단계라서 라이브 서비스 중인 게임에서는 사용하기에는 조심스럽습니다. 하지만, 이제 개발 착수단계인 프로젝트에서는 사용 여부를 고려해보심이 어떨까 합니다.

감사합니다.

Posted by ozlael
,