'Unity3D'에 해당되는 글 43건

  1. 2018.12.23 3D 메시 렌더링을 위한 버텍스 트랜스폼 (Vertex Transform)
  2. 2018.12.15 ASTC : 가성비 좋은 텍스처 압축 포맷
  3. 2018.12.15 LWRP(LightweightRenderPipeline) : 렌더링 성능을 위한 경량 파이프라인
  4. 2018.11.03 텍스쳐의 Read/Write Enabled 1
  5. 2018.10.30 유니티의 Mixed Lighting 모드 (라이트맵 모드)
  6. 2018.08.03 유니티 안드로이드 빌드 환경 설정 가이드 5
  7. 2018.07.10 유니티 최적화 관련 문서들 모음집 (Documents of optimization for Unity) 5
  8. 2017.09.30 Unity OVR Input 2
  9. 2017.08.16 나만 안써 진짜 사람들 메모리 프로파일러 다 쓰고 나만 안써
  10. 2016.10.14 유니티 Best Practices - Resources 폴더
  11. 2016.08.31 Debug.Log() 사용 시 주의점 1
  12. 2016.04.29 유니티에서의 텍스쳐 밉맵과 필터링 (Texture Mipmap & filtering in Unity) 5
  13. 2016.01.12 유니티 UI 위에 3D 오브젝트 그리기 (Rendering 3D objects on Unity's UI) 1
  14. 2016.01.06 저사양 기기에서 스탠다드 쉐이더 사용하기 (Using Standard Shader on low-end devices)
  15. 2016.01.06 유니티에서 ETC2 텍스쳐 사용 시 애매한 사항들 (Ambiguous things by using ETC2 on Unity 4
  16. 2016.01.03 PBS 느낌을 흉내내기 위한 Metallic MatCap 쉐이더 1
  17. 2015.12.09 유니티 5.3 WebGL 업데이트 (UNITY 5.3 WEBGL UPDATES)
  18. 2015.10.08 쉐이더에서 한번에 샘플링 할 수 있는 텍스쳐 갯수는? (How many textures do you sample in Shader?)
  19. 2015.09.30 커스텀쉐이더에서 리플렉션 프로브 사용하기 (Using Reflection Probes in Custom Shader)
  20. 2015.09.23 유니티5의 라이트맵 빌드 시간이 향상됩니다. (라이트맵 분산 빌드 & 점진적 빌드 소개)
  21. 2015.09.18 유니티 패치 릴리즈 계획 (UNITY PATCH RELEASE PLAN)
  22. 2015.09.16 몇 번의 클릭만으로 유니티 서비스를 사용해보세요 (UNITY SERVICES ARE JUST A FEW CLICKS AWAY)
  23. 2015.09.10 유니티 5.2 - 유니티 서비스로 가는 길 (original: UNITY 5.2 – YOUR GATEWAY TO UNITY SERVICES)
  24. 2015.09.01 Unity WebGL 로드맵(Roadmap) (한글)
  25. 2015.08.24 몹의 다양화(variation) 작업을 위한 파츠 컬러 쉐이더(Parts Color Shader) 2
  26. 2015.08.18 "게임은 어떻게 만드나요?" 라는 질문에 뭐라고 대답해야 할까요? (질문글 작성 가이드)
  27. 2015.06.12 유니티 5.1부터는 Unity Analytics가 기본적으로 통합되었습니다.
  28. 2015.06.12 유니티 배우려는데 무슨 언어로 배워야할까요? C#? 아니면 자바스크립트? 3
  29. 2015.06.09 모바일 기기의 Tile Based Rendering(타일 기반 렌더링)과 유니티에서의 주의 사항 #2 : TBR 대응 리소스 제작시 주의점 2
  30. 2015.06.09 모바일 기기의 Tile Based Rendering(타일 기반 렌더링)과 유니티에서의 주의 사항 #1 : TBR의 이해 1
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

버텍스 트랜스폼 (Vertex Transform)


버텍스 데이터들은 GPU 메모리에 저장되어 있습니다.렌더링을 수행해야하는 시점이 되면 GPU는 메모리로부터 버텍스 정보들을 가져옵니다. 그리고 적절한 위치에 그려주기 위해서 위치 변환 즉 트랜스폼(transform)을 수행해주게 됩니다. (명사형으로 트랜스포메이션(Transformation)이라고 표현하기도 합니다.)


저장되어 있는 버텍스 데이터는 특정 위치가 반영된 데이터가 아닌 메시 형태만 반영되있는 데이터입니다. 하나의 메시가 여러 오브젝트 즉 인스턴스에서 사용되고 인스턴스마다 위치가 다릅니다. 또한 매번 위치가 바뀌기 때문에 원본 메시 데이터에 3D 공간상의 위치를 반영해놓을 수는 없고, 3D 공간의 특정 위치가 반영되지 않는 원점 기준의 메시 모델에 대한 위치 데이터만 가지고 있는 것입니다. 이러한 데이터를 로컬 스페이스(local space)에 존재한다고 표현합니다.





이를 3D 공간상의 특정 위치에 위치시켜줘야 합니다. 만일 오브젝트의 인스펙터에서 트랜스폼 컴포넌트의 position이 -4.5,0.7,3 으로 설정되어 있고 rotation y가 55으로 되어있다면 메시 데이터를 -4.5,0.7,3으로 위치시켜주고 y축으로 55도 회전시켜줘야합니다.

이러한 식으로 월드 스페이스(world space) 혹은 월드 좌표계(world coordinates)로 변환시켜주는 것을 월드 트랜스폼(world transform)이라고 표현합니다.

이 월드 트랜스폼 시에는 메시의 모든 버텍스의 위치와 노멀(Normal)(경우에 따라서 탄젠트(Tangent) 및 바이노멀(Binormal) 데이터 포함)을 월드 트랜스폼 시켜줍니다. 즉, 모든 버텍스의 위치와 노멀 정보가 로컬 스페이스에서 월드 스페이스로 변환되는 과정이 월드 트랜스폼인 것입니다.




월드 스페이스로 변환을 해준 뒤에는 카메라 스페이스(Camera Space)로 또 변환을 해줘야 합니다. 월드 트랜스폼을 거쳐서 모든 오브젝트의 버텍스들이 원래 있어야 할 위치로 위치하게 되었지만 , 이 오브젝트들은 카메라를 통해서 디스플레이가 됩니다. 카메라는 원점(x:0,y:0,z:0)에만 있는 것이 아니고 카메라 역시 고유의 위치와 방향을 가지고 있습니다. 그렇기 때문에 오브젝트의 버텍스들을 카메라에 상대적인 위치로 변환을 해줘야 합니다. 이러한 공간을 카메라 스페이스(Camera Space) 또는 뷰 스페이스(view space)라고 부르고, 뷰 스페이스로 변환하는 과정을 뷰 트랜스폼(view transform)이라고 합니다.




오브젝트들은 3차원 공간에 있지만 최종적으로 오브젝트가 렌더링되어 디스플레이 되는 공간은 2차원입니다. 3D 공간을 2D상의 위치로 매칭시켜주는 과정을 프로젝션(투영,projection)이라고 합니다. (빔프로젝터에서 빛을 쏘아서 스크린에 투영시키는 모습을 연상하면 됩니다.)


이러한 프로젝션 트랜스폼 과정에서는 원근법도 적용이 됩니다. 사람이 세상을 볼 때 멀리 있는 것은 작게 보이고 가까이 있는 것은 크게 보입니다. 또한 거리가 멀어질 수록 많은 사물들이 시야에 들어오게 됩니다. 카메라를 통해서 볼때도 이 역시 마찬가지며 유니티 카메라에서는 뷰 영역을 나타내는 프라미드 볼륨을 확인할 수 있습니다. 이를 뷰 프러스텀(view frustum)이라고 합니다.


이러한 투영을 퍼스펙티브 프로젝션(원근 투영, perspective projection)이라고 부릅니다.

cam_pers.png


또한, 원근법이 적용 된 퍼스펙티브 프로젝션 외에도 원근법이 제거 된 오쏘그래픽 프로젝션(orthographic projection, 직교 투영)도 존재합니다. 카메라와의 거리와는 무관하게 시각적으로 크기의 변화가 없이 보여집니다.

cam_ortho.png


카메라 투영에 관한 설정은 다음 비디오에서 자세하게 확인할 수 있습니다 : https://youtu.be/52g_3CX7avo?t=4m2s



유니티의 쉐이더를 작성할 시 UNITY_MATRIX_MVP 변수는 이러한 변환을 의미합니다. UnityShaderVariables.cginc 파일에 기술되어 있습니다.


더 많은 내용은 "유니티 그래픽스 최적화 스타트업"을 참고하세요








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


ASTC(Adaptive Scalable Texture Compression)


ASTC(Adaptive Scalable Texture Compression)는 ARM에서 개발하고 2012년에 크로노스 그룹에서 OpenGL ES에 표준으로 지정되었습니다. ASTC는 PVRTC나 ETC와 마찬가지로 손실 블록 기반 텍스처 압축 알고리즘입니다.


ASTC는 용량과 품질에 대한 트레이드오프(Trade-off)가 가능합니다. ETC나 PVRTC는 bpp가 한정되어 있는 반면,  ASTC는 8bpp에서 0.86bpp까지 품질을 향상시킬 수 있습니다. 이러한 조절이 가능한 것은 가변 블록 크기를 사용하기 때문입니다. ETC와 PVRTC는 압축되는 블럭의 크기가 4x4로 고정되어 있습니다. 반면, ASTC는 압축되는 기준 블럭의 크기를 4x4에서 12x12 블럭으로 다양하게 선택을 할 수 있습니다. ASTC는 블럭 당 128비트를 사용합니다. 128비트를 4x4블럭에 할당하면 128/16=8bpp가 되는 것이고, 12x12 블럭에 할당하면 128/144=약0.89bpp가 되는 것입니다.

아래 이미지는 좌측으로부터 각각 8bpp, 3.56bpp, 2bpp의 결과를 보여주고 있습니다.

<이미지 출처 : 위키피디아 >


유니티에서도 텍스쳐 압축 포맷을 ASTC로 선택할 수 있고, 4x4에서 12x12까지 블록 크기를 선택할 수 있습니다.


텍스처의 중요도나 복잡도에 따라서 블럭의 크기를 개별적으로 선택할 수 있습니다. 예를 들어거 캐릭터의  텍스쳐같은 경우는 4x4를 선택하고,


파티클같이 이미지가 많이 뭉개져도 상관 없는 경우는 12x12를 선택함으로써 용량을 절약할 수 있습니다.


ASTC는 ETC보다 더 복잡한 인코딩 과정을 거칩니다. 그러다보니 압축 시간이 조금 더 걸리지만 결과적으로는 ETC보다는 ASTC가 일반적인 품질이 좋습니다.

< 이미지 출처 : developer.arm.com>


ASTC는 안드로이드폰과 iOS폰 모두에서 지원하기 때문에 같은 텍스처 압축 포맷을 사용함으로써  퀄리티와 용량에 대한 유지 보수를 한결 더 수월하게 할 수 있습니다.


물론, 문제는 지원 기기의 범위입니다.


안드로이드의 경우는 OpenGL 3.2 이상 혹은 OpenGL ES 3.1 + AEP(Android Extension Pack)이 지원되어야합니다. 삼성 갤럭시 S6 혹은 LG G5 이상의 기기들이 이에 해당합니다. 안드로이드의 경우에는 기종이 정말 다양하게 존재하기 때문에 반드시 주 타겟 기기에서 지원 여부를 직접 테스트해보아야합니다.


iOS는 A8 processor를 사용하기 시작하는 기종부터 사용이 가능합니다. iPhone 6, iPad mini 4가 이에 해당합니다.


따라서, 그 이하의 구형 기종도 지원해야하는 게임이라면 ASTC를 사용하기가 애매할 수도 있습니다. 하지만, 그렇지 않은 경우에는 ASTC를 사용하는 것이 품질과 용량을 모두 절약할 수 있는 좋은 방법이 될 수도 있습니다. 그러한 이유로 최근에 출시하는 많은 3D 게임에서 ASTC를 사용하기 시작하고 있습니다.


관련 참고 링크 :

https://developer.nvidia.com/astc-texture-compression-for-game-assets



더 많은 내용은 "유니티 그래픽스 최적화 스타트업"을 참고하세요

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


SRP(Scriptable render pipeline)

유니티 2018부터 스크립터블 렌더 파이프라인(Scriptable render pipeline, 이하 SRP)이라는 기능을 제공합니다. SRP는 유니티의 렌더링 처리 방식을 C# 스크립트로 제어할 수 있는 기능입니다. 이를 통해서 라이팅 처리 방식을 포함한 전반적인 렌더링 루프를 직접 구성할 수 있습니다. 그렇게 함으로써 기존에 유니티에서 고정해놓은 방식대로만 렌더링하는 것이 아니라, 직접 렌더링 루프를 커스터마이징함으로써 원하는 방식으로 렌더링을 구성할 수 있습니다. 예를 들어서, 새로운 렌더링 기술을 직접 적용할 수도 있고, 특정 하드웨어에 맞게 최적화를 할 수도 있습니다.

유니티의 로우 레벨 렌더링 파트는 유니티가 C++로 구현해놓았습니다. 그리고, 이러한 기능들을 C# 스크립트로 사용하고 제어할 수 있도록 되어 있습니다. 유니티를 사용하는 개발자는 C# 스크립트로 자신만의 렌더 루프를 만들 수 있습니다. 하지만, SRP로 렌더 파이프라인을 직접 구성한다는 것은 많은 지식이 요구되고 많은 작업이 필요합니다. 대신, 유니티는 유니티에서는 SRP를 이용하여 HDRP(HD Render Pipeline)와 LWRP(Lightweight Render Pipeline)을 만들어두어 제공하고 있습니다. SRP로 직접 렌더 파이프라인을 구성하지 않고 HDRP나 LWRP를 이용하여 프로젝트를 진행할 수 있습니다.


HDRP(High Definition render pipeline)

HDRP는 하이엔드 PC나 콘솔등을 고려해서 고품질의 비주얼을 구현하는데 적합한 파이프라인입니다. 유니티의 빌트인에 구현되어있는 디퍼드나 포워드보다 발전되고 개선된 렌더링 기법이 적용되어있습니다. (주석 : Clustered tiled lighting, Fine pruned tiled lighting) 또한, Anisotropy, Subsurface 등 더 많은 재질 표현이 가능합니다.

하지만, HDRP는 기본적으로 요구되는 하드웨어 스펙들이 존재하기 때문에 성능이 낮은 플랫폼에서는 작동하지 않습니다. 즉, 모바일 게임 개발용으로는 적합하지가 않습니다.


LWRP(Lightweight Render Pipeline)

대신, 모바일을 위해서 LWRP라는 파이프라인이 제공됩니다. LWRP는 퍼포먼스에 최적화되어 있고, 모바일이나 VR이나 AR처럼 성능에 민감한 환경에서 높은 성능을 보여줍니다.

LWRP는 기존 파이프라인에 비하여 성능을 위한 특징들이 존재합니다. 이를 통해서 라이팅과 쉐이딩 관련하여 단점들을 해결하여 성능 제약이있는 플랫폼에서 최적화 된 실시간 렌더링 퍼포먼스를 제공합니다.


Multi light Single pass

그 중 가장 큰 특징은 실시간 라이팅들이 싱글패스로 처리된다는 점입니다. 앞서 설명하였듯이 포워드 렌더링에서는 실시간 라이트를 여러개를 처리하기 위해서는 그만큼 덧그리게 됨으로써 드로우콜이 늘어납니다. (주석:이를 멀티 라이트 멀티 패스(Multi light Multi pass)라고 표현됩니다.)

LWRP는 유니티에 기본으로 구현된 포워드 렌더링과는 달리, 여러개의 실시간 라이트를 한번의 패스로 처리하도록 만들어져 있습니다. (주석 : 즉, 멀티 라이트 싱글 패스(Multi light Single pass)입니다. ) 오브젝트를 렌더링 할 때 오브젝트에 영향받는 실시간 라이트들을 쉐이더에 전달해줍니다. 쉐이더에서는 한번에 여러 라이트들을 모두 처리해줌으로써 별도의 드로우콜이 발생하는 것을 방지합니다. 이러한 과정을 통해서 기존의 포워드 렌더링과 비교하여 드로우콜이 줄어들게 설계되어있습니다.


관련 참고 자료 링크 : 


더 많은 내용은 "유니티 그래픽스 최적화 스타트업"을 참고하세요

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

텍스쳐의 Read/Write Enabled


텍스쳐의 임포트 셋팅 중 Read/Write Enabled 플래그도 메모리에 영향을 미칩니다. 이 플래그가 활성화되어 있다면 텍스쳐 데이터가 CPU 메모리에 상주하게 됩니다. 원래 텍스처 데이터는 GPU에서 사용할 수 있도록 GPU 메모리에 상주합니다. 하지만, 이 플래그가 활성화가 되면 추가적으로 CPU 메모리에도 상주하게 됨으로써 메모리 사용량이 두 배가 되는 것입니다.

이 플래그는 유저 스크립트에서 Texture.GetPixel 혹은 Texture.SetPixel 등의 코드를 통해 텍스쳐의 읽기 및 쓰기가 가능한지의 여부를 의미합니다. 만일 런타임이나 로딩타임동안 스크립트에서 텍스쳐의 데이터에 접근할 필요가 있다면 이 플래그가 활성화되어야 합니다.

하지만, 대부분의 경우에는 렌더링에 사용되는 텍스처가 스크립트에서 변경될 일이 없으므로 이 플래그를 비활성화 시켜야 메모리를 절약할 수 있습니다. 때문에, 기본적으로는 비활성화되어되어있습니다.


더 많은 내용은 "유니티 그래픽스 최적화 스타트업"을 참고하세요


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

유니티의 씬의 모든 Mixed 라이트는 Mixed Lighting Mode에 의존합니다. Lighting Mode 를 설정하려면, Window Rendering > Lighting SettingsEdit > Window > Lighting을 선택하여 라이팅 창을 열면 Mixed Lighting 섹션이 있습니다. Baked Global Illumination 플래그는 베이킹된 GI 즉 라이트맵 사용 여부를 의미합니다. 라이트맵을 사용하려면 이 플래그가 켜져있으면 됩니다.


Mixed Lighting 의 Lighting Mode는 씬의 라이트들 중 모드가 Mixed로 되어있는 라이트들에 의해서 영향을 받습니다. Baked Indirect, Subtractive, Shadowmask 중 하나를 선택할 수 있습니다. 이 모드에 따라서 라이트맵들은 큰 차이를 보입니다.

(이 글에서는 포워드 렌더링 패스를 기준으로 설명합니다.)


Baked Indirect


이 모드로 설정된 경우는 GI만 라이트맵에 기록되고 그림자는 기록되지 않습니다. 그림자는 베이킹이 되지 않고 런타임동안 실시간으로 연산됩니다. 즉, 그림자는 실시간으로 처리하고 GI만 미리 연산해놓고 싶은 경우 이 모드를 사용합니다. 그림자가 매우 중요하게 다뤄져야할 경우 유용합니다. 하지만 그만큼 그림자 처리 비용이 들어가는 것을 염두해두어야 합니다. 그림자 뿐만 아니라 직접광(Direct lighting)도 리얼타임으로 처리됩니다. 따라서 런타임상에서 라이트의 컬러와 강도(intensity)도 변경 가능합니다. 다음 이미지는 스태틱으로 처리된 건물의 그림자와 케릭터의 그림자가 실시간으로 처리되고 있는 모습을 보여주고 있습니다. 건물 옆의 바위는 실시간 라이팅이 적용되어 스페큘러 하이라이트가 반영되어 있습니다.

< Assets : Lighting Optimisation Tutorial, Survival Shooter Tutorial, by Unity Technologies>


씬 뷰에서 Baked Lightmap 모드로 선택하여 확인해보면 AO등의 GI는 반영이 되어있지만 디렉셔널 라이트의 그림자는 반영이 되어 있지 않습니다.



Subtractive


Subtractive는 정통적인 라이트맵이라고 볼 수 있습니다. 라이트맵에 GI와 직접조명, 그림자 까지 모두 라이트맵에 베이킹됩니다. 이 모드는 스태틱 오브젝트에 대한 라이팅 연산이 라이트맵에 새겨지므로 스태틱 오브젝트에는 실시간 라이팅이 이루어지지 않고 오로지 라이트맵에해서만 라이팅이 이루어지기 때문에 스페큘러가 반영되지 않습니다.

라이트맵에 그려진 라이트는 단순히 텍스처에 그려진 이미지와 다름 없기때문에 실시간 그림자와 자연스럽게 반응하거나 하지는 않습니다. 아래 이미지는 베이킹된 건물의 그림자 위에 케릭터의 실시간 그림자가 그려지는 모습을 보여주고 있습니다. 앞의 Baked Indirect에서 캐릭터와 건물의 그림자가 자연스럽게 연결되는 모습과는 대조되는 현상입니다.

그래서 Subtractive 모드에서는 실시간 그림자의 컬러를 조절할 수 있습니다. Realtime Shadow Color를 변경하여서 그림자 컬러를 조절해줄 수 있습니다. 씬의 전반적인 그림자의 컬러와 어울리는 컬러로 선택해서 그림자의 이질감을 줄여줄 수 있습니다.


씬 뷰에서 드로우 모드를 Baked Lightmap로 확인한 모습입니다. 오브젝트의 라이팅과 그림자, AO까지 모두 라이트맵에 처리가 되어 있습니다.

Subtractive 모드에서는 이처럼 스태틱 오브젝트들의 라이트는 라이트맵에서 다 처리하므로 런타임 동안의 라이팅 오버헤드가 극히 적습니다. 그렇기 때문에 저사양 모바일 디바이스에서 사용하기 적합한 모드입니다.




Shadowmask


Shadowmask모드는 라이트맵을 베이킹 시 그림자 영역을 별도의 텍스쳐로 따로 저장합니다. 이러한 그림자 영역을 따로 저장해놓은 텍스처를 쉐도우마스크라도 부릅니다. 얼핏 보기에는 Baked GI와 비슷하게 보일 수 있습니다. 하지만, 런타임동안 그림자 캐스팅 연산 자체를 수행하지는 않습니다. 대신 쉐도우 마스크로부터 그림자 여부를 판단해서 실시간 그림자와 자연스럽게 합성해줍니다. 따라서, Subtractive 모드와는 달리 스태틱 오브젝트와 다이나믹 오브젝트의 그림자가 자연스럽게 연결됩니다.

다음 이미지에서 건물 그림자와 캐릭터 그림자가 자연스럽게 어울리고 있습니다.



Shadowmask모드는 라이트맵이 적용되는 오브젝트에도 스페큘라 하이라이트가 적용됩니다. 건물 옆바위를 보면 스페큘라 하이라이트가 맺히고 있음을 확인할 수 있습니다. 앞선 Subtractive 모드일 경우와 비교해보면 차이가 명확하게 드러납니다. 이 스페큘라 하이라이트는 리얼타임으로 픽셀쉐이더에서 연산되기 때문에 그 만큼의 추가적인 GPU 성능이 소모됩니다. 이는 BakedGI모드에서도 마찬가지지만, BakedGI와 다른점은 그림자 캐스팅 연산에 대한 비용이 상대적으로 절약된다는 점입니다. 스태틱 오브젝트의 그림자 영역은 미리 쉐도우마스크로 저장되어 있기 때문에 런타임동안 쉐도우맵을 이용한 연산을 수행하지 않습니다. ( 주석 : Distance Shadowmask는 경우에 따라 달라집니다.)동적인 오브젝트에 대해서만 쉐도우맵 연산을 함으로써 그림자 연산에 대한 비용을 절약할 수 있습니다.


씬 뷰에서서 드로우 모드를 Shadowmask로 설정하면 쉐도우마스크가 적용되는 부분만 따로 확인할 수 있습니다.


이처럼, 그림자 연산에 대한 성능 비용이 대폭 감소하기때문에 모바일 디바이스에서 사용하기 적합합니다. Subtractive 모드에서의 시각적인 품질이 아쉽다면 Shadowmask도 고려해볼만 합니다. 다만 물론 Subtractive 모드보다는 성능 비용이 더 필요합니다.  


또한, 쉐도우마스크 텍스처가 추가적으로 만들어지기 때문에 텍스처 메모리가 추가적으로 필요합니다. 라이트캡 텍스처 생성 결과물은 라이팅 윈도우의  Global Maps 탭에서 확인할 수 있습니다. 아래 이미지는 위 씬을 디렉셔널 모드를 Directional로 설정하고 라이팅 모드를 Shadowmask로 라이트맵을 베이킹한 결과물들입니다.

첫번째 행에 보여지는 것들이 본래의 라이트맵입니다. 두번째 행에 보여지는 것들이 디렉셔널 모드로 인해 추가된 텍스쳐입니다. 세번째 행에 보여지는 것들이 쉐도우마스크입니다. 원래는 4장인 라이트맵이 디렉셔널 모드와 쉐도우마스크로 인해서 3배가 되었습니다. 하단에 총 용량이 190.7MB임을 나타내고 있습니다. PC나 콘솔에서는 문제가 되지 않는 크기이지만 모바일 디바이스에서는 메모리 문제를 일으킬 수가 있는 수치입니다. 따라서 모바일을 타겟으로 할 시에는 이러한 점들을 염두해두어야 합니다.


Shadowmask는 Distance Shadowmask 모드로 확장될 수 있습니다. Edit > Project Settings > Quality 를 선택하여 퀄리티 셋팅 창에서 선택할 수 있습니다. Shadows 섹션의 Shadowmask Mode를 Distance Shadmowmask로 설정하면 디스턴스 쉐도우마스크 모드가 활성화 됩니다.


이 모드를 활성화 시켜주면 스태틱 오브젝트도 거리에 따라 쉐도우맵을 적용합니다. 가까운 거리는 쉐도우맵으로 실시간으로 그림자를 처리하고 먼 거리는 쉐도우매스크로 그림자를 처리하는 것입니다.

가까운 거리에 있는 다이나믹 오브젝트에게 스태틱 오브젝트로부터 캐스팅되는 그림자를 고품질로 드리우고 싶을 때 이 모드를 사용할 수 있습니다. 다음 이미지는 Distance Shadowmask 모드에서 건물의 리얼타임 그림자가 캐릭터에게 맺히는 모습을 보여주고 있습니다.


Shadow Distance에 설정된 값 이상의 거리는 Shadowmask를 적용해서 처리합니다. 아래 두 이미지는 그러한 예를 보여주고 있습니다.

카메라가 건물과 멀리 떨어져 있을 시에는 쉐도우맵의 영향이 아닌 쉐도우마스크로 처리가 되어서 그림자가 만들어집니다. 그림자의 경계가 쉐도우마스크의 해상도로 인해 블럭화되는 것을 볼 수 있습니다. 또한, 케릭터는 Shadow Distance보다 멀리 있어서 그림자가 생략됩니다.

카메라가 가까이 가면 쉐도우맵을 이용하는 실시간 그림자로 바뀝니다. 건물 그림자의 경계 품질이 바뀐 것을 확인할 수 있습니다.

이처럼, 스태틱 오브젝트도 실시간 그림자를 캐스팅하게 두고싶다면 디스턴스 쉐도우마스크를 이용하면 성능을 절약할 수 있습니다.


더 많은 내용은 "유니티 그래픽스 최적화 스타트업"을 참고하세요

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

안드로이드 개발 환경 설정


-------- 주의 ---------

이 글의 내용은 더 이상 필요가 없는 설정입니다. 이제는 유니티 허브에서 모듈 추가 시 체크만 해주면 안드로이드 빌드 설정은 유니티가 알아서 해줍니다. 아래 3개의 체크 박스만 확인해주심 땡입니다요




유니티의 프로젝트를 안드로이드로 빌드하기 위해서는 우선 빌드 타겟을 안드로이드로 설정해줘야 합니다.


File > Build Settings 로 빌드셋팅창을 열고 Platform을 Android 로 선택 후 Switch Platform 버튼을 눌러서 빌드타겟을 안드로이드로 바꿉니다.


만일, 안드로이드 빌드용 모듈이 설치되어 있지 않다면 다음과 같이 No Android Module loaded 라는 메시지가 나옵니다. 메시지 바로 아래 있는 Open Download Page 버튼을 눌러 모듈을 다운로드받고 설치해줍니다. 모듈 설치시에는 유니티를 종료시켜줘야합니다. 설치 완료되고나면 유니티를 다시 켜고 프로젝트를 열어줍니다.


Switch Platform 버튼을 누르면 Asset Progress 프로그레스 팝업이 뜬 후 에셋들을 안드로이드 타겟으로 임포트 진행을 처리합니다.

완료되고나면 유니티 상단 타이틀바에 다음과같이 타겟이 안드로이드로 되어있음을 확인할 수 있습니다. ProfilerSampl1은 프로젝트명입니다. 각자 본인이 설정한 프로젝트명으로 표기됩니다.

빌드셋팅창에서 Player Settings 버튼을 누르면 Inspector창에 Player Settings가 뜹니다. Package Name을 변경해줍니다. Package Name은 Rendering 섹션의 하단에 있는 Identification 섹션에 있습니다. Package Name은 안드로이드 패키지의 이름이므로 원하는 이름으로 지으면 됩니다. 다만, com.제작자.프로젝트명 과 같은 형식으로 짓는 것이 일반적입니다.

이제 빌드를 하면 되는데, 유니티로 안드로이드 빌드를 해본 적이 없다면 빌드 전 안드로이드 개발 환경을 셋팅해줘야합니다. 우선, Preferences창을 엽니다. 윈도우즈는 File > Preferences, 맥은 Unity > Preferences. 윈도우 하단의 SDK와 JDK가 비어있는데, 여기에 경로 설정을 해줘야합니다.

우선, SDK는 Android SDK를 의미합니다. 안드로이드 개발을 위해서는 Android SDK가 필수적으로 설티되어 있어야합니다. SDK 항목 우측의 Download 버튼을 누르면 웹브라우저가 열리면서 다운로드 받을 수 있는 Android Studio 페이지로 이동합니다.

다운로드 버튼을 눌러 다운로드받고 설치를 합니다. 설치를 하고나서 Android Studio를 수행하면 다음과 같은 윈도우가 뜹니다. 여기서 Start a new Android Studio Project를 눌러서 새로운 프로젝트를 생성할 필요는 없습니다. 우리가 필요한 것은 단지 SDK가 설치된 위치만 알면 됩니다. 나머지는 유니티가 빌드할 때 알아서 해줍니다.

안드로이드 스튜디오의 새로운 프로젝트를 만드는 대신, 하단의 Configure 버튼을 눌러서 뜨는 리스트 중 SDK Manager 를 선택합니다.

그럼 SDK 매니저가 뜹니다. 이 중 상단의 Android SDK Location의 경로를 복사합니다.

다시 유니티의 Preferences 윈도우로 돌아가서 SDK 항목에 패스를 그대로 붙여넣으면 됩니다.


윈도우즈에서는 Android SDK 경로에 공백이 들어가 있으면 문제가 발생할 수 있습니다. 예를 들어서 사용자 이름에 공백이 들어가게 되면 전체 경로에 공백이 포함되어버리므로 문제가 발생할 여지가 있습니다. Android SDK Location 옆의 Edit 버튼을 눌러보면 다음과 같이 경고가 뜹니다.

이러한 경우에는 다른 경로에 공백이 없이 새로운 폴더를 만들어서 지정해주면 됩니다.


Android SDK를 완료했으면 이제 JDK를 설치해줘야합니다. JDK는 자바 SDK를 의미합니다. 안드로이는 JAVA를 기반으로 개발하게 되어있으므로 JDK가 설치되어 있어야합니다. 역시 JDK 옆의 Download 버튼을 누르면 웹페이지가 열리고 JDK를 다운로드 받을 수 있는 페이지로 이동합니다.

Download JDK 버튼을 눌르면 다음과 같은 선택 페이지로 들어갑니다.

Accept License Agreement를 체크하고, 본인의  PC에 맞는 OS용 설치 파일을 다운로드하여 설치합니다.


이제 유니티 Preferences 윈도우에서 JDK 경로를 입력해줘야합니다. 기본적으로 다음과 같은 폴더에 설치가 됩니다.

윈도우즈 : C:\Program Files\Java\jdk+버젼명

맥 : /Library/Java/JavaVirtualMachines/jdk+버젼명+.jdk/Contents/Home

탐색기나 파인더로 해당 폴더를 확인하신 다음에 JDK 항목에 패스를 기입해주면 됩니다.


SDK와 JDK 설정을 완료했으면 이제 빌드가 가능합니다. 하지만, 안드로이드도 IL2PP 백엔드로 빌드를 하려면  NDK도 추가로 설정을 해주어야 합니다. NDK는 Android Native Development Kit를 의미합니다. C와 C++ 같은 네이티브 코드 언어를 사용하여 앱의 일부를 구현하는 도구 모음입니다. IL2CPP 백엔드를 이용하면 최종적으로 유저 코드를 C++로 변경하기때문에 NDK가 필요합니다. NDK의 경우에는 Android Studio에서 설치가 가능합니다. 하지만 유니티에서는 특정 버전의 NDK를 요구하므로 Android Studio를 통해서 설치하면 버전이 맞지 않을 수도 있습니다. 따라서 SDK와 JDK와 마찬가지로 우측의 Download를 눌러서 다운로드 받습니다. NDK의 경우에는 인스톨 프로그램이 아니라 폴더 압축파일입니다. 윈도우즈의 경우에는 exe로 되어있어서 실행하면 바로 압축이 풀립니다. 맥에서는 bin파일로 되어있어서 터미널에서 커맨드라인으로 압축을 풀어줘야합니다. 우선 터미널을 열고 다운로드 받은 폴더로 이동합니다. 그 후 다음과같이 실행 권한을 추가해주고 압축을 풀어줍니다.

스크린샷 2017-05-19 오전 2.00.13.png

압축 푼 폴더를 적당한 위치로 옮겨주고 해당 경로를 Preference에 입력해줍니다.

스크린샷 2017-05-19 오전 2.11.02.png


Android SDK, JDK, NDK 모두 설치가 되었으면 이제 디바이스에 띄워볼 차례입니다. 우선, 안드로이드폰과 작업 PC를 USB로 연결해줍니다. Build Settings 윈도우로 돌아가서 Build And Run 버튼을 누르면, 빌드할 apk파일명을 물어봅니다. 원하는 이름으로 입력해주면 빌드가 진행됩니다.


만일, SDK 패스등이 제대로 설정되어 있지 않다면 빌드 시 다음과같은 실패 메시지가 뜹니다.

SDK 패스 설정이 잘 되어있음에도 불구하고 위와 같은 실패 메시지가 뜬다면, 유니티를 껏다 켜보고 OS 재부팅도 해보세요 :)


만일, 안드로이드 디바이스가 디버깅 환경 설정이 되어있지 않다면 다음과 같은 팝업창이 뜹니다.

안드로이드 디바이스는 기기를 개발용 디버깅이 가능한 개발자 모드로 설정을 해줘야 프로젝트를 빌드하여 띄울 수 있습니다. 개발자 모드 설정은 안드로이드OS 버전이나 기기마다 방법이 조금씩 상이합니다. 구글에서 본인의 테스트 기기에 대한 개발자 모드 방법을 검색하면 쉽게 방법을 찾을 수 있습니다.

개발자 옵션을 활성화시키고나면 개발자 옵션에 들어가서 USB 디버깅을 활성화시켜주면 됩니다.

또한, Windows OS의 경우에는 디바이스의 드라이버를 설치해줘야 합니다. 디바이스 벤더 사이트에서 해당 디바이스에대한 드라이버를 다운로드 받을 수 있습니다.

이제 다시 Build Settings 창에서 Build And Run 버튼을 누르면 빌드가 진행되고 빌드가 완료되면 디바이스에 apk가 자동으로 설치되고 게임이 수행됩니다. 디바이스에 맨 처음 연결하는 것이라면 디바이스에서 디버깅 연결할 지 여부를 묻는 창이 뜰 수도 있습니다. 이러한 경우에는 승인 전 까지는 PC에서 디바이스 연결이 실패하기때문에 승인 후 다시 빌드해줘야 할 수도 있습니다.


만일 타겟팅하고 있는 Android API Level(Edit>Project Settings>Player>Other Settings>Identification)이 설치가 되어있지 않은 경우에는 빌드시 Target SDK가 설치되어 있지 않다는 메시지가 뜰 수도 있습니다.


이러한 경우에는 Android Studio의 SDK Manager를 열어서 SDK Platforms 탭에서 해당 SDK를 체크해주고 Apply를 누르면 해상 SDK를 설치합니다.



더 많은 내용은 "유니티 그래픽스 최적화 스타트업"을 참고하세요


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

문서들을 여기 저기 따로 공유하려느 번거로워서 유니티 최적화 관련 문서들을 모아두었습니다. 정리는 두서 없이 했고,다만 출처가 유니티 크루인지 아닌지로만 분류하였습니다. 추가적으로 발견하는 대로 지속적으로 갱신 할 예정입니다.

Update : 2018-07-10


From Unity


from Developers




Posted by ozlael
,

Unity OVR Input

Unity3D/Others 2017. 9. 30. 15:34
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

VR컨텐츠를 만들 때 일반적으로는 양대 HMD( 오큘러스, 바이브)를 모두 지원해야합니다. HMD 디바이스만 지원하는 것은 매우 쉽습니다. HDM의 트래킹을 지원하기 위해서 별도의 SDK나 에셋을 필요호 하지 않고 유니티의 기본 기능으로 충분하기 때문입니다. 하지만 문제는 컨트롤러의 트래킹과 입력을 지원하는 경우에 발생합니다. 오큘러스와 바이브 컨트롤러를 지원하기위해서는 각각의 SDK를 임포트해서 사용해야합니다. 예를 들어서, 오큘러스 터치를 지원하기 위해서는 오큘러스 디벨로퍼 센터에서 오큘러스 유틸리티를 받아서 임포트해야 합니다. 또한, 바이브 컨트롤러를 지원하기 위해서는 스팀VR  플러그인은 에셋스토어로부터 받아서 임포트해야합니다. 결과적으로는 컨트롤러 관련하여 각각 다른 코드와 프리팹들을 관히애하 합니다. 이는 프로젝트를 개발하고 유지보수하는데 있어서 매우 번거로운 상황입니다. 하지만, 만일 컨트롤러 시스템이 간단한 컨텐츠를 만든다면, 더 이상 이럴 필요가 없습니다. 유니티는 VR 트래킹 API를 제공하고있고, 이를 이용해서 컨트롤러의 위치를 트래킹 할 수 있습니다. 컨트롤러를 트래킹하기 위해서 추가적인 SDK를 유니티 외부로부터 임토프하지 않아도 됩니다. 유니티에서 제공하는 API만으로도 구현이 가능합니다. 버튼 및 트리거 입력은 유니티의 기본적인 인풋 시스템을 이용하면 됩니다.

If you want to make VR content, you have to support all of major HMDs.(Oculus and Vive at this moment :p) You may know supporting HMD devices only is very easy. You don't need any additional SDK or assets to track and support HMD deivces. Problem is supporting and tracking controllers. If you want to support both Oculus Touch and Vive Controller , you may import both SDKs. For Oculus Touch, You have to import Oculus Utilities for Unity rom Oculus Developer Center. And for Vive Controller, you have to import SteamVR Plugin from Unity Store. As a result, you have to use different prefabs and different codes to support both different controller systems. It is very annoying stuff for maintaining. Actually, you don't have to do it anymore, if your controll input system is simple. Unity provide VR tracking APIs to track posion of controllers. To track controllers, you don't have to import additional SDKs from out of Unity. You can do it as using API built inside unity. Plus, You can get input of triggers and buttons from controllers using basing Input system of Unity.


VRControllerTracking.cs :

transform.localPosition = InputTracking.GetLocalPosition (whichNode);

transform.localRotation = InputTracking.GetLocalRotation (whichNode);


컨트롤러 인풋을 얻어오기 위해서는 유니티 공식 매뉴얼을 참고하면 됩니다 : Input table for OVR controllers, Input API, Input Manager. 이는 일반적인 게임 컨트롤러와 동일합니다. 인풋 매핑 테이블을 참고하면 됩니다. 예를 들어서,  LeftHandTrigger를 얻어오고 싶으면, 조이스틱 버튼 14에 해당합니다.

To get input of controllers, You may refer official manual : Input table for OVR controllers, Input API, Input Manager. It is the same with general game controllers. Look at the input mapping table. For example, if you want to get LeftHandTrigger, it will say Joystick Button 14 in there.


LaserSwordControl.cs :

if (blade && Input.GetAxisRaw (inputNameToActiveBlade) > 0.1f) {


자세한 코드와 내용은 샘플 프로젝트 코드를 참고하세요 : https://github.com/ozlael/UnityDemo_InputForOVR

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


게임을 개발함에 있어서 가장 중요한 것은 물론 재미입니다. 게임은 재미를 주는 것이 주 목적이니 당연한 이야기겠죠. 하지만, 게임을 아무리 재밌게 만들었다 하더라도 게임이 실행이 되야 재미를 느낄 수 있겠죠. 게임을 플레이하다가 게임이 자꾸 강제 종료되버린다면 말짱 도루묵이 되겠죠.

그렇기 때문에 게임 개발에 있어서 메모리 이슈도 중요합니다. 특히 모바일 환경에서는 더 심하죠. PC에서는 실제 물리적인 램이 부족하더라도, 디스크의 공간을 활용하여 모자란 메모리를 보조하는 시스템이 존재합니다. 때문에, 현대의 PC에서는 게임이 버벅일지언정 메모리 부족으로 게임이 강제종료되는 상황까지 가는 것이 흔치는 않습니다. 하지만, 스마트폰에는 그러한 기능이 존재하지 않습니다. 그말인 즉슨, 실제의 물리적인 메모리 공간을 넘어서 사용이 불가능하다는 것을 의미합니다. 그렇기때문에, 스마트폰 게임이 메모리를 많이 사용한다는 것은 게임이 뜻하지 않게 강제종료될 가능성이 그만큼 많아진다는 것을 의미합니다.  

스마트폰 게임을 개발할 때에는 항상 메모리에대해서 신경쓰면서 개발을 해야합니다. 하지만 메모리를 줄여야 하는 것은 알겠는데, 무엇을 어떻게 줄여야 할지 막막한 채로 작업을 할 수는 없겠죠. 그렇기 때문에  메모리도 프로파일링이 필요합니다.


유니티 5.3부터는 메모리 프로파일러라는 확장 툴을 이용하여 메모리를 확인할 수 있습니다. 이 툴을 이용하면 어떤 메모리가 얼만큼의 힙 메모리를 사용하고 있는 지를 직관적으로 쉽게 확인 할 수 있습니다.

다운로드 : https://bitbucket.org/Unity-Technologies/memoryprofiler/downloads/

아쉽게도 아직 유니티 기본 내장 툴은 아니고, 에디터 확장 기능으로 따로 다운로드받아서 사용해야합니다. 유니티도 오픈소스 형태로 개발하는 기능들이 많이 있는데요, 빗버킷에 올려두고 개발을 진행합니다. GUI 시스템도 마찬가지고 Post Processing Stack, Asset Bundle Manager 등등 많은 프로젝트들이 오픈소스 형태로 진행중입니다. 메모리 프로파일러 역시 이 중 하나라고 보시면 됩니다. 

유니티 5.3 이상부터 적용이 가능합니다. 다운로드 받은 프로젝트의 에디터 폴더를 현재 현재 개발중인 프로젝트의 에디터 폴더로 임포트 하면 됩니다. 스크립트 백엔드는 IL2CPP로 적용해줘야합니다. 안드로이드 역시 IL2CPP가 정식 지원되고 있기 때문에 안드로이드도 사용이 가능합니다. 다만 주의할 점은 5.3에서는 안드로이드 IL2CPP가 정식 지원이 아니라는 점입니다. 결론적으로는 메모리 프로파일러를 이용하려면 5.3을 이용중인 프로젝트라면 5.4 이상으로 업데이트를 해야한다는 의미가 됩니다.

메모리 프로파일러는 내부적으로 Profiler API를 이용합니다. 그렇기 때문에, Development Build로 빌드하여야 합니다. 게임을 띄우고나면 유니티 프로파일러를 띄우고 디바이스에 프로파일러를 연결하여 프로파일링이 되는 것을 확인합니다, 그 뒤에 유니티에서 Windows>Memory Profiler를 선택합니다.

그럼 이렇게 생긴 메모리프로파일러 윈도우가 뜹니다. 이 화면에서 Take Snapshot 버튼을 누르면 됩니다. 디바이스에서 데이터 긁어오다보니까 폰이 잠깐 멈췄다가 가져온 데이터를 분석하느라 에디터가 잠깐 멈출겁니다. 데이터가 많으면 좀 시간이 걸릴 수도 있기 때문에 인내심이 좀 필요할수도 있습니다.

데이터 분석이 다 끝나면 메모리 사용량을 종류별로 시각화 보여줍니다. 종류별로 메모리를 얼마만큼 차지하는지를 사각형의 크기로 보여줍니다. 사각형 크기 비율이 실제의 메모리 사용량의 비율을 나타냅니다. 즉, 사각형의 크기가 큰 것 을 우선순위로 줄여나가면 되는 것입니다.

항목을 클릭하면 개별 리소스나 오브젝트들의 메모리 차지 면적을 볼 수 있습니다. 우측에는 선택한 오브젝트의 이름 및 인스턴스 아이디 등등의 자세한 내용을 확인할 수 있습니다. 크기가 작아서 보기 힘든 항목들은 마우스 휠을 굴려서 줌인 줌아웃이 가능합니다. 솔직히 인터페이스가 이쁜 편은 아닙니다. 좀 투박한 느낌은 있지만 시각적으로 확인하고 분석하는 기능은 충분합니다.


실제의 예를 하나 들어보겠습니다. 에셋스토어에서 게임을 하나 받아서 갤럭시S2에서 수행한 모습입니다. 2D게임이라 갤럭시 2S에서도 동작하는데 무리가 없습니다.

근데, 문제가 없어보인 것이지 실제로는 문제가 있는 상황입니다. 프로파일링해보기 전에는 문제가 없다고 단정하면 안됩니다. 실제로 메모리 프로파일러로 확인해보니 텍스쳐 메모리 사용량이 엄청납니다. 어떤 텍스쳐는 16MB나 차지하고 있습니다. 

확인해보니 사이즈가 2048이기는 하지만 ETC2 압축을 설정해놓았으니 16MB는 말이 안되는 것 같아보입니다.

사실, 이건 갤럭시2S가 OpenGL ES 2.0만 지원해서 발생하는 현상입니다. 갤럭시 S2는 오래된 모델이라 OpenGL ES 3.0을 지원하지 못하고 OpenGL ES 2.0만 지원합니다. 문제는 ETC2는 OpenGL ES 3.0부터 지원된다는 것입니다. 즉 OpenGL ES2.0에서는 ETC2를 사용하지 못한다는 것입니다. 그래서 OpenGL ES 2.0에서는 ETC2 텍스쳐를 읽어들일 때 ETC2를 압축을 풀어서 메모리에 올라갑니다. 그래서 2048 * 2048 * 4바이트 = 16MB가 되서 메모리에 올라간 것입니다. 

똑같은 텍스쳐를 OpenGL ES 3.0 지원되는 기기에서 확인해보면  텍스쳐 압축이 잘 되서 4MB로 올라갑니다. 그래서 알파가 있는 텍스쳐를 컴프레스트로 두면 OpenGL ES 2.0까지만 지원하는 갤럭시S2랑 OpenGL ES 3.0을 지원하는 갤럭시 S4에서의 실제 텍스쳐 메모리 사용량이 많이 차이가 날 겁니다. (갤럭시 S3로 비교하지 않은 이유는, 갤럭시 S3 중에서도 세부 기종에따라 지원하는 버전이 다르기 때문입니다)


메모리 프로파일러를 이용하면 이런식으로 어떤 리소스가 얼만큼을 차지하고 있는 지를 쉽게 분석할 수 있습니다. 메모리를 프로파일링하기 위해서는 필수적인 툴일 것입니다.

이 툴에 대하여 건의 사항이나 버그가 있다면 아래 주소로 이슈를 만들어주시면 됩니다. 만약 영어가 불편하면 저한테 말씀해주세요.

링크 : https://bitbucket.org/Unity-Technologies/memoryprofiler/issues?status=new&status=open

 제가 사실 블로그 댓글은 잘 확인하지를 않아서 페이스북이나 트위터로 연락 주세요 :)

페이스북 : ozlael.oz

트위터 : @ozlael

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

이 글은 유니티 자습서Best Practices 문서 중 Resources Folder를 번역/의역한 것입니다.


Resources 폴더

이 글은 “유니티5의 에셋과 리소스 관리” 시리즈의 3번째 글입니다.


이 챕터는 Resources 시스템에 대하여 다룹니다. 이 시스템은 개발자가 여러 에셋들을 Resources 폴더에 두고 런타임동안 Resources API를 통해서 에셋을 로드/언로드할 수 있도록 해줍니다.


2.1 Resources 시스템을 위한 실용 가이드


사용하지 마세요.


다음과 같은 이유들로 사용하지 않기를 강력하게 권고합니다

  • Resources 폴더를 사용하는 것은 메모리 관리를 더욱 복잡하게 만듭니다.

  • Resources 폴더를 부적절하게 사용하면 어플리케이션 시작 시간과 빌드 시간을 늘리게 됩니다.

  • Resources 폴더들이 많아지면 그 안에 있는 에셋들의 관리가 힘듭니다.

  • Resources 시스템은 사용자 정의 컨텐츠를 특정 플랫폼으로 옮기는 것이 까다로워집니다. 컨텐츠를 업그레이드하는 경우도 마찬가지입니다.

  • 디바이스에 맞는 컨텐츠를을 조정하는데 적합한 주요 기능은 에셋번들입니다.


2.2 Resources 시스템의 적절한 사용

다음과 같은 두 가지의 경우에는 개발 시 Resources 시스템을 사용하기에 적합한 경우입니다.

  1. 빠른 프로토타이핑이나 검증이 필요한 경우에는 Resources를 사용하기에 좋습니다. 간단하고 사용하기 쉽기 때문입니다. 하지만, 프로젝트가 프로덕션 단계에 가게 되면 Resources 폴더 사용을 중단해야 합니다.

  2. Resources 폴더는 다음 모든 경우를 만족하는 상황에서는 유용한 시스템입니다.

    • Resources 폴더에 들어있는 컨텐츠들은 메모리에 민감한 것 들이 아닐 경우

    • 컨텐츠가 어플리케이션의 수행 시간 동안 계속 필요한 경우

    • 컨텐츠가 패치될 일이 거의 없는 경우

    • 컨텐츠가 플랫폼이나 디바이스별로 달라지지 않는 경우

이 중 두 번째 케이스에 해당하는 예시는 전역으로 사용되는 싱클턴 모노비헤이비어나 페이스북 앱 ID등의 서드파티 데이터를 다루는 에셋등이 될 것입니다.


2.3 Resources의 시리얼라이제이션

프로젝트 빌드 시 “Resources” 폴더 내 모든 에셋과 오브젝트들은 하나의 시리얼라이즈된 파일에 정보가 담깁니다. 이 파일은 에셋번들처럼 메타데이터와 인덱싱 정보를 포함합니다. “에셋번들 의 근본”챕터의 “에셋번들이란 무엇인가?” 섹션에서 설명된 바와 같이, 이 인덱싱 정보는 시리얼라이즈된 룩업  트리를 포함합니다. 여기에는 주어진 오브젝트 이름을 파일 GUID와 로컬 ID와 매칭시키는데 쓰이는 정보들을 포함합니다. 오브젝트를 시리얼라이즈된 파일의 몇 바이트째 위치시키느냐등의 정보도 포함합니다.


룩업 데이터 구조가 균형잡힌 탐색 트리라서 구축 시간 비용은 O(N log(N)) 비율로 증가합니다.(대부분의 플랫폼에서는 C++ Standard Template Library의 std::multimap를 사용합니다.) 여기서 N은 트리에 들어가는 오브젝트 갯수를 의미합니다. 이러한 증가치는 인덱스의 로딩 타임에 많은 비용이 들게합니다. 따라서 Resources 폴더 안의 오브젝트들이 많을수록 성능에 좋지 않습니다.   


이 동작은 건너뛸 수 없기때문에 어플리케이션의 초기 시작 시간을 늘리게 되서 인터렉션이 불가능한 스플레시 화면이 떠 있는 시간이 길어지는 요인이 됩니다. 특히 저사양 기기일 수록 Resources 시스템에 많은 오젝트가 포함되있으면 어플리케이션 시작 시간이 매우 길어지게 됩니다. 특히, Resources 폴더의 대부분의 오브젝트들이 첫 씬에서 보여질 필요가 없는 경우에는 효율적이지 못한 상황이 되는 것입니다.




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

게임을 개발하는 과정에서 콘솔 로그를 출력하는 것은 필수적입니다. 당연히 유니티에서도 로그를 출력하는 함수가 존재하고 Debug.Log()를 많이 사용하시죠.

Manual : https://docs.unity3d.com/ScriptReference/Debug.Log.html 


근데 많이들 오해하시는게, 이 Debug.Log 함수는 Debug클래수 함수니까 Development Build일 때에만 작동하고 릴리즈 빌드때는 자동적으로 제거된 다고 오인하시는 것입니다. 콘솔 출력용으로 남발해서 사용되도 최종 릴리즈에는 영향 미치지 않는다고 오인하시는 경우가 많습니다, 하지만 아쉽게도 그렇지 않습니다. Debug.Log()는 릴리즈 빌드때고 고스란히 작동합니다. 따라서 쓸데 없는 성능을 쉽게 잡아먹는 녀석중 하나가 되버리죠.


예를 들어서 다음과 같이 콘솔 출력용 로그를 수없이 찍는 코드를 만들고

public class TestLog : MonoBehaviour {


public int logCount = 500;

public string testStr;

void Update () {

for( int i=0; i< logCount; i++) {

UnityEngine.Debug.Log("test log : " + testStr + "!" );

}

}

}

빈 프로젝트에서 위 코드만 돌린 프로젝트를빌드하여 홍미 폰에 띄우니 30FPS로 돌아갑니다. 디벨롭먼트 빌드가 아닌데도 불구하구요. 물론 실제로 매 프레임마다 500번의 출력을 하는 경우는 실존하지 않을 것입니다. 테스트를 보여주기 위하여 극악의 상황을 만들어본 것 뿐입니다. 다만, Debug.Log()가 쓸데 없이 작동하는 것을 증명하기에 충분한 코드겠지요. 


이러한 쓸데없는 행위를 막기 위해서 #if 디파인문을 많이들 사용하십니다. 다음과 같이요

#if TRACE_ON

UnityEngine.Debug.Log("test log : " + testStr + "!" );

#endif

이렇게 두고 플레이어 셋팅의 Scripting Define Symbols이나 .rsp 파일에 TRACE_ON을 추가하한 경우에만 수행되고 아닌 경우에서는 Debug.Log()가 수행되지 않고 60FPS가 잘 나옵니다.

Manual : https://docs.unity3d.com/Manual/PlatformDependentCompilation.html

이제 문제가 전혀 없습니다. 없을까요? 

있습니다. 귀찮은게 문제지요.


Debug.Log()를 출력하는 곳이 한두군데도 아니고 매번 작성할 때 마다 #if #endif로 묶으려면 매우 귀찮습니다. 게다가 실수로 잘못 묶으면 짜증이 짜증이 아휴~



대안으로는 Conditional를 사용하시면 편합니다. Debug.log()를 래핑하는 클래스를 만들고 함수에다가 Conditional를 선언하면 됩니다.

using UnityEngine;

using System.Collections;

using System.Diagnostics;


public class TestLog : MonoBehaviour {


public int logCount=500;

public string testStr;


[Conditional("TRACE_ON")]

void DebugLogWrap( string str) {

UnityEngine.Debug.Log(str);

}

void Update () {

for( int i=0; i< logCount; i++) {

DebugLogWrap("test log : " + testStr + "!" );

}

}

}

TRACE_ON 디파인이 켜져있지 않는 경우에는 DebugWrap을 호출하는 라인이 통채로 무시됩니다. 따라서 #if 디파인을 매번 사용하지 않고도 같은 효과를 볼 수 있습니다. 사실 저도 얼마 전에 알게 된 것인데 굉장히 편하네요 ㅋ C# 짱짱맨 :)

MSDN : https://msdn.microsoft.com/en-us/library/4xssyw96(v=vs.90).aspx


궁극적으로는 다음 링크처럼 사용하시면 됩니다 : 

https://gist.github.com/kimsama/4123043


끗!


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

많은분들이 물어보시는 내용 중 하나가 텍스쳐입니다. 그 중 밉맵과 필터링에 대한 내용을 정리해보고자합니다.



밉맵


텍스쳐에서 밉맵이란 텍스쳐에게 있어서 LOD같은 개념입니다. 만일 256x256짜리 텍스쳐가 화면에 그려진다고 생각을 해보죠. 이 텍스쳐가 화면에 굉장히 작은 영역으로 그려져서 실제로는 32x32픽셀만큼의 영역만 그려지는 상황이라면 굳이 256텍스쳐를 바를 필요가 없습니다. 괜히 대역폭을 낭비할 필요 없이 32텍스쳐를 가져가면 충분한 상황일 것입니다.

이런 컨셉이 바로 텍스쳐 밉맵입니다. 텍스쳐 하나 만들면 내부적으로는 여러 크기 단계의 텍스쳐를 만들어 두는 것입니다. 예를 들어서 256텍스쳐를 사용하면 내부적으로는 256,128,64,32,16,8,4,2크기의 텍스쳐를 추가적으로 생성하게 되는 것입니다. 그러고서는 런타임에서 렌더링 시 픽셀쉐이더에서 텍스쳐를 읽어들일 때 상황에 맞는 크기의 텍스쳐를 가져감으로써 실시간 대역폭을 절약하는 것입니다.

이미지 출처 : http://www.tomshardware.com/reviews/ati,819-2.html


이런식으로 하면 런타임 성능은 절약되지만 메모리는 약 30%가 늘어나게 됩니다.(정확한 수치는 아니고 통상적인 수치입니다) 따라서 메모리가 걱정된다면 밉맵을 끌 수도 있습니다. 유니티에서는 기본적으로 텍스쳐가 밉맵을 사용하도록 설정됩니다. 밉맵을 끄려면 텍스쳐별로 밉맵을 사용 안하도록 설정해줘야합니다. 텍스쳐 타입을 Advanced로 두고 Generate Mip Maps를 해제하면 됩니다. 


하지만 3D 게임에서는 특수한 상황이 아니고서는 밉맵을 끄는 것을 권장하지는 않습니다. 성능 문제도 있거니와 지글거림이 발생하여서 시각적인 문제도 발생합니다. ( 반대로 2D 게임에서는 뭉개져보이는 시각적인 문제로 밉맵을 꺼주는 것이 좋을 수도 있습니다.)

이미지 출처 : http://www.tomshardware.com/reviews/ati,819-2.html



필터링


밉맵을 이야기하면 필터링도 함께 이야기 하게될 수 밖에 없습니다. 텍스쳐 필터링은 텍스쳐 설정의 filter mode에서 변경할 수 있습니다.

  • 포인트(Point) : 필터링을 하지 않습니다. 따라서 픽셀이 블럭으로 깨져보이게 됩니다.

  • 바이리니어(Bilinear) : 텍스쳐가 필터링 됩니다. 확대필터와 축소필터 모두 적용 됩니다. 즉 원래 텍스쳐보다 확대되서 그려지든 작게 그려지든 필터링이 되는 것입니다. 

  • 트라이리니어(Trilinear) : 바이리니어가 기본적으로 작동하고, 추가적으로 밉맵 레벨이 바뀌는 구간도 필터링이 됩니다.

바이리니어와 트라이니리어간의 차이점은 밉맵 레벨이 바뀌는 구간이 필터링 되냐 아니냐의 차이입니다. 트라이리니어로 설정하면 밉맵 레벨이 바뀌는 구간도 부드러워집니다. 따라서, 바닥같은데서 시각적으로 자연스러운 렌더링이 되려면 트라이리니어를 사용해야합니다.

이미지 출처 : http://www.tomshardware.com/reviews/ati,819-4.html

또한, Anisotropic filtering을 적용하면 더욱 좋은 품질을 얻을 수 있습니다. Anisotropic은 면의 기울기를 필터링에 반영하기때문에 바닥이나 벽 등에 사용하면 좋습니다. 텍스쳐 인트펙터에서 Aniso Level을 2 이상으로 설정하면 필터링이 적용됩니다. 숫자가 높을수록 필터링이 강하게 작용하고 성능도 그만큼 필요로하게됩니다.

이미지 출처 : http://www.gamespot.com/forums/system-wars-314159282/df-issue-with-blurry-console-texture-filtering-32700608/


다만 이들은 디바이스마다 지원 여부가 다릅니다. 특히, anisotropic 필터링은 많은 기기들에서 사용이 불가능합니다. 유니티를 실행 시 로그캣으로 확인해보면 다음과 같이 기기에서 지원하는 GL 익스텐션 목록들이 출력됩니다.

ex > GL_EXT_debug_marker GL_ARM_rgba8 GL_ARM_mali_shader_binary GL_OES_depth24 GL_OES_depth_texture GL_OES_depth_texture_cube_map GL_OES_packed_depth_stencil GL_OES_rgb8_rgba8 GL_EXT_read_format_bgra GL_OES_compressed_paletted_texture GL_OES_compressed_ETC1_RGB8_texture ...

이 목록 중 "GL_EXT_texture_filter_anisotropic" 항목이 없으면 해당 기기에서 anisotropic 필터링을 지원하지 않는 것입니다.

다만, 텍스쳐 임포트 셋팅에서 aniso level을 설정해놓아도 기기에서 지원하지 않으면 작동하지 않으므로 비정상 작동하거나 하지는 않습니다. 설정을 굳이 1로 돌려놓지 않으셔도 무방합니다. 트라이리니어 역시 마찬가지로 기기에서 지원하지 않는다면 바이리니어로 작동하므로 트라이리니어로 두셔도 비정상 작동하거나 하지는 않습니다.


밉맵 바이어스


낮은 밉맵 단계가 흐려보이는 것이 거슬린다면 낮은 밉맵 단계가 적용되는 기준을 조절해줄 수도 있습니다. 물론 성능 문제상 추천되는 방법은 아닙니다만 밉맵 바이어스를 건드리면 밉맵 레벨이 바뀌는 기준을 바꿔주실 수도 있습니다. 다만, OpenGLES에서는 작동하지 않습니다.

http://docs.unity3d.com/ScriptReference/Texture-mipMapBias.html

따라서 이 기능과 같은 결과를 만들어내시려면 쉐이더에서 건드려주시면 됩니다. tex2D함수 대신 tex2Dbias를 사용하시면 됩니다. 자세한 내용은 대마왕님의 블로그를 참고하세요 :

http://chulin28ho.tistory.com/258

다만 이 역시 기기에서 지원을 해줘야합니다. GL익스텐션 목록에 EXT_shader_texture_lod가 있다면 지원 되는 것입니다.




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

유니티의 UI 관련하여 빈번하게 문의들어오는 것 중 하나가 UI와 3D 오브젝트들의 위치 관계에 관한 것입니다. 

일반적인 UI는 게임 씬 위에 덧그려지는 방식으로 만들어집니다. 기본적으로 유니티에서 UI 컴포넌트를 생성하면 3D 오브젝트들을 렌더링 후 UI를 렌더링 하게 됩니다. 기본적으로 이러한 방식으로 UI가 화면에 덧그려지게 되지요.

하지만 인게임 말고 로비나 생성창 등에서 UI 위에 파티클을 그린다거나 UI와 UI 사이에 케릭터를 그리는 등의 상황도 필요합니다. 이러한 구성은 어떻게 하는지 문의가 자주 들어오곤 합니다. 

구성 방법이야 여러가지가 있을 수 있겠지만, 우선은 캔버스의 렌더 모드를 스크린스페이스-카메라로 사용해주면 됩니다. 기본으로 캔버스를 생성하면 렌더 모드가 스크린스페이스-오버레이인데, 이는 씬 렌더 후 화면에 덮어서 그리는 UI를 의미합니다. 스크린스페이스-카메라는 캔버스의 깊이를 설정할 수 있어서 3D 오브젝트와의 깊이 관계를 설정할 수가 있습니다. 따라서, 위 화면과 같이 케릭터 배경 창이 있고 케릭터 위에 버튼을 그리고자 하는 경우라면, 깊이가 다른 각각의 두 캔버스를 스크린스페이스-카메라 렌더모드로 만들고, 각각의 캔버스의 평면 거리(plane distance)를 적절한 깊이로 설정한 다음, 사이에 3d 오브젝트를 배치하면 다중 UI 깊이에 대해서 렌더링을 할 수 있습니다.

샘플 프로젝트를 올려두었으니 이를 참고해보시면 도움 되실 것이라 생각합니다 : https://drive.google.com/a/unity3d.com/file/d/0B70AOyGiQJsGT3dDRW9uUldOeTg/view?usp=sharing



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

제 개인적인 생각으로는 물리기반렌더링(Physically Based Rendering/Shading, 이하 PBR,PBS)이 2016년 국내 게임 시장의 중요 키워드 중 하나가 아닐까 생각합니다.  모바일 기기의 성능들이 많이 발전하고 특히 국내에는 고사양 폰의 보급률이 높아짐에 따라 모바일에서도 PBR을 사용하는 움직임들이 많이 보이고 있습니다. 유니티에서는 스탠다드(Standard) 쉐이더를 통해서 PBR을 처리해주고 있습니다. 이 스탠다드 쉐이더는 유니티5에 적용된 인라이튼(Enlighten)과 연동하여 실시간 GI(Global Illumination) 및 물리 기반 라이팅을 표현해줌으로써 더욱 사실적이고 멋진 그래픽을 표현할 수 있도록 해줍니다. 

하지만 PBS는 복잡한 연산을 거쳐서 빛을 표현해주어야 하다보니 성능을 크게 잡아먹습니다. 물론 게임에서는 이를 나름 간략화 시켜서 사용하고, 유니티 역시 스탠다드 쉐이더에 이를 최적화하여 적용합니다. 또한, PC에서 수행하면 PC용 모드의 스탠다드 쉐이더로 수행되고 모바일 기기에서 수행하면 모바일용으로 더 최적화된 모드의 스탠다드 쉐이더로 수행됩니다. 이 역시 버전을 거듭할 수록 계속 최적화가 진행중입니다. 하지만, 기본적으로 연산 자체가 복잡하기 때문에 씬 전체를 스탠다드 쉐이더로 사용하는 것은 아이폰5, 아이패드에어, 넥서스9 급 이상의 하이엔드 기기를 타겟으로 사용하는 경우에만 권장합니다.

고사양 기기가 많이 보급되어 있긴 하지만 아직도 저사양 폰들이 시장에 많이 존재합니다. 이러한 기기들에서는 씬 전체를 스탠다드 쉐이더로 그리는 것은 무리입니다. 하지만, 스탠다드 쉐이더를 부분적으로만 사용한다면 충분히 보급형 기기에서도 이를 활용 할 수도 있습니다. 예를 들어, 케릭터에게만 스탠다드 쉐이더를 사용하고 배경에는 다른 가벼운 쉐이더를 사용하는 것입니다. 다음 이미지에서는 그러한 예시를 보여주고 있습니다. 로보트들과 드론들에게는 스탠다드 쉐이더를 사용하였고 배경에는 Mobile/Unlit (Supports Lightmap) 쉐이더를 사용하였습니다. 갤럭시 S3에서 60 이상의 FPS로 렌더링 되고 있습니다. 데모를 구글플레이에 올려두었습니다. 다운로드 받아서 확인 가능하십니다. 

링크 : https://play.google.com/store/apps/details?id=com.ozproject.demo2

사용 에셋 : Armored Golem, Sci-fi Flying Droid, Mech Robot Sci-fi, Orbital Reentry Craft - No Interior ( 제가 아트감각이라고는 빵점인 공돌이라 비쥬얼 퀄리티가 좋지 못한 점 너른 양해 부탁드립니다;; )

또한, 저사양 기기에서 스탠다드 쉐이더를 사용하기 위해서는 텍스쳐 슬롯을 가능한 아껴주는 것이 좋습니다. 사용되지 않는 텍스쳐 슬롯은 스탠다스 쉐이더가 알아서 연산을 건너뜀으로써 성능을 절약하 수 있습니다.

예를 들어 다음 우주선은 Emission 맵을 사용하지 않았습니다.

드론에게는 노말맵을 사용하지 않았습니다.

골렘 로보트에게는 Metallic맵을 사용하지 않고 수치로써 단순하게 적용하였습니다.


이러한 식으로 스탠다드 쉐이더를 선택적으로 사용하고 파라미터를 절약한다면 저사양 기기에서도 충분히 스탠다드 쉐이더를 통한 PBR을 사용할 수 있습니다. 감사합니다.


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


들어가며

유니티에서 안드로이드 타겟으로 개발하면 텍스쳐 압축을 ETC로 사용하게 됩니다. 기존에는 텍스쳐의 기본 압축 포맷이 ETC1이였는데, 최근 5.2.0부터는 RGBA 텍스쳐의 압축 포맷이 ETC2.0으로 바뀌게 되었습니다. 텍스쳐 포맷을 compressed로 두면 내부적으로는 ETC2를 사용하도록 되는 것입니다. 그래서 그런지 ETC 포맷에 관한 문의가 빈번하게 들어오고 있습니다. 그래서, 잘 오해할 수 있는 부분을 정리해드리고자 합니다.


Open GL ES 버전 & ECT 포맷 버전

ETC2 압축 포맷은 ETC1가 확장 및 개선된 포맷입니다. 때문에, 가능하다면 ETC1보다는 ETC2를 사용하는 것이 당연히 좋습니다. (참고로, DXT1, DTX3, DXT5는 이야기가 다릅니다. 서로 품질과 크기의 조율 선택 사항입니다.) 다만 문제는 ETC2는 Open GL ES 3.0 이상에서만 지원됩니다. 갤럭시 S3 이하 등의 구형 기종에서는 Open GL ES 2.0으로 돌아가기 때문에 ETC2를 사용하는 것이 불가능합니다.


Open GL ES 2.0 기기에서의 ETC2 사용

하지만 막상 유니티에서 텍스쳐 포맷을 ETC2로 두고 Open GS ES 2.0 기기에서 구동을 해봐도 텍스쳐가 정상적으로 그려집니다. ETC2가 Open GL ES 2.0에서는 지원이 되지 않기때문에 텍스쳐가 그려지지 않아야 될 것으로 생각되서 혼란스러우실 수도 있겟습니다. 

이미지 출처 : http://chulin28ho.tistory.com/

사실, 기기에서 지원되지 않는 텍스쳐 압축을 사용하는 경우, 텍스처는 비압축 RGBA 32 형식으로 압축된 텍스처와 함께 메모리에 저장됩니다. 따라서 이러한 경우에는 텍스처 압축을 푸는 만큼 불필요한 계산 시간이 발생하게 되며 메모리 공간도 두 배로 필요해집니다. 이것 또한 렌더링 성능에 심각한 악영향을 미칩니다.

설명이 좀 애매하긴 한데 예를 들자면, OpenGL ES 2.0 기기에 ETC2 포맷을 사용하면 작동하는데에는 문제가 없지만 성능상 효율이 떨어지게 됩니다. 왜냐하면 ES 2.0 기기는 ETC2를 지원하지 않기 때문에 32비트x폭x높이 + 원래의 ETC2 사이즈 만큼의 메모리가 늘어나서 압축 지원도 못받으면서 메모리만 늘어나게 되기 때문입니다. 또한 로딩 타임에 텍스쳐를 소프트웨어적으로 압축을 푸는 시간도 추가됩니다.


ETC2의 ETC1 하위 호환성

ETC2는 ETC1의 하위 호환성을 보유하고 있습니다. 때문에 Open GL ES 2.0에서도 ETC2를 읽을 수 있는 것으로 알고 계시는 분도 간혹 계십니다. 충분히 오해할만 하지만, ETC2가 ETC1 하위 호환을 포함한다는 것은 기기에서 ETC1을 ETC2처럼 취급할 수 있다는 것일 뿐입니다. 앞서 말씀드린대로 유니티에서는 ETC2를 ES2.0 기기에서 올리면 23bit RGBA로 사용됩니다. 


알파 유무의 차이

안드로이드 텍스쳐 압축의 기본 값이 ETC2 로 바뀌었습니다만 모든 텍스쳐가 ETC2로 기본 설정 되는 것은 아닙니다. ETC2가 기본이 되는 것은 RGBA 텍스쳐(즉, 알파를 포함하는)입니다. ETC2는 ETC1과는 달리 알파 채널을 포함할 수 있기 때문입니다. RGB만 존재하는(즉, 알파채널이 없는) 텍스쳐의 기본 압축 포맷은 여전히 ETC1입니다. RGB 텍스쳐를 ETC로 사용하기를 원하시면 Texture Type을 Advanced 로 변경 후 Format 설정을 바꿔주셔야 합니다. 

릴리즈 노트에서 언급한 포맷 기본값이 바뀌었다는 내용은 RGBA 텍스쳐에 해당하는 내용입니다. 기존에는 16bit RGBA였는데 이 것이 ETC2로 바뀌었다는 것입니다. 릴리즈 노트가 부실해서 충분히 오해의 소지가 있을 것 같습니다. (아직 매뉴얼 페이지에는 이 내용이 갱신되지 않은 것 같습니다. 사람 사는데가 다 똑같죠 뭐 헤헤 양해좀 굽신굽신)


Open GL ES 2.0에서의 RGBA 텍스쳐

하지만 그렇다고 Open GL ES 2.0에서 RGBA 텍스쳐를 사용하려면 RGBA 16비트 혹은 RGBA32비트만 사용하여야 하는 것은 아닙니다. Compress using ETC1(split alpha channel)을 선택하면 원본의 RGBA가 유니티 내부적으로 두 개의 ETC1으로 갈라서 하나는 RGB, 다른 하나는 알파 채널 정보를 담는게됩니다. 그럼으로써 ETC2를 사용하지 않고도 알파 채널을 사용할 수 있는 꼼수를 부립니다.

다만, 이렇게 되면 실제로는 2 개의 텍스쳐 슬롯이므로 쉐이더에서도 텍스쳐 레지스터를 두 개를 차지하게 됩니다. 예를 들자면 내장(bult-in)쉐이더 중 Sprite-Diffuse.shader를 살펴보면 다음과 같이 메인 텍스쳐를 읽은 뒤 _AlphaSplitEnabled 조건이라면 알파 채널을 별도로 한번 더 읽는 것을 확인 가능합니다.

fixed4 SampleSpriteTexture (float2 uv)

{

fixed4 color = tex2D (_MainTex, uv);

#if UNITY_TEXTURE_ALPHASPLIT_ALLOWED

if (_AlphaSplitEnabled)

color.a = tex2D (_AlphaTex, uv).r;

#endif //UNITY_TEXTURE_ALPHASPLIT_ALLOWED

return color;

}

단, 이 기능은 현재 릴리즈된 버전에는 스프라이트에 쓰이는 경우에만 작동하고 있으며 차츰 사용처를 확대해나가는 작업이 진행 중입니다.


ETC1이냐 ETC2냐 그것이 문제로다

“어쩌라는거야 그럼 ETC1 쓰라는거야 ETC2 쓰라는거야?” 이쯤 되면 이러한 질문이 나오시게 될 것입니다 :) 저도 사실 여기에 대한 명쾌한 답변을 드릴 수는 없습니다. ES 3.0지원 기기의 점유율이 증가하고 있는 추세긴 하지만 아직까지는 ES 2.0 지원 기기들의 점유율이 더 높은 상태기 때문입니다. (RGB 텍스쳐의 압축 기본 포맷은 ETC1으로 유지하는 이유이기도 합니다.) 이는 유니티 하드웨어 스탯 사이트에서 확인 가능합니다. 

다만, ETC2를 사용하면 그 만큼 더 메모리를 절약하고 더 높은 퀄리티를 낼 수 있는 것은 자명한 일입니다. 때문에 제 개인적인 생각으로는 주 타켓 기기를 무엇으로 삼냐에 따라 선택을 달리해야 할 것 같습니다. 물론, 보급형 기기를 타겟으로 하는 가벼운 게임이라면 ETC1을 포기해서는 안될 것입니다. 하지만, 고퀄리티 고성능 기기 게임이라면 ETC2를 사용하고 ES 2.0 기종에서는 낭비되는 메모리만큼 다른 부분에서의 품질을 과감히 포기하는 방향도 그리 나쁜 선택만은 아닐 것입니다. 참고로, SystemInfo.graphicsDeviceVersion를 통해 ES 버전을 확인 가능하고 QualitySettings.SetQualityLevel를 통해서 퀄리티 변경이 가능합니다.


SA

다음 링크들을 같이 참고해보시면 더 추가적인 정보들을 확인 하실 수 있을 것입니다:



더 많은 내용은 "유니티 그래픽스 최적화 스타트업"을 참고하세요

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


들어가며

물리기반렌더링( Physically based rendering, PBR, Physically based shading, PBS, 이하 PBR, PBS)이라는 키워드가 떠오른 것은 꽤 오래 되었고 이미 PC나 콘솔에서는 널리 적용되었습니다. 최근 출시한 메탈기어솔리드5는 그 정점을 보여주고 있습니다.

하지만, 모바일이 주력 시장인 국내 게임 시장에서는 관심 밖이였지요. 하지만 최근들어 국내에서도 PBR에 대한 관심이 많아지고 있습니다. 이러한 관심의 가장 큰 이유는 모바일 하드웨어의 성능 발전일 것입니다. PBR이 기본적으로 소모하는 비용을 충분히 감당한 만큼의 성능을 내는 기기들이 보편화 되고 있는 것입니다. 비단 최신 기종이 아니더라도 캐릭터에게만 PBS를 사용하는 등 부분적으로만 사용하여 성능을 절약할 수도 있습니다. 하지만, PBS 쉐이더를 사용하지 않고도 PBS 느낌을 낼 수 있다면 더욱 많은 성능을 절약할 수 있을것입니다. 물론, 초실사 렌더링을 지향하는 게임이라면 100% PBS로 렌더링을 해야겠지요. 하지만 대부분의 모바일 게임들은 그렇지가 않습니다. 근래의 모바일 게임에서 PBS사용하고자 함은 좀 더 멋진 그래픽을 표현하고자 함이 주 목적일일 뿐이지 꼭 물리적으로 정확한 그래픽을 표현하고자 함이 주 목적은 아니라고 생각합니다. 특히, 그 초점은 금속 재질 표현에 맞춰져 있습니다. 비 금속 재질보다는 금속 재질에 촛점을 맞춰서 금속 부분과 금속이 아닌 부분을 함께 표현하고자 함이 목적인 것으로 생각됩니다. 

이러한 관점을 기준으로 느낌을 내는 쉐이더를 만져보보았습니다. 그 결과물인 PBR 대응 머티리얼 텍스쳐들을 그대로 사용하는 가벼운 쉐이더를 소개해드릴까 합니다. MatCap 쉐이더에 Metallic factor를 적용해서 PBS같은 느낌을 내는 방식입니다. 다음 스크린샷 이미지에서 렌더링 되고 있는 케릭터와 발판은 PBR 대응으로 만들어진 텍스쳐들을 그대로 사용하고 있으며 실시간 라이팅이 아닌 MatCap 텍스쳐 기반으로 처리되어있습니다. 데모를 구글 플레이스토어에 올려놓았으므로 기기에 설치하여 확인해보실 수 있습니다. 

다운로드 링크 : https://play.google.com/store/apps/details?id=com.ozproject.demo1



MatCap 쉐이더

우선, MatCap 쉐이더를 기반으로 하고 있으므로 MatCap 쉐이더에 대해 간략하게 설명을 드리도록 하겠습니다. MatCap 쉐이더는 모바일에서 유용하게 사용할 수 있는 이미지 기반 라이팅 중 하나입니다. MatCap은 Material Capture의 약자인데, Material Capture는 현실 세계의 라이팅을 수집해서 캡쳐하기 위한 구체를 의미합니다. 보통 CG 영상이나 이미지에서 실사 렌더링을 위한 라이팅 참고 자료로 사용하기 위한 용도로 만들어집니다.

MatCap 쉐이더는 이러한 Material Capture를 그대로 텍스쳐(이를 MatCap 텍스쳐라 부릅니다)로 만들어서 라이팅 결과로 활용하는 것입니다. 이를 이용하면 재질에 따른 라이팅을 미리 텍스쳐로 만들어놓기 때문에 실시간으로 라이팅 연산을 않고도 실사적인 라이팅을 처리할 수 있습니다. 

출처 : https://shaderforge.userecho.com/topic/416166-it_matrix/

MatCap 쉐이더는 유니티에 내장된 쉐이더는 아니지만 구글링이나 유니티 에셋스토어에서 쉽게 구할 수 있습니다. 이 글에서 소개하고자 하는 쉐이더는 에셋스토어에 있는 MatCap 쉐이더를 기반으로 작업하였습니다. 쉐이더 링크 : https://www.assetstore.unity3d.com/en/#!/content/8221


Metallic

PBS에서의 특징중 하나는 금속과 비금속을 수치로 표현하는 것입니다. 빛이 사물에 닿으면 일부는 흡수되었다가 방출되고 나머지는 바로 반사되 튕겨나갑니다. 이 중 흡수되었다가 방출출되는 빛이 일반적으로 말하는 디퓨즈 영역이고 바로 튕겨나가는 빛이 일반적으로 말하는 스페큘라 영역이 되는 것입니다.

금속은 빛이 닿으면 이러한 디퓨즈 영역이 없이 완전 반사가 일어납니다. 즉, 표면이 금속에 가까울수록 반사의 비중이 높고 금속이 아닌 비전도체에 가까울 수록 디퓨즈의 비중이 높아집니다. 

이미지 출처 : http://docs.unity3d.com/kr/current/Manual/StandardShaderMaterialCharts.html

PBS 머리티얼에서는 이를 반영하여 얼마나 금속에 가까운지의 정도를 나타내는 Metallic 텍스쳐를 사용합니다.

기존의 MatCap 쉐이더는 MatCap 텍스쳐를 한 장만 사용합니다. 이를 Metallic 텍스쳐를 사용하기 위해서 MatCap 텍스쳐를 두 장을 사용하도록 변경해줍니다. 금속성이 0인 경우의 MatCap 텍스쳐와 완전 금속인 경우의 MatCap 두 개의 MatCap을 사용하여 Metallic에 따라 비중을 반영해주면 되는 것입니다. 


파라미터

또한, AO맵 역시 반영해주어야합니다. AO는 빛이 차폐되는 정도를 나타내주는 것이므로 라이팅 연산 최종 단계에서 곱해주는 것으로 간단히 처리 해주면 됩니다. Emissive는 발광하는 부분이므로 라이팅 연산 최종 단계에서 더해주는 것으로 간단히 처리 해주면 됩니다. 최종적인 파라미터들은 다음과 같습니다.

코드

쉐이더 코드는 다음과 같습니다. 데모에 쓰인 리소스는 에셋스토어에서 유료로 판매되고 있는 리소스이므로 프로젝트를 공유드리지 못하는 점 양해 바랍니다. 

Shader "MatCap/Bumped/Textured Metalic" {

Properties {

_MainTex ("Base (RGB)", 2D) = "white" {}

_AOMap ("AO (RGB)", 2D) = "white" {}

_AOFactor ("AO Factor" , Range(0.0,2.0)) =1.0

_BumpMap ("Normal Map", 2D) = "bump" {}

_MetalicMap ("Metallic (RGB)", 2D) = "white" {}

_MetalicMultiply ("Metallic Multiply" , Range(0.0,10.0)) =1.0

_EmissiveTex ("Emissive (RGB)", 2D) = "black" {}

_EmissiveMultiply ("Emissive Multiply" , Range(0.0,10.0)) =1.0

_MatCapDiffuse ("MatCap Diffuse (RGB)", 2D) = "white" {}

_MatCapReflect ("MatCap Reflect (RGB)", 2D) = "white" {}

_MatCapReflectMultiply ("MatCap Reflect Multiply" , Range(0.0,10.0)) =1.0

}

Subshader {

Tags { "RenderType"="Opaque" }

Pass {

Tags { "LightMode" = "Always" }

CGPROGRAM

#pragma vertex vert

#pragma fragment frag

#pragma fragmentoption ARB_precision_hint_fastest

#include "UnityCG.cginc"

struct v2f {

float4 pos : SV_POSITION;

float4 uv : TEXCOORD0;

float3 c0 : TEXCOORD1;

float3 c1 : TEXCOORD2;

};

uniform float4 _MainTex_ST;

uniform float4 _BumpMap_ST;

v2f vert (appdata_tan v) {

v2f o;

o.pos = mul (UNITY_MATRIX_MVP, v.vertex);

o.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex);

o.uv.zw = TRANSFORM_TEX(v.texcoord, _BumpMap);

float3 n = normalize(v.normal).xyz;

float3 t = normalize(v.tangent).xyz;

float3 b = normalize(cross( n, t ) * v.tangent.w);

float3x3 rotation = float3x3( t, b, n );

o.c0 = mul(rotation, normalize(UNITY_MATRIX_IT_MV[0].xyz));

o.c1 = mul(rotation, normalize(UNITY_MATRIX_IT_MV[1].xyz));

return o;

}

uniform sampler2D _MainTex;

uniform sampler2D _BumpMap;

uniform sampler2D _AOMap;

uniform sampler2D _MetalicMap;

uniform sampler2D _MatCapDiffuse;

uniform sampler2D _MatCapReflect;

uniform sampler2D _EmissiveTex;

uniform float _MatCapReflectMultiply;

uniform float _AOFactor;

uniform float _EmissiveMultiply;

uniform float _MetalicMultiply;

fixed4 frag (v2f i) : COLOR {

fixed4 tex = tex2D(_MainTex, i.uv.xy);

fixed4 ao = tex2D(_AOMap, i.uv.xy);

fixed4 metalic = tex2D(_MetalicMap, i.uv.xy);

fixed4 si = tex2D(_EmissiveTex, i.uv.xy);

fixed3 normals = UnpackNormal(tex2D(_BumpMap, i.uv.zw));

half2 capCoord = half2(dot(i.c0, normals), dot(i.c1, normals));

fixed4 diff = tex2D(_MatCapDiffuse, capCoord*0.5+0.5) * tex;

fixed4 refl = tex2D(_MatCapReflect, capCoord*0.5+0.5);

refl.a = 1;

refl *= _MatCapReflectMultiply;


fixed4 ret = lerp( diff, refl, saturate(float4(metalic.rgb * _MetalicMultiply,1)));

return ret * lerp( 1, ao, _AOFactor) + si * _EmissiveMultiply;

}

ENDCG

}

}

Fallback "VertexLit"

}


한계

간단한 쉐이더다보니 많은 한계점을 가지고있습니다. 보시다시피 이는 정확한 PBS는 아닙니다. 많은 부분들이 생략되어 있고 라이팅 재질 느낌은 전적으로 MatCap 텍스쳐에 의지하고 있습니다. 때문에, MatCap 텍스쳐를 어떤 것으로 사용하느냐에 따라 품질이 크게 좌우됩니다. 또한, 씬 별로 라이팅이 다르다면 씬 별로 MatCap 텍스쳐를 만들어 줘야 합니다. MatCap 텍스쳐를 어떻게 만드냐에 따라 결과가 달라질 것입니다. 

MatCap 방식은 한 쪽에서 바라보는 라이팅만 표현이 가능하기 때문에 카메라 각도가 고정되어 있는 경우에만 유효하다는 제약이 있습니다.그러나, 대부분의 모바일 게임들은 탑 뷰(Top View), 쿼터 뷰(Quarter View), 백 뷰(Back View) 등 카메라의 방향이 고정된 채로 게임이 진행되는 경우가 대부분이므로 모바일서는 큰 제약 사항이 되지는 않을 것입니다.



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


Unity 5.3 릴리즈는 WebGL를 지원하는 네번째 버전입니다. 5.0에서부터 WebGL을 프리뷰(Preview)로 처음 탑재하고 난 이후에 수 많은 사항들이 개선되어 왔습니다. 몇 가지 사항들을 공유드리고자 합니다. 이 글은 유니티 공식 블로그의 UNITY 5.3 WEBGL UPDATES를 번역 및 요약한 글입니다. 정확한 내용을 원하신다면 원문을 읽어보시길 바랍니다.


5.3에서의 바뀐 점

  • WebGL에서 스탠다드쉐이더가 데스크탑 퀄리티의 리플렉션을 사용합니다. 기존에는 유니티 WebGL은 OpenGL 2.0을 사용하는 모바일용으로 간략화된 버전의 스탠다드 쉐이더를 사용했었습니다. 이제는 데스크톱과 동일한 리플렉션을 사용하여 고품질의 재질 결과를 표현해줍니다.
  • 부드러운 그림자(Soft Shadow)를 지원합니다.
  • 귀하의 서버가 설정이 되어 있지 않더라도 유니티 WebGL은 압축을 지원합니다.기존에는 WebGL은 gzip 압축된 파일을 제공하기 위해서는 서버에 셋팅이 필요했습니다. 그렇지 않으면 압축되지 않은 데이터를 사용하여 긴 시간의 다운로드가 필요했습니다. 하지만 이제는 유니티의 WebGL은 자동적으로 gzip 압축된 데이터를 제공합니다. 이는 클라이언트단의 자바스크립트에서 압축 해제를 수행합니다. 이로 인해 압축 처리 딜레이가 조금 발생하긴 하지만 거대한 다운로드 시간을 피할 수 있습니다. 배포 사이즈에 대한 자세한 내용은 이 문서를 참고 바랍니다.
  • 데이터 파일이 LZ4 압축 상태로 메모리에 존재합니다. 유니티 5.3에서는 에셋 데이터가 메모리에 LZ4 압축된 상태로 메모리에 올라갑니다. 에셋이 로드 될 때에만 압축이 해제됩니다. 이는 에셋 데이터가 적은 메모리를 차지해서 메모리 낭비될 일이 적어짐을 의미합니다.
  • WebGL 빌드 파일을 다른 url로 이전하는 것이 쉬워졌습니다. 빌드 프로세스 과정에서 생성되는 파일들은 index.html에 의해 참조됩니다. 이로인해 빌드 데이터를 외부 호스팅 솔루션으로 배치하는 것이 쉬워졌습니다. 빌드 아웃풋 파일 이전의 자세한 내용은 이 문서를 참고 바랍니다.
  • 웹캠을 지원합니다. 5.3에 WebCamTexture 클래스가 추가되었습니다. 이는 getUserMedia API를 지원하는 브라우저에서 사용 가능합니다. 
  • WebGL이 유니티 클라우드 빌드가 가능합니다.
  • 문서들을 개선하였습니다. 5.3을 위해서 WebGL 문서가 대폭 개선되어 많은 정보들이 추가되었습니다.
  • 수 많은 버그들이 수정되었습니다. 5.3에서는 5.2에 비해 28개의 WebGL 버그가 수정되었습니다. 외에도 WebGL에서 간접적으로 영향을 주는 수 많은 버그들이 수정되었습니다. 또한, 5.2.x 패치 릴리즈 사이클 동안 수정된 WebGL 버그 수정 사항들이 포함되어 있습니다.


WebGL이 공식 지원 타겟이 되었습니다.

WebGL은 공식 지원하지 않는 프리뷰(Preview) 상태였습니다. 5.3부터는 WebGL에서 프리뷰 레이블을 제거하고 공식 지원 대상이 되었습니다. 따라서, 프리미엄 서포트 및 엔터프라이즈 서포트는 WebGL을 커버합니다.

5.0에서 WebGL이 탑재되고나서 5.3까지 오면서 시간이 꽤 지났고 시간이 지날 수록 브라우저 기술도 발전해왔습니다. 예를 들어 마이크로소프트는 새로운 브라우저인 엣지를 윈도우즈10에 탑재하고, 이 브라우저는 asm.js를 지원함으로써 익스플로러 11에서는 불가능했던 컨텐츠들을 지원할 수 있게 되었습니다. 

그간 WebGL이 많은 개선이 되었긴 했지만 갑자기 모든 기능들이 WebGL에서 잘 동작한다는 의미는 아닙니다. 또한, 네이티브 빌드만큼의 성능이 나온다거나 모든 브라우저에서 아무 문제 없이 동작한다는 것은 아닙니다. 시간이 지남에 따라 개선은 계속 이루어 질 것이며 지금 시점에서는 공식 지원을 시작하기 적절한 시기인 것으로 판단한 것입니다. 현재의 작업 상태와 제한 상황을 문서에 명시하였으므로 이를 참고 바랍니다.


브라우저 제조사들과의 작업

유니티의 WebGL은 브라우저가 제공하는 웹 기술에 의존적일 수 밖에 없습니다. 주요 브라우저 제조사들과 긴밀하게 작업을 하고 있으며, 이들은 빠른 속도로 기술을 발전시키고 있습니다. 모질라의 파이어폭스, 마이크로 소프트의 엣지, 구글의 크롬 등의 주요 브라우저들과 유니티의 호환 작업이 지속적으로 이루어지고 있어서 빠른 속도로 개선이 되고 있습니다.


시도해보세요!

WebGL로의 익스포트는 웹 게이밍의 미래라고 믿고 있습니다. 귀하의 게임을 유니티의 WebGL로 배포해보십시요. Heroes Of Paragon, Spider Box, Big Buck Hunter 등 이미 몇 개의 사례들이 있습니다. (역주 : 씨발 애석하게도 이 예시들의 게임은 망할 게등위(게임산업진흥에관한법률)때문에 국내에서는 플레이가 불가능합니다.시작하기 위해서는 다음 절차를 따르십시요. 



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


쉐이더를 작성하다보면 텍스쳐를 많이 사용하는 기능을 만들 때도 있습니다. 대표적인게 바로 지형 스플래팅이죠. (유니티의 터레인은 아무도 쓰지 않는다는 슬픈 전설이...) 스플래팅의 개념을 모르시는 분든을 위해서 간략히 설명 드리자면, 스플래팅은 여러 텍스쳐를 서로 블렌딩해서 표현해주는 방식을 뜻합니다. 이렇게 하게 되면 작은 크기의 텍스쳐들을 가지고도 넓은 지역을 표현해줄 수가 있어서 텍스쳐 메모리를 상당히 절약할 수 있게 됩니다. 

이미지 출처 : http://blog.naver.com/sorkelf/40151055590

예전에 GPU의 쉐이더 성능이 좋지 않은 시절에는 이러한 스플래팅을 처리하기위해 여러번 덧그리는 멀티 패스로 구현해야만 했습니다. 하지만 요즘은 쉐이더에서 여러장의 텍스쳐를 한번에 읽어서 싱글 패스로 처리할 수가 있습니다. 하지만 문제는 쉐이더에서 한번에 읽을 수 있는 텍스쳐의 갯수가 제한 되어 있다는 것입니다. 만일 쉐이더에서 너무 많은 쉐이더를 샘플링 하면 원하는대로 작동하지 않게 됩니다. 근데, 이 현상이 인지하기 쉽지도 않습니다. 쉐이더 컴파일 오류가 나는 것 도 아니고 오브젝트가 보라색으로 칠해지는 것 도 아니도 그냥 몇 개의 텍스쳐가 읽히지 않고 무시되어 버립니다. 이러한 현상은 OpenGL에서 제한하는 텍스쳐 수가 다르기 때문입니다. OpenGL 공식 스펙에 이러한 숫자가 정해져 있긴 하지만 디바이스마다도 또한 차이가 발생합니다. 때문에컴파일 단계에서 이러한 제한을 탐지할 방법이 없습니다. 그러다보니 실제 렌더링 과정에서 텍스쳐 샘플링 갯수 제한을 넘게 되면 더 이상의 텍스쳐 샘플링은 무시가 되고 렌더링이 되는 것입니다.

OpenGL에서 쉐이더에서 한번에 샘플링 할 수 있는 텍스쳐 갯수는 MAX_TEXTURE_IMAGE_UNITS로 정의 되어 있습니다. (유니티에서 확인해볼 수 있는 수치는 아닙니다.)이를 문서에서 확인해보면 ES2는 8, ES3에서는 16으로 나옵니다. 즉, OpenGL ES2에서는 쉐이더에서 한번에 최대 8개의 텍스쳐를 사용할 수 있고, OpenGL ES3에서는 쉐이더에서 한번에 최대 16개의 텍스쳐를 샘플링 할 수 있다는 말이 됩니다. (물론 이 값은 특정 디바이스에서는 다른 값일 수도 있습니다.)

이미지 출처 : iOS 개발자 라이브러리

그렇다고 쉐이더이 인스펙터에 텍스쳐 슬롯을 8개 만들면 정상적으로 쓸 수 있다는 말은 또 아닙니다. 유니티는 서피스 쉐이더로 작성하고나면 유니티는 자동적으로 추가적인 정보들을 처리해줍니다. 그러는 과정에서 유니티에서 사용하는 텍스쳐가 추가적으로 쓰일 수 있습니다. 이는 쉐이더의 variant에 따라서 다르므로 완성된 코드를 확인하여야 합니다. 쉐이터를 선택 후 인스펙터에서 Compile and show code를 선택합니다. 

그러면 유니티가 서피스 쉐이더를 기반으로 추가적인 코드들과 variant들을 만들어내어 완성한 후 최종 컴파일에 사용한 코드를 보여줍니다. 코드를 확인해보면 각각의 variant에 따른 사용 텍스쳐 갯수를 주석으로 확인해볼 수 있습니다. 이 예시의 쉐이더는 서피스 쉐이더에서 8개의 텍스쳐를 사용하고 있었고 인스펙터에서 설정하고 있는 텍스쳐도 8개뿐이지만 실제로 생성된 결과물을 보면 조건에 따라 10개의 텍스쳐를 사용하고 있음을 알 수 있습니다. 

이러한 경우에는 ES 2.0에서의 한계치인 8을 넘어버리기 때문에 원하는 모습대로 렌더링이 되지 않을 수 있습니다. 때문에, 작성하고 있는 쉐이더에서 텍스쳐를 6개 이상 사용할 경우에는 variant에 따른 실제 텍스쳐 사용 갯수를 확인하여야 합니다.

맺음말 적당한게 생각 안나네요. 걍 끘! 안녕~



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


게임 그래픽에서 반사의 표현은 매우 중요한 시각적 요소 중 하나입니다. 주변 환경의 반사를 표현함으로써 금속 재질을 처리할 수 있기 때문입니다. 판타지물의 투구라든가 SiFi물의 로보트 등 금속 재질에서의 반사 표현 여부는 그래픽 퀄리티에 큰 영향을 미칩니다.

유니티5에서 라이팅 관련 기능이 강화되면서 리플렉션 프로브(Reflection Probe) 기능이 추가되었습니다. 이름에서 유추할 수 있듯이, 라이트 프로브(Light Probe)처럼 특정 지점들의 리플렉션을 미리 연산해서 프로브에 저장해놓는 것입니다. 

라이트 프로브 및 라이트맵(Lightmap)이 정적(static)인 오브젝트와 Baked 또는 mixed로 설정 된 라이트만 반영하는 것과 마찬가지로, 리플렉션 프로브 역시 정적인 오브젝트들만 반영한다는 등의 제약점들이 있긴 합니다. 하지만 부분 부분 마다의 반사를 제대로 반영할 수 있다는 점은 크나큰 매력이 될 것입니다. 자세한 사용법은 메뉴얼 및 블로그 글을 참고하세요. (PHYSICALLY BASED SHADING IN UNITY 5: A PRIMER, 리플렉션 프로브, 리플렉션 프로브 개요리플렉션 프로브 사용하기, 물리 기반 쉐이딩으로 작업하기) 메뉴얼의 글은 조만간 한글로 업데이트 될 예정입니다.

사실, 반사의 표현은 유니티5에서부터만 쓰게된 것은 아닙니다. 전통적으로 큐브맵(Cubemap)을 사용하여 쉐이더에서 반사를 표현해왔습니다. 유니티에 내장(Built-in)된 기존 쉐이더(Legacy Shader)에서도 이러한 큐브맵 반사들을 지원해왔습니다. (메뉴얼 : 반사 쉐이더 Family

하지만 기존의 쉐이더들은 특정 큐브맵을 명시적으로 지정해줘야만 하고 위치마다 다른 환경을 반영하는 리플렉션 프로브를 적용하지는 않습니다. 때문에, 내장 쉐이더에서 리플렉션 프로브를 사용하기 위해서 스탠다드 쉐이더(Standard Shadder)를 이용하여야합니다. 하지만, 저가의 보급형 모바일 기기에서는 스탠다드 쉐이더를 사용하기에는 성능의 부담이 존재합니다.

따라서, 모바일에서 리플렉션 프로브를 사용하기 위해서는 내장되어있는 기존 쉐이더나 스탠다드 쉐이더 대신, 쉐이더를 직접 작성한 커스텀 쉐이더를 사용하여야 합니다. 사실, 리플렉션 프로브도 근본적인 형태는 큐브맵입니다. 큐브맵을 미리 프로브별로 미리 구워놓고 가지고 있는 것이지요. 오브젝트의 위치에 따라서 적절한 큐브맵을 리플렉션 프로브로부터 가져오게 되는 것입니다. 

여차 저차 서론이 길어졌습니다만 결론만 말씀드리면 큐브맵을 인스펙터 창에서 지정해서 받아오는 대신 유니티에서 사전 정의해놓은 uniform sampler를 사용하여 큐브맵을 읽어들이면 된다는 것입니니다.

유니티가 리플렉션 프로브로 들어오는 큐브맵을 unity_SpecCube0로 사전 정의해놓았습니다. 이를 사전 정의된 UNITY_SAMPLE_TEXCUBE()로 읽어들입니다. 사실, UNITY_SAMPLE_TEXCUBE()는 texCUBE()를 디파인 한 것 뿐이지만 모바일 외 다른 플랫폼에서도 정상 작동을 하기 위해서는 UNITY_SAMPLE_TEXCUBE()로 사용하는 것이 좋습니다. 어찌되었든 리플렉션 프로브의 큐브맵으로부터 읽어들인 값에다가 리플렉션 프로브의 HDR 계수인 unity_SpecCube0_HDR의 r속성을 곱해주어서 반사 이미지의 최종 결과물을 얻습니다. 서피스 쉐이더를 작성하는 경우에는 surface 아웃풋의 Emission으로 이 값을 설정해두면 됩니다.

o.Emission = UNITY_SAMPLE_TEXCUBE(unity_SpecCube0, rv).rgb * unity_SpecCube0_HDR.r;

이름이 unity_SpecCube가 아니라 뒤에 0가 붙었다는 것을 보면 unity_SpecCube1도 존재한다는 것을 유추하실 수 있을 것입니다. unity_SpecCube0_HDR도 마찬가지로 unity_SpecCube1_HDR이 존재합니다. 이를 설명하기 위해서 오브젝트의 Mesh Renderer 인스펙터를 살펴보겠습니다. Reflection Probes 드롭다운을 내려보면 항목 중 Blend Probes라는 항목이 있는 것을 확인 가능합니다. 말 그대로 리플렉션 프로브를 블렌딩 해준다는 의미입니다. 오브젝트가 각기 다른 리플렉션 프로브 영역으로 이동 할 시 리플렉션 이미지가 갑자기 틱 하고 바뀌는 것을 방지하기 위하여 블렌딩을 해주는 것입니다. 

그러기 위해서는 쉐이더에서 큐브맵 두 개를 읽어야한다는 의미가 됩니다. unity_SpecCube1을 unity_SpecCube0와 같이 읽어들인 다음 unity_SpecCube0_BoxMin.w값으로 보간해주면 됩니다. 원래는 이런 블렌딩 기능을 UNITY_SPECCUBE_BLENDING 디파인으로 묶어놓아야 합니다. 하지만 모바일 타겟에서는 UNITY_SPECCUBE_BLENDING 디파인이 꺼져있기 때문에 해당 디파인에 종속적이지는 않게 두었습니다. 사실, 모바일에서 성능을 생각한다면 블렌딩 기능은 사용하지 않는 것이 좋습니다. 다만, 금속 느낌이 강한 재질이여서 이미지가 툭툭 바뀌는 모습이 크게 거슬린다면 블렌딩 연산을 사용할 수 밖에 없을 것입니다.

fixed3 blendTarget = UNITY_SAMPLE_TEXCUBE(unity_SpecCube1, rv).rgb * unity_SpecCube1_HDR.r;

o.Emission = lerp(blendTarget, o.Emission, unity_SpecCube0_BoxMin.w);

그러고 나면 리플렉션 프로브가 자연스럽게 반영되는 모습을 확인 할 수 있습니다. 다음 영상은 리플렉션 프로브를 사용하는 커스텀 쉐이더를 적용한 드론의 모습을 보여주고 있습니다. 

모두 유료 에셋을 사용한 관계로 프로젝트를 공유해드리지 못하는 점 양해 바랍니다. 다만 제작한 쉐이더의 전체 코드는 다음과 같습니다.

Shader "Example/WorldRefl Normalmap Refl" {

Properties{

_MainTex("Texture", 2D) = "white" {}

_BumpMap("Bumpmap", 2D) = "bump" {}

_Metalic("Metalic", Range(0,1)) = 0.5

_MetalicMap("Metalicmap", 2D) = "white" {}

}

SubShader{

Tags{ "RenderType" = "Opaque" }

CGPROGRAM

#pragma surface surf FakeMetal noshadow nolightmap 

struct Input {

float2 uv_MainTex;

float2 uv_BumpMap;

float3 worldRefl;

INTERNAL_DATA

};


struct SurfaceOutputCustom

{

fixed3 Albedo;  // diffuse color

fixed3 Normal;  // tangent space normal, if written

fixed Alpha;    // alpha for transparencies

fixed3 Emission;

fixed3 Metalic;

};


sampler2D _MainTex;

sampler2D _BumpMap;

sampler2D _MetalicMap;

fixed _Metalic;


half4 LightingFakeMetal(SurfaceOutputCustom s, half3 lightDir, half3 viewDir, half atten) {

half NdotL = saturate(dot(s.Normal, lightDir));

half diff = NdotL * 0.5 + 0.5; // Half-Lambert

half4 c;

c.rgb = s.Albedo *_LightColor0.rgb * (diff * atten);

c.a = s.Alpha;

c.rgb *= 1 - s.Metalic;

return c;

}


void surf(Input IN, inout SurfaceOutputCustom o) {

o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb;

o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));

float3 rv = WorldReflectionVector(IN, o.Normal).xyz;

o.Emission = UNITY_SAMPLE_TEXCUBE(unity_SpecCube0, rv).rgb * unity_SpecCube0_HDR.r;

//#if UNITY_SPECCUBE_BLENDING

fixed3 blendTarget = UNITY_SAMPLE_TEXCUBE(unity_SpecCube1, rv).rgb * unity_SpecCube1_HDR.r;

o.Emission = lerp(blendTarget, o.Emission, unity_SpecCube0_BoxMin.w);

//#endif

o.Metalic = tex2D(_MetalicMap, IN.uv_MainTex).rgb * _Metalic;

o.Emission.rgb *= o.Metalic.rgb;

}

ENDCG

}

Fallback "Diffuse"

}

이는 메탈 느낌에 초점을 맞춘 유사 PBS라고 볼 수 있겠습니다. 물론 PBS는 전혀 아니지만 모바일에서 저렴한 비용으로 PBS의 느낌적인 느낌을 내기에는 적당하지 않나 싶습니다 :)


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

Unity5에서 라이트맵 빌드시 많은 시간이 소요된다는 불편을 호소하시는 분들이 많이들 계십니다. 유니티 또한 이를 인지하고 있으며 라이트맵 빌드를 개선시키기 위해 다방면으로 노력을 하는 중입니다. 이 일례로 현재 작업중인 라이트맵 LAN 분산 빌드(Distributed LAN lighting build)와 점진적 빌드(Progressive Lightmap Baking) 기능을 알려드리고자 합니다. 


라이트맵 LAN 분산 빌드(Distributed LAN Lightmap Build) 

이트맵을 빌드하는 과정은 많은 시간이 소요됩니다. 품질 설정에 따라 빌드 시간이 다르긴 하지만 고품질의 결과를 얻고자 할 수록 더 많은 시간이 필요할 수 밖에 없습니다. 품질을 낮추지 않으면서 빌드 시간을 단축 시키는 유일한 방법은 더욱 고성능의 PC를 사용하는 것입니다. 라고 말씀드린다면 너무 무책임한 말이 되겠지요 :) 아마 대부분은 이미 충분히 고성능의 컴퓨터에서 작업을 하고 계실 것이기때문에 유니티에서는 분산 빌드 시스템 도입을 작업중입니다. 백지장도 맞들면 낫다는 말이 있듯이, 라이트맵을 하나의 컴퓨터로만 빌드하는 것이 아니라 여러 PC에서 함께 연산하는 것입니다. 에이전트 컴퓨터에서 라이트맵을 빌드할 시, LAN으로 연결되어 있는 다른 컴퓨터에 작업 단위를 나누어서 할당해줍니다. 그 후 컴퓨터들은 각자 작업을 거친 후 다시 작업물을 에이전트 컴퓨터로 모아서 최종 마무리를 거치면 라이트맵이 완성 되는 것입니다. 이리하면 컴퓨터가 많을 수록 라이트맵 빌드 시간이 획기적으로 단축 될 수 있게 됩니다. (아래 이미지는 여러 컴퓨터와 연결 된 에이전트 컴퓨터의 빌드 화면을 보여주고 있습니다.)

참고 영상 링크 : https://www.youtube.com/watch?v=W7aaM9M0YWo&feature=youtu.be


점진적 빌드(Progressive Lightmap Baking)

앞서 말씀드렸다시피 현재 라이트맵을 빌드하면 그 결과를 보기 전까지는 긴 시간이 소요됩니다. 씬을 수정 하 긴 시간 라이트맵을 빌드하고 다시 씬을 수정하는 반복 과정을 거치면서 작업하는 것은 매우 고통스러운 시간이 될 것입니다. 이를 보완하기위해 라이팅 인스펙터에서 자동(Auto) 빌드 기능을 제공해주고 있습니다. 하지만, 라이트맵 빌드 자체가 오래걸리기 때문에 완벽한 해결책이 되지는 못합니다. 따라서, 유니티에서는 라이트맵이 저해상도에서 고해상도로 빌드 되는 과정을 미리 보여주며 빌드하는 기능을 작업 중입니다. 마치 GIF 이미지를 열었을 때 저해상도의 이미지로 보여줬다가 로딩됨에따라 원본 해상도의 이미지로 보여주는 과정을 생각하시면 될 것 갑습니다. 이렇게 함으로써 씬 변경 후 대략적인 라이트맵 결과를 빨리 확인하고 다시 씬 구성을 바꾸는 등 씬 작업 이터레이션을 효율을 획기적으로 개선시킬 수 있게 됩니다. (아래 이미지는 빌드 버튼을 누른 후 시간이 지남에 따라 보여지는 모습을 나타냅니다.)

참고 영상 링크 : https://drive.google.com/a/unity3d.com/file/d/0B11iL4IgOgWLUTJWU1ZXOXFheTA/view


계획

다만 앞서 말씀드렸다시피 이 기능들은 아직 작업중입니다. 기본적인 기능은 완료 된 상태이긴 하지만 실제 릴리즈까지 가기 위해서는 아직 손 봐야 할 부분이 많습니다. 따라서 구체적인 스케쥴이나 기능 탑재 버전등의 세부 계획에 대해서는 말씀드리기가 힘듭니다. 다만, 개발자 여러분들의 불편사항을 없애기위해 최선을 다하고 있으며 라이트맵 빌드 또한 개선중에 있다는 것을 말씀드리고자 합니다. 감사합니다.


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


유니티 5.2가 배포 된 이후 애로 사항을 겪는 분들이 계시는 것으로 알고 있습니다. 

5.2;;;

조만간 이를 보완하기 위한 패치가 릴리즈 될 것이며 공식 버전 또한 지속적으로 배포될 것입니다. 유니티의 로드맵이 공개되었습니다. 더불어, 주간 패치와 월간 공식 릴리즈에 대한 유지 보수 엔지니어링 팀의 계획을 공유하고자 합니다. (원문 : UNITY PATCH RELEASE PLAN)


5.1 패치 릴리즈

유니티 5.1.4는 5.1.x.의 마지막 공식 릴리즈가 될 것입니다. 이는 지난 5.1.3p1, 5.1.3p2, 5.1.3p3 패치를 모두 포함하는 것입니다. 9월 8일 5.2.0이 릴리즈됨과 동시에 패치 개발 주기는 5.2 버전에 맞춰지게 되었습니다. 따라서, 다음 패치는 5.2.0p1이 될 것입니다. 패치 5.2.0p1이 5.1.3p3의 모든 수정 사항들을 포함하는 반면, 5.2.0은 5.1.2까지의 수정 사항만을 반영합니다. 그말인 즉슨, 5.2.1 공식 릴리즈는 5.1.4까지의 모든 사항을 반영하게 된다는 것입니다. 5.2.0p1에는 5.2.0에 포함되지 않았던 많은 버그 수정 내역이 포함되어 있으며, 5.2.0p1 패치 이후 빠른 시일내로 5.2.1 정식 릴리즈를 배포할 것입니다.


5.2+ 패치 릴리즈

5.2.1 공식 릴리즈는 5.2.0p1의 수정 내용 모두를 반영할 계획입니다. 또한 필요에따라서 수정 사항들이 추가적으로 반영 될 수도 있습니다. 5.3.0이 출시되기 전 까지는 5.2.x 패치가 매 주 수요일마다 나오게 될 것입니다. 또한, 매 4주간의 패치 릴리즈 후 정식 릴리즈를 배포함으로써 매 달 마다 공식 릴리즈를 배포할 계획입니다. 이는 5.3.0이 배포된 후 5.3 패치 싸이클에도 마찬가지가 될 것입니다.


4.6 패치 릴리즈

최종적으로, 2015년 12월을 끝으로 4.6에 대한 패치 혹은 공식 릴리즈를 종료할 것입니다. 유니티의 개발력을 유니티5에 집중하기 위한 어쩔 수 없는 선택임을 양해 바랍니다. 이미 4.6 패치 주기가 2주 단위로 줄어든 상태입니다. 격 주 단위로 금요일에 4.6x 패치 릴리즈가 배포될 것이며 공식 릴리즈는 2달 주기로 나오게 됩니다. 2015년 12월 아후로는 더 이상 릴리즈 되지 않을것입니다.


유지 보수 엔지니어링 팀

유니티의 재빨리 버그를 수정하고 전반적인 품질을 높이는데 집중하기 위해서 저희 유지 보수 엔지니어링 팀에 더 많은 엔지니어가 참여하게 되었습니다. 또한, 저희는 포럼을 항상 주시하고 있으며 새로운 릴리즈가 배포될 때 마다의 피드백과 반응을 살피고 있습니다. 저희는 더 많은 작업 계획을 가지고 있으며, 계획이 진행됨에 따라 블로그 포스팅을 올리도록 하겠습니다. 감사합니다.


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

원문 : http://blogs.unity3d.com/2015/09/10/unity-services-are-just-a-few-clicks-away/


유니티 5.2에서 서비스 윈도우가 추가되었습니다. 이를 통해서 에디터상에서  유니티애즈(Unity Ads), 유니티애널리틱스(Unity Analytics), 유니티클라우드빌드(Unity Cloud Build), 유니티멀티플레이어(Unity Multiplayer)를 제어할 수 있습니다. 또한 더 이상 SDK를 별도로 통합하는 과정을 거치지 않아도 됩니다.

우선, Window 메뉴를 통하거나 에디터 우측 상단의 구름 모양의 아이콘을 클릭하여 서비스 윈도우를 열 수 있습니다.

그 후, 프로젝트 ID가 생성됩니다. 이 프로젝트 ID는 프로젝트의 고유 식별 번호가 됩니다. 서비스 윈도우에는 서비스(Services), 멤버(Members), 연령제한(Age Designation), 설정(Settings) 총 4개의 탭이 존재합니다. 


서비스(Services)

프로젝트에서 Unity Ads와 Unity Analytics를 활성화 시키는 것은 매우 간단합니다. 위해서는 스위치를 "On"으로 켜주기만 하면 됩니다. Unity Cloud Build를 위해서는 약관에 동의하기만 하면 됩니다. Unity Multiplayer는 환경 설정을 함으로써 시작할 수 있습니다. 


멤버(Members)

프로젝트(Project)를 공유할 시에는 사람들의 접근 권한을 적용해주는 것이 중요합니다. Members 탭에서 프로젝트의 추가적인 멤버를 초대할 수 있습니다. 또한, 프로젝트의 온라인 대시보드에서 권한을 관리할 수 있습니다. 프로젝트(Project)는 조직(Organization)에 포함될 수 있으며, 조직(Organization)은 여러 프로젝트(Project)를 포함할 수 있습니다.


연령제한(Age Designation)

미국에서는 13세 이하의 어린이가 앱을 사용하도록 허용하기 위해서는 COPPA(the Children’s Online Privacy and Protection Act)를 준수해야합니다. 게임이 이 카테고리에 부합한다면 연련 제한을 “under 13”로 설정하십시요. 유니티애즈와 유니티애널리틱스에서 수집하는 데이터의 제약이 생기긴 하지만 그래도 동작은 이상 없이 합니다.


설정(Settings)

설정(Settings)탭을 이용하면 프로젝트명을 바꿀 수 있습니다. 프로젝트 ID는 아닙니다. 현재의 프로젝트를 다른 프로젝트로 확장하는 용도 등으로 새로운 프로젝트 ID를 생성하기 위해서는 "Unlink"를 누르기만 하면 됩니다. 서비스를 언제든지 다시 시작할 수 있습니다.


대시보드(Dashboard)

유니티 서비스를 활설화하고나면 온라인 대시보드에서 환경을 설정할 수 있습니다. 유니티애즈(Unity Ads), 유니티애널리틱스(Unity Analytics), 유니티클라우드빌드(Unity Cloud Build), 유니티멀티플레이어(Unity Multiplayer)의매뉴얼 문서도 확인하실 수 있습니다.

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

원문 : http://blogs.unity3d.com/2015/09/08/unity-5-2-easy-access-to-unity-services/


Unity 5.2가 출시되었습니다. 다운로드 받으세요.

최신 릴리즈에서 빅 뉴스중 하나는 서비스 윈도우가 추가되었다는 것입니다. 유니티 애즈, 유니티 애널리틱스, 유니티 클라우드 빌드, 유니티 멀티플레이어가 이 서비스 윈도우에 통합되었습니다. 더 이상 각각의 별도의 SDK가 필요하지 않게 되었습니다.


수익을 극대화 시켜주는 유니티 애즈

유니티 애즈는 급속도로 성장중이며, 세계에서 가장 널리 쓰이는 광고 네트워크가 되가고 있습니다. Best Fiends에서 리텐션 감소 없이 어떻게 수익을 250% 극대화시켰는지를 확인해보시면, 왜 더 많은 스튜디오들이 유니티 애즈를 채용하고있는지를 알 수 있을 것입니다.


앱을 자동으로 빌드, 설치, 테스트

유니티 클라우드 빌드는 자동으로 여러 플랫폼을 한번에 빌드하고 쉽게 다운로드하고 공유할 수 있게 해줍으로써서 게임 개발 파이프라인을 최적화시켜줍니다. 이로 인해서 게임 개발 자체에 집중할 수 있도록 도와줍니다. Synapse Games는 "유니티 클라우드 빌드는 빌드 당 45분씩 낭비되던 시간을 0로 바꿔주었습니다"라고 하였습니다. 셋업도 쉽습니다. 지금 사용해보세요.


게임의 성과를 개선

런칭한 게임에서 유니티 애널리틱스를 사용하지 않고있다면 사용해보세요. 사용해보기 전에는 그 효과를 모릅니다. Ultrateam은 그들의 게임 디자인을 결정하기 위해 유니티 애널리틱스를 사용하고나서는 "결과는 놀라웠습니다. 이 간단한 적용이 큰 효과를 가져왔습니다."라며 감탄했습니다.


멀티플랫폼 멀티플레이어 네트워킹

유니티 멀티플레이어를 사용해서 네트워크 게임 제작의 고통을 없애세요. 만드는 게임이 모바일이든 데스크톱이든 콘솔이든 기반 엔지니어링 프레임워크는 동일합니다. 유니티 멀티플레이어 릴레이와 매치메이커 서버 서비스를 무료로 이용해보세요.


강화된 VR

5.2에서 프로젝트 모피어스의 빌드 옵션이 추가되었습니다. 이제 오큘러스 리프트, 기어 VR, 프로젝트 모피어스를 기본으로 탑재하여 고도로 최적화된 VR/AR 파이프라인을 갖추게 되었습니다.


강화된 멀티플랫폼

유니티 5.2는 윈도우즈 10과 유니버셜 윈도우즈 플랫폼(UWP) 빌드 옵션을 추가하였습니다. UWP 앱은 핸드폰뽄 아니라 엑스박스 및 PC등 모든 윈도우 기반 기기에서 수행됩니다.


비주얼 스튜디오 통합

유니티 5.2에서 비주얼 스튜디오가 통합되어 윈도우 머신에서의 코딩과 디버깅이 비약적으로 향상되었습니다. 유니티를 위한 비주얼 스튜디오 커뮤니티 2015 툴이 유니티 인스톨러에서 기본적으로 제공됩니다. 


더 많은 정보

유니티 5.2 릴리즈 노트를 확인하여 더 어떤 뉴스들이 있는 지 알아보십시요. 다중 씬 라이트맵 베이킹, 3DS 맥스 바이패드 리깅, 오클루전 컬링 개선 등 많은 변경 사항들이 있습니다.



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

올해 3월, WebGL의 프리뷰(preview) 버전이 Unity 5.0에 포함되어 릴리즈되었습니다. 그 후, 구글은 크롬 브라우저에서의 NPAPI 지원을 중단하였습니다. (기본값) 이는 더 이상 크롬 브라우저에서 Unity Web Player를 실행할 수 없다는 것을 의미합니다. 때문에, 그 대안으로 WebGL을 사용해야만 합니다. 이미 일부 개발자들이 WebGL로 게임을 배포하였습니다만, 기존 Web Player 게임을 WebGL로 포팅하는 데 애로 사항을 겪고 있는 것으로 알고 있습니다. 이는 Web Player와 WebGL은 완전히 다른 플랫폼이기 때문입니다. 웹 브라우저에서 게임을 돌린다는 궁극적인 목적은 동일하지만, 기반 기술은 완전이 다른 플랫폼입니다. 또한 WebGL은 매우 빠르게 성장하고 있기 때문에 시간이 지날 수록 지원 기능들과 상황이 시시각각 다를 것으로 생각합니다.

이러한 이유로, WebGL에 대한 우리의 계획에 대한 이야기를 할 까 합니다. 이 글은 유니티 공식 포럼의 WebGL 로드맵 글을 번역 및 요약한 글입니다.

주의 : 이 글의 모든 정보는 현재의 WebGL 생태계와 계획에 의존하고 있습니다. 이 모든 것들이 미래에는 어떻게 바뀔 지 장담하지는 못합니다. 기능들에 대한 구체적인 릴리즈 날짜를 보장하지는 못합니다. 또한, 일부는 진행하지 않기로 결정 할 가능성도 있습니다. 따라서, 이 글에서 버전이 언급되는 것은 현재의 계획일 뿐이며 미래를 보장하는 것은 아닙니다. (적고보니 보험광고같은 느낌이;;;)


Unity 5.1의 WebGL

5.1에서의 가장 큰 이슈중 하나는 5.0에서 발견 된 버그들을 수정하는 것입니다. 게다가, IL2CPP팀은 지난 몇 개월 간 IL2CPP의 무수히 많은 문제점들을 고치느라 매우 바쁜 시간을 보냈습니다. WebGL은 스크립트 런타임으로 IL2CPP를 사용하다보니 이로 인해 WebGL 플랫폼의 품질도 좋아지게 되었습니다.

또한, Unity 5.1에서의 WebGL 사용자들에게 중요한 이슈 중 하나는 텍스쳐 압축입니다. 텍스쳐 압축을 통해서 전송량 및 용량을 절약하고, 런타임중에 압축을 풀어 GPU 친화적인 DXTn 텍스쳐로 사용합니다. 일반적으로 텍스쳐가 사이즈를 차지하는 주 된 에셋이기 때문에 이를 통해서 WebGL 컨텐츠의 배포 용량을 획기적으로 줄일 수 있게 됩니다.


"프리뷰(Preview)" 레이블

요즘, 프리뷰(preview) 레이블을 언제 제거할 것인가에 대한 질문을 많이 받습니다. 하지만 이에 대해서는 확답을 드릴 수가 없는 상황입니다. 우리는 플랫폼이 안정화 되었다고 판단되어야만 프리뷰 레이블을 제거할 것입니다. 이는 유니티에서의 기술적인 문제 뿐만 아니라 WebGL의 기술 생태계 역시 충분히 준비된 시점을 의미합니다. 그러기 위해서는 브라우저의 개발사들이 우리가 원하는 기능을 구현해주어야만 합니다. 때문에 우리가 기능을 다 구현했다고 프리뷰 레이블을 제거하는 것은 말이 안되는 행위입니다. 우리는 주요 웹 브라우저 업체와 이야기중이고, 우리가 원하는 기능을 위해 최선을 다하고 있다고 믿고 있습니다.


메모리 이슈

현재의 Unity WebGL에서의 가장 큰 이슈중 하나가 메모리 이슈입니다. 특히 크롬 브라우저에서 Unity WebGL을 돌릴 경우 메모리가 낭비되는 현상이 있습니다. 

- 유니티의 WebGL 콘텐츠를 위해서는 연속된 공간의 메모리 블럭이 필요합니다. 이 사이즈는 WebGL Player 셋팅에서 설정할 수 있습니다. 이 사이즈는 리소스를 로드하면서 필요한 메모리 공간 만큼 충분히 확보되어야 합니다. 메모리 프로파일러를 통해서 공간이 어떻게 쓰이고 있는 지 디버깅 가능합니다. 이는 웹브라우저의 힙(heap) 메모리에 연속적인 공간이 필요합니다. 브라우저의 메모리가 낮게 잡혀있거나 힙이 파편화(fragmented)되어 있는 경우 메모리 할당이 실패해버립니다.

- 브라우저는 자바스크립트(JavaScript)를 파싱하는 과정에서 많은 메모리를 사용합니다. Unity WebGL Player로부터 파생된 자바스크립트 코드는 다른 것에 비해 매우 큰 메모리 공간을 소모합니다. 그리고, 자바스크립트 VM은 이러한 코드들을 분석하는 과정에서 매우 많은 양의 메모리를 필요로합니다. 득히, 크롬 V8은 때때로 이러한 이슈때문에 크래시가 일어나곤 합니다. 반면 파이어폭스는 asm.js로 AOT 컴파일을 수행하기 때문에 비교적 적은 메모리를 사용합니다.

이러한 이유들로 메모리 문제는 가장 큰 이슈이긴 합니다만 고치는 것이 쉽지가 않습니다. 현 시점에서는 우리가 할 수 있는 것은 결과 코드 사이즈를 줄이는 것 뿐입니다. 우리는 사내 워크샵에서 이러한 문제를 고민하였으며, 배포 사이즈를 1.2M까지 줄이는 데 성공하였습니다. 코드 스트리핑을 강화하고 컴파일러 설정을 개선하고 불필요한 코드를 제거 하는 등의 작업을 하였으며 이는 계속 개선해 나갈 것입니다. 이러한 개선 사항들은 5.2에 적용될 것으로 예상합니다. 또한 빌드에 포함된 코드 모듈을 시각적으로 확일 할 수 있는 툴을 만들고 있습니다. 얼마나 많은 코드들이 어떤 것에 의해 생성이 되었는 지 등을 확인할 수 있게 됩니다. 이 툴은 빨라야 5.3은 되어야 적용 될 것입니다. 이를 통해서 빌드 결과 사이즈를 줄일 수 있을 것입니다. 결과물의 코드 사이즈가 줄어들면 코드 파싱 시간이 줄어드는 만큼 구동 시간이 빨라지게 될 것입니다.

궁극적으로는, 브라우저의 기술 발전이 메모리 이슈를 훨씬 더 많이 해결할 수 있을 것으로 기대하고 있습니다. 모든 브라우저들이 64비트로 만들어지고 있으며 더 큰 메모리 공간을 사용할 수 있게 됩니다. 또한, 더 중요한 것은, 모질라, 구글, 마이크로소프트가 웹어셈블리(WebAssembly)라 불리우는 신기술을 만들고 있다는 것입니다. 이는 asm.js를 바이트코드(ByteCode) 포맷으로 패킹함으로써 매우 효과적으로 네이티브 코드로 컴파일 될 수 있게 합니다. 이를 통해서 로드 시간과 메모리 오버헤드와 배포 사이즈를 획기적으로 개선시킬 수 있습니다.


데이터 압축

앞서서 메모리 이슈를 언급했 던 것 처럼, 배포 사이즈도 Unity WebGL에서 중요한 이슈입니다. 배포 사이즈는 다운로스 시간과 메모리 사용량에 영향을 미칩니다. 사용할만한 다운로드 속도가 나오려면 데이터를 압축한 상태로 전송해주어야 합니다. 현재로써는 http 프로토콜이 지원하는 gzip 압축에 의존하고 있습니다. 하지만, 이는 종종 서버 사이드의 작업이 필요로하기때문에 불편함이 따릅니다. 게다가, gzip은 현대의 압축 알고리즘에 비해 효율성이 떨어집니다.

미래에는(스케쥴상으로는 Unity 5.3), Unity 자체적으로 에셋 데이터 파일 압축을 모든 플랫폼에서 지원할 것입니다. http 압축에 의존해있던 것을 제거하고 자체적인 압축을 코드상으로 구현할 것입니다. 이로써 WebGL 콘텐츠를 더 빨리 받아볼 수 있게되고, 데이터가 메모리상에 압축된 상태로 머무르는 것이 가능해집니다. 이로 인해서 에셋 로딩 속도도 빨라지고 메모리 대역폭도 줄어들게 됩니다.


성능(Performance)

작년에 작성 한 WebGl 벤치마크 포스팅에서 브라우저와 네이티브 런타임의 성능 비교를 하였습니다. 어떤 영역에서는 괜챦은 성능을 보였었고, 어떤 영역에서는 훨씬 큰 성능 차이를 보여주었습니다. 우리는 이러한 성능 차이를 줄이고자합니다. 큰 성능 차이는 SIMD 및 멀티-스레딩(multi-threading)을 활용함으로써 줄일 수 있습니다. 애석하게도 현재 시점의 WebGL에서는 이들을 사용하는 것이 불가능하지만 다음과 같이 개선 될 예정입니다.

- SIMD : SIMD.js를 통해서 자바스크립트에서 SIMD를 지원할 수 있습니다. 모질라, 구글, 마이크로소프트 모두 이를 지원할 계획을 가지고 있습니다. 현재 다른 플랫폼들이 SIMD를 이용해서 퍼포먼스를 향상시키듯이 WebGL도 SIMD를 활용하면 퍼포먼스가 향상될 것입니다.

- 공유 배열 버퍼(Shared Array Buffers) : 공유 배열 버퍼(Shared Array Buffers)는 WebWorker(자바스크립트에서의 멀티스레드와 같은 역할)가 메모리를 공유할 수 있게 합니다. 이로 인해 기존 멀티스레드 코드를 자바스크립트로 컴파일하는 것이 가능해집니다. 모질라에서는 이미 Unity WebGL 콘텐츠를 멀티스레딩으로 돌리는 것에 성공하였고, 구글 역시 공유 배열 버퍼를 지원할 계획이라고 발표하였습니다.


모바일 지원

모바일에서 WebGL을 지원할 것이냐는 질문도 많이 받고 있습니다. 현재 우리는 모바일에서 구동하는데 방해가 되는 작업을 따로 하고 있지는 않지만, 모바일 최적화를 위한 작업도 따로 하고 있지는 않습니다. 때문에, 고성능의 최신 안드로이드 기기에서는 잘 돌아가겠지만 대부분의 보급형 기기에서는 그렇지가 않을 것입니다. 앞서 언급한 성능 향상 작업들이 모바일에서도 효과를 발휘한다고는 기대하지 않고 있습니다. 때문에, 모바일 지원에 대한 일정에 대해서는 말씀 드릴 것이 없는 상황입니다.


빌드 시간

또 다른 이슈로는 WebGL 빌드가 오래 걸린 다는 것이 있습니다. 모질라는 현재 엠스크립튼(Emscripten) 컴파일러 툴체인을 네이티브 코드로 옮기는 작업을 진행중입니다. 이를 통해서 빌드 시간이 상당히 개선될 것으로 기대하고 있습니다. 이미 Unity 5.1에서는 자바스크립트 최적화가 네이티브로 옮겨진 버젼의 엠스크립튼(Emscripten)이 탑재되서어 5.0에 비해 빌드 속도가 개선되었습니다.


오디오

다른 플랫폼들은 오디오 시스템을 FMOD를 이용하는 반면, 현재의 Unity WebGL은 Web Audio를 기반으로 자체적인 오디오 시스템을 구현하였습니다. 때문에, 현재로써는 기본적인 플레이백(playback)이나 볼륨 및 피치(pitch) 조절 등이 지원 될 뿐 그 이상의 고급 기능은 지원되지 않습니다. 이러한 상황은 Unity WebGL의 스레드 지원이 가능하기 전 까지는 변치 않을 것입니다. 스레드가 지원되면 FMOD 라이브러리를 WebGL로 컴파일 할 수 있게되고 원하는 모습에 가까워 질 수 있습니다. 하지만, Web Audio(“Audio Workers”)의 스펙인 오디오 데이터 워커 API 또한 필요합니다. 하지만 이 기능이 구현 된 브러우저는 아직 존재하지 않습니다. 따라서, 완전한 오디오 기능이 지원되려면 오랜 시간이 걸릴 것으로 예상합니다.


그래픽

WebGL은 OpenGL ES 2.0에 기반을 두고 있는 자바스크립트 API입니다. OpenGL ES 2.0은 많은 제약 사항이 있기 때문에 다른 플랫폼에 비해 제한된 그래픽 기능을 가지고 있음을 의미합니다. 또한, 유니티는 현재 어떤 그래픽 API에서 어떤 그래픽 기능을 사용하는 지에 대해 결정하는 부분이 하드코딩으로 되어있습니다. 이 과정 중에서 OpenGL ES 2.0은 모바일에서 돌아간다고 가정하고 있습니다. 하지만 WebGL은 고성능 데스크톱 GPU에서 구동될 수가 있으므로 이러한 가정은 더 이상 유효하지가 않습니다. 이로 인해 원래 가능한 것 보다는 시각적인 퀄리티가 떨어지는 결과를 초래합니다. 특히 스탠다드 쉐이더와 그림자등이 대표적인 예가 될 것입니다. 우리는 이러한 하드코딩을 걷어내고 쉐이더 품질 등을 프로젝트 별 설정할 수 있는 기능을 만들고 있습니다.

또한, GDC 2015에서 우리는 WebGL 2.0(OpenGL ES 3.0 기반)에서 돌아가는 Unity5의 프로토타입을 시연한 바 있습니다. 이는 WebGL의 그래픽 성능을 한 단계 끌어올린 것입니다. Unity 5.2에서는 WebGL 2.0 지원이 실험적으로 적용될 것입니다. 다만, 브라우저들이 실제적으로 이 API를 올해 안에는 릴리즈 버전에 포함하지는 않을 것으로 생각합니다.


브라우저 지원

현재로써는, Unity WebGL은 크롬, 파이어폭스, 사파리를 지원합니다. 주요 브라우저 중 마이크로소프트의 브라우저는 제외 된 상태입니다. 인터넷 익스플로러의 현재 버젼이 WebGL을 지원하긴 하지만 Web Audio에 대한 지원이 빠져있습니다. 또한, 성능도 썩 좋지 않다보니 우리의 공식 지원 대상에서 제외되었습니다.

마이크로소트의 새로운 브라우저인 Edge에서는 이러한 점이 개선됩니다. Edge는 IE를 대체하여 Windows10에 기본 브라우저로 탑재됩니다. Edge에서는 Web Audio가 탑재되고 asm.js가 지원되어서 높은 성능으로 Unity 콘텐츠를 구동시킬 수 있습니다.


비디오

Unity의 MovieTexture 클래스는 현재 WebGL에서 지원되지 않습니다. MovieTexture는 현재 WebGL의 오디오 솔루션에서 오디오 플레이백이 불가능한 관계로 현재로써는 이에 대한 계획이 없는 상태입니다. 게다가, 브라우저의 html5 비디오 기능을 이용하면 완벽한 비디오 텍스쳐 솔루션을 Unity WebGL에서 손쉽게 이용 가능합니다.


네트워킹

현재 System.IO.Sockets.*과 UnityEngine.Network.*는 WebGL에서 동작하지 않으며 앞으로도 마찬가지 일 것입니다. 이는 플랫폼에서 보안상의 문제로 IP 소켓에 직접 접근하는것이 불가능하기 때문입니다. 대신, WWW는 이용 가능합니다. 또한, 자바스크립트를 이용하여 Web Socket이나 WebRTC를 통합하는 방법도 있습니다. 아니면, Unity 5.1부터 내장되어있는 멀티플레이어 기능을 활용할 수도 있고, 포톤(Photon)이나 스마트폭스서버(SmartFoxServer)같은 서드 파티 라이브러리를 활용하는 방법도 있습니다. 이들 모두 WebGL에서 WebSocket을 이용합니다.


쓰레드

앞서 성능 섹션에서도 언급하였듯이, 브라우저가 공유배열버퍼(Shared Array Buffer)기능을 지원하게되면 우리는 내부 엔진 코드에 멀티 스레딩을 적용할 예정입니다. 또한, 최종적으로는 사용자 System.Threading.*등을 이용하여 사용자 코드에서 멀티스레딩을 활용할 수 있도록 하는 것이 우리의 목표입니다. 하지만, 공유배열버퍼(Shared Array Buffer)는 GC가 필요한 일부 기능들을 제공하지 않는 등 꽤 까다로운 문제들이 있습니다. 우리는 이 문제를 풀기위한 고민을 계속 하고 있으며 언젠가는 기능이 구현 될 것입니다. 다만, 엔진 내부에 멀티스레딩이 적용 된 이후에나 될 것입니다.



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


Variation

게임에는 기본적으로 플레이어가 존재하고, 그 플레이어에게 방해가 되는 장애물이 존재합니다. 퍼즐류가 아닌 이상 이러한 장애물은 몹 또는 몬스터의 형태로 나타나게 되고, 게임의 재미를 좌우하는데 결정적인 역할을 하는 존재가 됩니다.

이미지 : 엔젤 스톤

이러한 몹의 종류가 적으면 사용자는 금새 지루해지게 됩니다. 때문에, 개발자는 매우 다양한 모습과 패턴을 갖도록 만들어야 합니다. 예를 들어 좀비 형태의 몹을 만든다 가정했을 때, 모자를 쓴 좀비, 창을 든 좀비, 뚱뚱한 좀비 등등 좀비라는 큰 카테고리 안에서도 다양한 모습의 좀비를 만들어내야 합니다. 이를 흔히 "다양화(variation)시킨다" 라고 표현합니다.

이미지 : PVZ

하지만 이 때 문제는 리소스의 용량 크기입니다. 완전히 각각의 종류마다 완전히 새로운 리소스로 따로 따로 제작하게되면 리소스의 크기가 커질 수 밖에 없게 됩니다.때문에, 이러한 다양화(variation) 작업을 거칠 때 리소스를 최소한으로 사용하는 방법을 사용해야만 합니다.


부품 모듈화

그 방법 중 하나가 각각 파츠별로 모듈화 시키는 방법입니다. 각 파츠별로 부품 모듈을 만들어 놓고 프라모델이나 레고처럼 모듈을 조립하여 다양한 모습을 만들어 내는 것입니다. 예를 들어 로보트를 팔, 다리, 몸통, 총구 등으로 나누어 여러 종류로 제작한 뒤 이를 조립하여 다양한 종류의 로보트를 만들어 내는 것입니다. 보통 로보트나 비행기 등 강체로 이루어진 것 들이 이러한 조립식으로 많이 만들어집니다. 에셋 스토어에서도 마찬가지로 이러한 조립식 에셋들을 많이 찾아볼 수 있습니다. 

이미지 : 에셋스토어


텍스쳐 변경

또 다른 방법으로는 텍스쳐만 바꾸는 방법도 존재합니다. 동일한 메시에 텍스쳐만 바꿔서 다른 모습을 연출해주게 되는 것입니다. 주로 인간형 케릭터에게 의상을 다양화 시킬 때 이러한 방법을 사용합니다.  

이미지 : 에셋스토어


파츠 컬러

이 글에서 소개할 또 다른 방법으로는 파츠 컬러를 변경하는 방법입니다. 앞서 방금 언급한 텍스쳐를 바꾸는 방식이나 메시 모듈들 조립하는 방식과는 달리, 메시와 텍스쳐는 교체하지 않고 하나의 텍스쳐와 하나의 메시만 사용하는 방식입니다. 때문에 앞서 언급한 방식들에 비해서 리소스를 크게 아낄 수 있습니다. 다만, 텍스쳐를 통채로 바꾸는 것이 아니기 때문에 전체적인 패턴과 모양은 그대로 유지하기 때문에 한계가 있습니다. 대신 전체적인 혹은 부분적인 색상을 바꿀 수 있기 때문에 주로 의상의 염색 시스템에서 활용되기도 합니다. 

이미지 : 레이더즈

또한 다양화 작업 말고도 RTS나 MOBA 등 대전 게임에서 팀 구분을 위한 색상으로 활용될 수도 있습니다.

이미지 : 스타크래프트2

이 글에서는 이러한 파츠 컬러 방식을 구현하는 것에 대하여 자세히 설명을 해볼까 합니다. 기본 원리는 간단합니다. 메시의 기본 albedo 색상 외 컬러를 변경할 마스크 영역을 준비합니다. 단순한 파츠 컬러 적용 여부를 나타내는 크레이스케일 값이기만 하면 되기 때문에 albedo 텍스쳐의 알파 채널에 이를 활용하면 됩니다. 물론, 대신 불투명 오브젝트에만 적용이 가능해진다는 제약은 있습니다.

그 예로 다음과 같은 로보트 Kyle에 이를 적용하여 보겠습니다.

이 모델은 불투명으로 만들어져 있어서 실제로는 다음과 같은 albedo 텍스쳐의 RGB만 사용합니다.

이 텍스쳐의 Alpha 채널을 다음과 같이 칠하여 파츠 컬러의 마스킹으로 사용하도록 합니다. 다음 이미지는 GIMP툴에서 보여주는 Alpha 채널의 모습입니다. 검은색이 1을 나타내고 회색의 체크무늬가 0인 영역을 의미합니다.

이 Alpha 채널의 역의 값을 마스킹으로 사용하여 (위 이미지의 회색 체크무늬 영역이 파츠 컬러가 되도록) 적용하는 것이 최종 목표입니다. 샘플 프로젝트를 올려두었습니다. 이 링크를 통해 다운받으셔서 확인해보실 수 있습니다.

쉐이더가 적용 된 마테리얼에서 Parts Color 색상을 변경할 수 있습니다.

이 색상을 바꾸면 이에 따라서 로봇의 파츠 컬러가 변경되어 보여집니다.


이 방식은 원리도 간단하기 때문에 쉐이더 코드도 크게 복잡하지 않습니다. 샘플 프로젝트에 포함 된 LambertUseColorPart.shader를 살표보도록 하겠습니다.

27번째 라인에서 albedo 텍스쳐의 값을 읽은 뒤 29번째 라인에서 alpha 채널의 값을 뒤집어줍니다. 이는 작업자의 성향에 따라 파츠 컬러 적용 값을 1로 둘것인가 0으로 둘 것인가에 따라 다릅니다. 머티리얼의 Invert Parts Color Mask 체크 여부에 따라 수행 여부가 달라집니다.

35번째 라인이 이 쉐이더의 핵심 구문입니다. 파츠컬러의 마스킹 값에 따라서 흰색과 지정된 색상 값을 보간합니다. 그후 그 값을 albedo와 곱하여 최종 albedo 값을 결정합니다. 결과적으로, 마스크가 1이면 albedo에 지정 컬러를 곱한 결과가 됩니다. 반대로 마스크가 0이면 원래의 albedo 색상을 그대로 사용합니다.

만일 머티리얼에서 Interpolated Parts Color가 체크되어 있다면 35번째 라인 대신 33번째 라인이 수행됩니다. 이는 albedo값과 지정 색상 값을 바로 보간합니다. 이는 흰색과 보간한 뒤 albedo에 곱해주는 결과와는 미묘한 차이를 가집니다.

다음 로보트의 몸통 이미지는 각각 33번 라인과 35번 라인을 수행 했을 때의 차이를 보여주고 있습니다. 첫 번 째 이미지는 35번 라인이 수행된 모습입니다. albedo와 곱하여 사용한 결과이기 때문에 albedo 자체에 새겨놓은 AO 라이팅이나 얼룩등이 그대로 살아있습니다. 만일 텍스쳐 자체에 라이팅이나 AO등을 새겨놓는 식으로 작업한다면  Interpolated Parts Color가 비활성화 되어야합니다.


이 두 번 째 이미지는 그 반대로 33번 라인이 수행된 모습입니다. albedo와 바로 보간해서 사용하기 때문에 마스크가 1인 영역은 albedo 텍스쳐의 모습을 완전히 없애버립니다. 첫 번 째의 이미지와는 달리 몸통에 페인트가 덧 칠해진 것 같은 느낌입니다. PBS 대응 텍스쳐는 albedo에 AO 및 라이팅이 포함되어서는 안되기 때문에, 만일 PBS 대응으로 작업하는 이미지라면 이 모습이 용이할 수도 있습니다. (예를 들어서 금속 물질 위에 칠해져있는 페인트가 벗겨져 있는 모습이라면) 



한계

이 쉐이더는 알파채널을 이용하여 한번에 한가지 색상만 적용합니다. 웬만한 경우에서는 한 가지 색상만 적용해줘도 크게 무리는 없습니다. 만일 푸품 모듈화 방식과 같이 사용한다면 더 다양한 조합을 만들 수도 있을 것입니다.

하지만 단일 메시만 사용하는 경우라면 단일 색상만 적용 가능 한 것이 조금 답답할 수도 있겠습니다. 그러한 경우에는 albedo 텍스쳐의 alpha 채널을 마스크로 활용하는 것이 아니라, 아예 마스크 텍스쳐를 별도로 제작하면 더욱 다양하게 활용이 가능합니다. 색상을 4가지를 지정하고 마스크 텍스쳐의 r,g,b,a 채널 모두 각각의 마스킹으로 활용하면 4가지 색상을 적용할 수 있습니다. 다만 추가적인 텍스쳐가 사용되므로 약간의 성능 감소는 있을 수 있습니다. 그렇다 하더라도 잘만 조작하면 적은 텍스쳐 메모리만으로도 훨씬 다양한 다양화(variation) 효과를 볼 수 있기 때문에 충분한 가치가 있습니다.

쉐이더 작성이 익숙하신 분이라면 쉐이더를 직접 수정하여 사용하시면 되고, 그렇지 않은 분이시라면 에셋 스토어에서 받아서 사용하시면 됩니다. 이 에셋이 제가 설명드린 것과 비슷한 작동을 수행하는 쉐이더를 사용하고 있습니다. ( 사실, 컬러 4개 지정하는 쉐이더를 올릴 까 했는데, 이 에셋이 유료로 판매되는 것을 보고나니 상도덕(?) 상 그러지를 못하겠네요;;)

이미지 : 에셋스토어


샘플 프로젝트 다운로드 링크 : https://drive.google.com/file/d/0B70AOyGiQJsGY2dEakU4Y2Q4WWs/view?usp=sharing



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

게임은 어떻게 만드나요?

라는 질문에 뭐라고 대답해야 할까요? 누군가는 어떤 말을 해야할 지 고민을 할 테고, 누군가는 쌍욕부터 할 지도 모르겠습니다. 어찌되었건 이런 질문을 받았을 때 공통적으로 느끼는 감정은 '혼란'일 것입니다. 대답해주려니 막막하고 어디서부터 풀어나가야 할 지 혼란스러워진다는 것입니다. 질문을 받은 사람이 이러한 감정을 느끼는 원인은 간단합니다. 바로 질문 자체가 막연하기 때문이죠.

제가 뜬금없이 이런 질문을 언급하는 것이 의아하실지도 모르겠습니다. 이런 질문을 하는 사람이 있을까 싶으시겠지만 실제로 인터넷 커뮤니티(특히 뇌입어)에 많이 올라오는 질문 중 하나입니다. 사실 이러한 비(非)개발 커뮤니티는 이런 허접한 질문이 올라올 수도 있다는 생각이 들 수도 있겠습니다. 하지만, 중요한 것은 개발 관련 포럼이나 커뮤니티에도 이러한 수준의 질문이 가끔 목격된 다는 것입니다. 제가 다소 공격적으로 "수준"이라는 표현을 사용했지만, 여기서 말하는 "수준"이라는 것이 별 뜻은 아닙니다. 질문 내용의 기술적인 난이도가 낮아서 수준이 낮다고 표현하는 것이 아닙니다. 기술적인 수준은 낮아도 질문 자체의 수준이 높은 경우는 얼마든지 많습니다. 제가 말하는 "수준이 낮다"고 표현하는 것은 질문 내용에 성의가 없기 때문입니다. 

예를 들어서 누군가 다음과 같은 질문을 올렸다 생각해보겠습니다.

광선검은 어떻게 만드나요?

이 질문이 뭐가 문제인지 의아해하시는 분도 계실지도 모르겠습니다. 하지만, 제가 보기에는 이 질문이 앞서 언급하였던 게임을 어떻게 만드냐에 대한 질문과 다를 바가 없어보입니다. 마찬가지로 막연하고 정보가 부족하기 때문입니다. 이로 인해서 받아들이는 사람 마다 질문의 의도를 각자 다르게 해석하고 각자 다른 초점의 정보를 말해주게 될 것입니다. 

"광선검"이라는 단어를 들으면 어떤 사람은 스타워즈의 라이트세이버를 떠올릴 것이고 어떤 사람은 건담의 빔샤벨을 떠올릴 것입니다. 

어떤 사람은 모바일 타겟으로 파티클로 빔샤벨을 만드는 방법을 안내할 것이고 어떤 사람은 PC 타겟으로 이미지 블룸 효과를 처리하는 방법을 안내할 것 입니다. 어떤 사람은 그래픽 리소스를 제작하는 방법을 안내할 것이고 어떤 사람은 손잡이에서 빔이 나오는 에니메이션 처리를 수행하는 스크립트를 안내할 것입니다. 이처럼 질문부터가 모호하고 정보가 없으면 질문자와 답변자 모두에게 만족으러운 결과를 도출하지 못하게 될 것입니다. 이는 당연한 결과입니다.

하지만, 의외로 이러한 모호한 질문들이 생각보다 많이 발견됩니다. 물론 예를 들어 말씀드린 질문은 극단적인 예일 뿐이고 사실 더 많은 정보를 포함한 질문들이 대부분입니다. 하지만 여전히 적은 정보만으로 모호한 질문을 물어보는 글들이 많이 보이곤 합니다. 비단 유니티 관련 포럼 뿐 아니라 언리얼, 코코스 등 다른 엔진 관련 포럼에도 나타나는 현상들이고 게임 뿐 아니라 개발 관련 된 커뮤니티라면 어디에서든지 존재하는 현상들입니다.

때문에 질문을 올리는 방법에 대한 가이드를 말씀드리고자 합니다. 물론 이 글이 객관적인 것은 아니며 어떤 기관에서 표준으로 인정한 양식도 아닙니다. 단지 제 개인적인 경험과 노하우를 통해 말씀드리는 것이니 절대적인 가이드라기보다는 참고사항으로만 생각해주시면 감사하겠습니다. 


육하원칙

기본적으로, 육하원칙(5W1H)을 생각하시면 됩니다. 누가,언제,어디서,무엇을,어떻게,왜 육하원칙은 초등학교에서  기본적으로 배우는 만큼 기초적이고 중요한 원칙입니다. 대부분의 질문은 이 육하원칙에서 한가지를 도출하는 과정이 될 것입니다. 어떠한 현상이 왜 생기는지를 물어보고자 한다면 나머지 다섯가지인 누가,언제,어디서,무엇을,어떻게에 대한 정보가 제공이 되어야 할 것입니다. 반대로 어떻게 해야하는지를 물어보고자 한다면 나머지 다섯가지인 누가,언제,어디서,무엇을,왜가 제공이 되어야 할 것입니다. 무조건 이 여섯가지 요소를 반드시 지켜야 한다는 것은 아닙니다. 질문에 따라서 모든 요소가 들어갈 필요는 없는 경우도 있습니다. 다만, 가능한 이 원칙에 입각하여 질문을 작성한다면 크게 모호해질 일은 없을 것입니다. 물론, 이 요소들을 명시적인 도표로 만들어서 작성하거나 하라는 것이 아닙니다. 글의 문맥 안에 이러한 요소들이 명시적이나 암묵적으로 포함되기만 하면 됩니다. 사실, 각각의 요소들에 대한 명확한 기준은 없습니다만 각각의 요소에 주로 담기게 되는 내용을 설명드려볼까 합니다.


누가(who)

"누가"는 대부분 질문자 본인이라 생각 할 수도 있습니다만 당연히 질문자가 이름이 뭔지 거주지가 어딘지따위는 중요하지 않습니다. 중요한 것은 직군이 어디인지 지식 수준이 어느정도 인 지 입니다. 그래야 어느정도 레벨까지 설명을 해 줘야 할 지 가늠할 수 있기 때문입니다. 다만 이러한 것은 질문 내용에서 간접적으로 표현 되는 경우가 많아서 명시적으로 언급해주지 않아도 되는 경우도 많습니다. 예를 들어서 NavMesh.Raycast()의 성능에 대해 물어는 글이 있다 치면, 그 질문의 작성자는 일단 프로그래머이일 것이며 네비게이션 메시에 대한 기본 지식은 가지고 있다고 가정해도 무방할 것입니다. 또한, "누가"는 사람에만 국한 되는 것이 아니라 시스템의 객체가 될 수도 있고 오브젝트의 인스턴스가 될 수도 있는 등 다양한 시각으로 반영될 수 있습니다.


언제(when)

"언제"는 몇시 몇분 몇초의 절대적인 시간이 아니라 재현 시퀀스의 타이밍이 되는 경우가 대부분입니다. "버튼을 세번 눌렀을 때" 혹은 "앱이 수행되자마자 항상" 등 재현 시퀀스상의 시간이 될 수도 있습니다. 때문에, "어떻게"와 같이 묶여서 표현 될 수도 있습니다. 


어떻게(how)

그렇다고해서 "언제"와 "어떻게"가 동일하다는 이야기는 아닙니다. "어떻게"는 주로 구현 방법에 대한 설명이 되는 경우가 많습니다. 어떤 기능을 어떻게 구현했냐에 대한 설명이 대부분일 것입니다. 주로 이 부분에 대한 설명이 자세할 수록 좋습니다.

구현을 어떻게 했고 무엇이 문제인 지에 대한 설명은 사실 말로만 설명하기에는 부족한 경우가 많습니다. 이러한 경우에는 보조적인 자료를 사용해주는 것이 좋습니다. 특히 코드에 관한 것을 물어볼 때에는 반드시 소스 코드가 포함되어야 합니다. 무슨 함수를 어떻게 썼다라는 것을 말로만 설명하는 것이 아니라 해당 코드를 반드시 올려주어야 합니다. 더 나아가서 프로젝트를 올려주시면 정확한 판단을 하기가 훨씬 수월해집니다. 포럼 사이트나 게시판마다 파일 업로드 용량 제한이 달라서 프로젝트 파일을 직접 올리지 못하는 경우가 대부분입니다. 구글 드라이브나 드랍박스에 파일을 올린 후 링크를 걸어두시는 식으로 하면 여러 커뮤니티에 질문을 올릴 때 유용합니다. 물론 프로젝트를 올려두었다 하더라도 문의하고자 하는 부분의 핵심 코드는 본문에 포함되어야 합니다.


어디서(where)

"어디서"는 말 그대로 문제가 발생하는 위치입니다. PC나 모바일 등 물리적인 위치가 될 수도 있고, 어느 클래스 어느 함수에서 발생하는 지 등의 논리적인 위치가 될 수도 있습니다. 위치 역시 최대한 자세히 적어주시는 것이 좋습니다. 예를 들어서 모바일 기기에서만 발생하는 문제라면 단순히 "모바일 기기"라는 표현으로 끝내는 것이 아니라 해당 기기의 모델명과 OS 버젼 등은 필수적으로 기입되어야합니다.


무엇을(what)

"무엇을"은 6가지 요소 중 가장 중요한 요소가 될 수도 있습니다. 구현하고자 하는 것이 무엇인 지 혹은 문제가 발생하는 현상이 무엇인 지 등 원하는 것이 정확히 기술되어야 합니다. 

어느날 사장님이 오셔서 이런 말을 했다고 가정해보겠습니다.

보스를 추가하고싶은데 메카닉이면서도 허접해보였으면 좋겠어. 또한 모던하면서도 클래식한 느낌이 나야해

이 말만 툭 던지고 자리로 돌아간다면 사장이고 뭐고 다 때려엎고 싶을 지도 모릅니다. 설명이란 것은 자세하면 자세할 수록 좋습니다. 여기서만큼은 과유불급이란 것은 존재하지 않습니다. 하지만 사실 아무리 말로 잘 표현하더라도 정확한 표현을 하는데에는 한계가 있을 수 있습니다. 백마디의 말 보다는 한장의 이미지가 더 효과적이라는 것을 항상 염두해두시길 바랍니다. 이까 그 사장님이 다시 돌아와서 다음과 같은 이미지를 던져주고 간다면 그나마 화가 조금은 풀릴 지도 모르겠습니다.

왜(why)

"왜"는 불필요한 정보라고 느낄 수도 있겠지만 이 역시 상당히 중요한 정보입니다. 만일 특정 함수의 오류에 대해 문의하는 것이라면 왜 그 함수의 사용 의도가 파악되어야 합니다. 그래야만 의도하는 방향 내에서 해결책을 제시할 수 있습니다. 또한, 용도에 맞지 않는 사용법으로 사용하는 것을 막을 수도 있습니다. 혹은, 더 나은 방법이 제시 될 수도 있습니다. 예를 들자면, 주기적인 타이밍으로 들어가는 도트데미지를 Update() 함수에서 구현하는 방법에 대한 문의를 한다면 코루틴을 사용하는 것으로 제안 할 수도 있을 것입니다.


아웃라인(outline)

육하원칙 외에도 글의 아웃라인을 서론과 본론으로 갖춰주시는게 좋습니다. 글을 자세히 적다보면 글이 길어질 수 밖에 없는데 서론 없이 바로 본론으로 들어가버린다면 질문에 대한 집중력이 떨어질 수 밖에 없습니다. 그렇다고 너무 아웃라인의 형태에 집착하지 않아도 됩니다. 글의 도입부에서 어떤 주제에 대한 질문인지 대략적으로 밝히고 진입하는 정도만 되어도 충분한 아웃라인을 갖추었다고 봐도 무방합니다.


퇴고

사실, 육하원칙이니 글의 아웃라인이니 그런 것 보다는 퇴고가 가장 중요합니다. 글을 길게 썼든 짧게 썼든 글을 최종 업로드 하기 전에 퇴고를 반드시 거쳐주시길 바랍니다. 제3자의 입장으로 글을 다시 한번 읽어가면서 내용이 이해가 가는지를 판단해보십시요. 의외로 자신이 글을 이해가 가지 않게 썼다는 것을 발견 하는 경우가 많을 것입니다.

이렇게까지 많은 것을 고려하면서 질문글을 써야하나 하는 의문을 제기하는 분도 간혹 계십니다. 물론 질문이란 것이 가볍게 던질 수도 있는 것입니다. 다만 자세한 질문을 할 수록 더 나은 답변과 토론이 오갈 수 있을 것이라 생각합니다. 또한, 질문을 적는 사람은 개인이지만 질문은 많은 사람들이 읽습니다. 더 많은 사람들이 더 많은 시간을 투자해서 함께 고민하는 것이기 때문에 질문 글에도 그만큼의 정성이 들어가는 것이 예의라고 생각합니다.


다시 광선검

마지막으로 다시 광선검을 예로 들어보겠습니다. 

광선검은 어떻게 만드나요?

라는 표현은 다음과 같이 바꿀 수 있겠습니다.(실제의 문의 내용이 아니라 제가 가상으로 작성한 글입니다.)

안녕하세요. 광선검의 검흔 효과 구현에 대한 조언좀 구하고자 문의글을 올립니다. 저희가 모바일 액션 RPG를 만들고 있습니다. D&D나 던파같이 사이드뷰인데 배경이 미래다보니 스타워즈 광선검이 무기로 등장합니다. 광선검 자체를 만드는 것은 문제가 없었습니다만 검흔 효과를 만드는데 애를 먹고있습니다.

검광 부분은 막대기 모델에 따라서 검광 텍스쳐 판때기 2개를 X자로 교차되게 간단하게 만들었습니다. 케릭터에게 쥐어줘보니 뭐 그럴싸합니다. 모바일이라 화면도 작은데다가 광선검이 클로즈업되서 보일 일이 없다보니 판때기로 박은게 티가 잘 안납니다. 근데 단순히 이것만 가지고 검을 휘둘러보니 뭔가 어색합니다. 영화에서 보면 검을 휘두르면 삼각형 모양의 블러가 생깁니다. 게임에서 이런게 안생기니 심심한 느낌입니다.

저는 단순 모델러라 이펙트를 잘 모릅니다. 신생팀이라 이펙터도 따로 없구요. 그래서 옆자리 프로그래머랑 같이 에셋스토어 뒤져서 trail 이펙트를 붙여봤는데 영화에서의 느낌은 나지 않네요. 그냥 일반적인 무협 게임의 검기같은 느낌일 뿐 광선검 특유의 느낌이 나지 않습니다. 검흔 자체가 불투명이어야하는데 빨간 화살표처럼 투명 그라데이션이 들어갑니다. 전체적인 헤일로 효과 없이 노란색 화살표처럼 검 진행 방향의 단면이 선명하게 떨어져버리구요. 영화에서는 순간적으로 검의 모양이 부채꼴로 변하는 듯한 느낌이라 이 이펙트와는 전혀 다른 느낌입니다. 

영화에서의 느낌을 내려면 어떤식으로 구현해야할 지 아니면 어떤 에셋을 사용해야 할 지 조언좀 부탁드립니다. 혹시 몰라서 파일을 올려두었습니다. 프로젝트라 광선검 부분만 따로 패키지로 추출한 점 양해 부탁드립니다.

다운로드 링크 : 어쩌고저쩌고

감사합니다 :)


P.S. 먹튀는 악질 행위입니다. 가끔 답변을 받으면 답변만 확인하고 질문들을 삭제하는 분도 계시는데 이러한 행위는 비매너 행위입니다. 커뮤니티는 다른 사람들과 정보와 노하우를 공유하는 공간입니다. 혼자만 알고싶으면 애초에 커뮤니티에 질문을 올리는 것 부터가 모순이라는 점을 말씀드리고 싶습니다.


로보트 이미지 출처 : Stephane Halleux

게임 trail 효과 이미지 출처 : SWTOR



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

유니티 5.1부터는 unity analytics가 기본적으로 통합되었습니다. 더 이상 플러그인을 사용하지 않아도 됩니다. 오히려 기존 플러그인은 제거하시는 것을 추천합니다. 다만 이로 인해서 사용법이 조금 바뀌었습니다.https://analytics.cloud.unity3d.com > 좌측 메뉴 INTEGRATION > 우측 상단의 5.1 에서 확인 가능합니다.

이 내용을 참고로 바뀐 점을 요약해보자면 다음과 같습니다.

우선, 프로젝트 아이디를 터이상 코드로 적지 않습니다. 대신 플레이어 셋팅에 아이디를 적게 되었습니다. 따라서 UnityAnalytics.StartSDK() 함수가 제거됩니다.

또한, 인터페이스 이름이 변경되었습니다. 기존 UnityAnalytics 에서 UnityEngine.Analytics 으로 변경되었습니다. 따라서 커스텀 이벤트를 사용하고 계신다면 이 부분 코드를 바꿔주셔야합니다.

이 이외에는 바뀐 부분이 크게 없어서 이 부분만 신경써주시면 무리 없을 듯 합니다.





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

유니티 배우려는데 무슨 언어로 배워야할까요? C#? 아니면 자바스크립트?

가끔 이러한 질문들을 듣곤 합니다. 일단 이 질문에 대한 대답을 먼저 드리자면 당연 C#입니다. 유니티는 C#과 자바스크립트 두 언어를 지원하기 때문에 유니티 입문 시 이 두 언어 중 무엇으로 사용해야 할 고민이 되곤 합니다. 하지만 고민하실 필요 없이 C#으로 선택하시길 추천드립니다. 

이유는 간단합니다. 많은 사람들이 사용하기 때문이죠. 이는 구글트렌드로 살펴보더라도 극병하게 드러납니다. 물론 구글 트렌드가 객관적이고 정확한 기준 자료가 될 수는 없겠지만, 시간이 지날수록 자바스크립트보다는 C#이 대세로 가고 있음을 확인 하실 수 있습니다.

이미지 : 구글 트렌드

그러다보니 당연히 많은 참고 자료들이 C#으로 되어있습니다. 기능 구현이나 알고리즘 자료들 뿐 아니라 각종 플러그인의 샘플들도 C# 위주로 되어있습니다. 물론 언어의 견고함이라든가 방대한 라이브러리등 더 많은 선택 기준이 있겠지만, 입문하시는 입장에서라면 대세가 C#이라는 이유만으로도 충분하리라 생각합니다.

간혹 SI에서 자바를 다루었거나 웹에서 자바스크립트를 다루었다는 이유로 자바스크립트를 선택하려는 분도 계십니다. 하지만 이는 잘못된 판단입니다. 

여기서 잠깐 질문 하나 하겠습니다. 오리와 오리너구리와 KOF이오리의 공통점은 무엇일까요? 

바로 이름에 오리가 들어가는 것입니다. 그것 말고는 서로간에 전혀 공통점이 없습니다. 자바와 자바스크립트와 유니티자바스크립의간의 관계도 이와 마찬가지입니다. 서로간에 전혀 공통점이 없다고 봐도 무방합니다. 문법이 비슷해보이지만 실제로 파고들어보면 전혀 다른 언어들입니다. 그러므로 그런거 신경쓰지 마시고 그냥 C#으로 사용하시는 것을 추천드립니다.



Posted by ozlael
,
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 크기의 광고 코드만 넣을 수 있습니다.

개요

기술이 발전하고 시간이 지남에 따라 그래픽카드 성능 역시 계속 발전해왔습니다. 그 덕에 더욱 놀랍고 사실적인 그래픽을 표현할 수 있게 되어왔습니다. 그 결과 현대의 PC 및 콘솔 게임의 그래픽은 현실과 그래픽을 분간하기 어려울 지경입니다. 이토록 그래픽 카드는 얼마나 더 멋진 그래픽을 얼마나 더 고속으로 처리할 수 있는 지가 가장 큰 이슈이고 이에 초점을 맞추어서 발전해왔습니다.

이미지 출처 : http://www.slideshare.net/ozlael/unitylightingslide-public

하지만 모바일 기기의 그래픽카드는 조금 다른 행보를 갖습니다.  모바일기기는 항상 전원이 연결되어있는 상황이 아니기때문에 전력 소모가 가장 큰 이슈가 됩니다. 또한 휴대가 용이하게 만들어야 하기 때문에 칩셋을 얼마나 물리적으로 작게 만드냐가 관건입니다. 게다가 물리적으로 작게 만드려면 쿨러를 장착할 수가 없기때문에 발열도 큰 문제가 됩니다. 이러한 모바일 기기의 특징들때문에 모바일에서는 Tile Based Rendering(타일 기반 렌더링)이라는 독특한 방식을 사용합니다. 이번 글에서는 Tile Based Rendering에 대해서 알아보고, 유니티에서 Tile Based Rendering을 고려시 주의점에 대해 다루고자 합니다.


Tile Based Rendering

우선 Tile Based Rendering에 대한 설명에 앞서 데스크톱의 렌더링 과정을 간단히 살펴보겠습니다. OpenGL에서 드로우콜을 날리면 지오메트리 데이터가 버텍스 쉐이더를 거쳐서 트랜스폼된 뒤 레스터화되고 픽셀쉐이더로 넘어가서 픽셀 컬러를 거칩니다. 픽셀쉐이더의 결과물은 바로 프레임 버퍼로 출력이 되면서 필요에따라 블렌딩 처리가 됩니다. 이처럼 드로우콜의 명령이 프레임버퍼까지 전달되는 과정이 한번의 패스로 이루어지고 매번 프레임버퍼 영역 전체가 갱신이 됩니다. 즉, 드로우콜 한번 당 한번에 바로 화면 전체에 렌더링합니다. (그래서 이러한 전통적인 렌더링 방식을 Immediate Mode Rendering이라 부르기도 합니다.)

이미지 출처 : http://www.ntu.edu.sg/home/ehchua/

하지만 모바일에서는 조금은 다른 방식을 사용합니다. 앞서 언급하였듯이 모바일에서는 전력 소모와 물리적 크기 등을 고려해야합니다. 이를 위해서 많은 고려사항들이 반영되며 설계가 됩니다만 그 중 가장 큰 고려 사항중 하나가 바로 대역폭입니다. 대역폭을 넉넉하게 쓰다보면 전력소모가 심해지고 물리적 칩셋 크기도 커집니다. 이는 발열로 이어지게 되는데 당연히 발열을 완화시킬 쿨러를 달 공간도 없습니다. 그래서 모바일에서는 대역폭을 줄이기위해 Tile Based Rendering(이하 TBR)이라는 아키텍쳐를 채용하고 있습니다.

앞서 말했던 것 처럼 전통적으로 데스크톱의 그래픽에서는 드로우콜마다 프레임 버퍼 전체를 갱신합니다. 하지만 높은 해상도의 프레임버퍼 전체를 매 번 갱신하는 것은 높은 메모리 대역폭을 요구하게 됩니다. 따라서 모바일에서는 프레임버퍼 전체를 매 번 갱신하는것이 아니라 타일 단위로 쪼개서 갱신을 하는 방식을 사용합니다. 드로우콜 발생 시 즉시 프레임버퍼에 기록하는 것이 아니라, 칩셋에 내장된 메모리에 존재하는 타일에 렌더링합니다. 이로 인해서 매번 화면 전체를 렌더링 하는 것이 아니라 실제 도형이 그려지는 타일만 렌더링 하게 됩니다.

이미지 출처 : Performance Tuning for Tile-Based Architectures

우선, 프레임버퍼를 일정 크기의 타일로 영역을 나눕니다. (이 타일 크기는 칩셋 벤더마다 차이가 있습니다.) 드로우콜이 발생하면 지오메트리 데이터가 버텍스쉐이더를 거쳐서 트랜스폼을 수행 후 레스터화됩니다. 여기까지는 전통적인 렌더링 방식과 동일합니다만 그 이후부터가 달라집니다. 버텍스 쉐이더의 결과가 바로 픽셀 쉐이더로 넘어가지 않고 타일을 선택하는 과정을 거칩니다. 그 후에 픽셀쉐이더가 수행되고 칩 내부 버퍼에 존재하는 타일에 그려집니다. 그 후 타일들이 완성되면 프레임버퍼에 그려집니다. 이런 식으로 타일 단위로 프레임버퍼를 갱신해주기때문에 적은 대역폭으로도 화면을 렌더링 할 수 있게됩니다.

이미지 출처 : http://wenku.baidu.com/view/85ea8fec998fcc22bcd10dcb.html


Tile Based Deferred Rendering

또한, TBR에서 변형되어 파생한 Tile Based Deferred Rendering(이하 TBDR) 라는 방식도 있습니다. 이 방식은 기본적으로는 TBR입니다. 다만 버텍스 쉐이더에서 트랜스폼 연산을 거치고나서 바로 픽셀 쉐이더로 넘기는 것이 아닙니다. 대신 버텍스 쉐이더의 결과를 중간 데이터를 담는 파라미터 버퍼에 담아둡니다. (이 버퍼를 ImgTec에서는 파라미터 버퍼라 부르고, ARM에서는 폴리곤 리스트라 부르는 등 여러 이름이 존재하지만 편의상 파라미터 버퍼로 통일하여 칭하겠습니다.) 이 파라미터 버퍼에 담은 후 픽셀 쉐이더로 바로 넘기는 것이 아니라, 매 드로우 콜 마다 버텍스 쉐이더의 결과를 계속 담아둡니다. 그 후 모든 드로우콜이 끝나면 그때서야 비로소 타일을 렌더링하고 프레임버퍼에 출력합니다. 그렇게되면 한 타일에 들어오는 모든 폴리곤을 한번에 처리 할 수가 있게됩니다. 이 과정에서 타일의 각 픽셀에는 은면제거가 처리되고 나서 도달하기 때문에 픽셀 오버드로우가 발생하지 않습니다. 이러한식으로 TBR을 지연해서 처리하기때문에 Tile Based Deferred Rendering(타일 기반 지연 렌더링)이라고 불립니다. 

이미지 출처 : Unity: iOS and Android - Cross Platform Challenges and Solutions

예전에는 TBDR 방식이 ImgTec의 PowerVR 즉 아이폰과 아이패드에서만 사용되었으나 최근들어서는 다른 칩셋들에서도 사용되고 있습니다. 하지만 여전히 안드로이드 기기는 TBDR보다는 TBR이 많이 사용되고 있습니다. 따라서 현 시점에서는 TBR을 사용하는 디바이스와 TBDR을 사용하는 디바이스가 공존하고 있는 상태입니다. (타일 기반이 아닌 전통적인 렌더링 기법을 쓰는 디바이스는 점유율이 매우 낮아서 논외로 합니다.)

이처럼 모바일에서는 타일 단위로 쪼개서 렌더링하는 방식을 사용하다보니 몇 가지 주의 사항이 존재합니다. 서론이 좀 길어지긴 했는데 결국 전달고자 하는 내용들은 다음과 같습니다.


이어지는 내용 : 

모바일 기기의 Tile Based Rendering(타일 기반 렌더링)과 유니티에서의 주의 사항 #2 : TBR 대응 리소스 제작시 주의점



Posted by ozlael
,