원문 주소 : https://unity3d.com/kr/learn/tutorials/topics/performance-optimization/profiler-window

도입

프로파일링 툴은 우리의 게임이 어떻게 동작하는지에 대한 자세한 정보를 줍니다. 만약 우리 게임에 낮은 프레임율(framerate)이나 높은 메모리 사용과 같은 문제가 있다면, 프로파일링 툴을 통해서 무엇이 이러한 문제를 일으키는지 확인할 수 있고, 이러한 문제를 해결하는데 도움이 될 수 있습니다.

프로파일러 창(Profiler window)은 유니티에 내장되어 있는 강력한 프로파일링 툴입니다. 이 글은 프로파일러 창이 무엇이고 어떻게 사용하는지에 대한 가이드가 되어줄 것 입니다. 일단 이 글을 읽고 프로파일러 창의 레이아웃과 기능에 익숙해지고나면, 다른 종류의 성능 문제를 분석하기 위해서 프로파일러 창을 어떻게 사용하는 지를 배우게 될 것 입니다.

프로파일러 창은 우리 게임의 다른 부분들이 어떻게 돌아가고 있는지에 대한 심도있는 정보를 보여줍니다.
그림 1 : 프로파일러 창
[그림 1 : 프로파일러 창]

프로파일러 창을 사용해서, 게임에서 메모리가 어떻게 사용되는지, 다른 작업들을 진행하는데에 얼마나 많은 CPU 시간이 소비되는지, 그리고 물리 계산이 얼마나 자주 이뤄지는지 등과 같이 게임 성능과 관련된 여러가지 면을 배울 수 있습니다. 가장 중요하게는, 이 데이터가 우리의 게임에서의 성능 문제에 대한 원인을 찾고, 그러한 문제를 해결하는 시도가 얼마나 영향을 미칠 수 있는지 측정하는데에 도움이 되도록 사용할 수 있다는 것입니다.

우리 게임에 성능 문제가 있다면, 그것을 고치려고 하기 이전에 성능 문제가 발생하는 원인을 먼저 아는 것이 필수적입니다. 다른 문제는 다른 해결책을 필요로 하기 때문이죠. 만약 우리 프로젝트가 느리게 동작하고 있고, 이 문제의 진짜 원인이 과도하게 복잡한 물리를 사용한 것이라면, 그래픽 렌더링을 개선하는 것은 전혀 도움이 되지 않습니다! 같은 이치로, 성능 문제를 해결하기 위한 시도가 얼마나 효과를 발휘했는지를 측정하는 것은 매우 중요합니다. 프로파일링 데이터를 효율적으로 사용한다는 것은 단순히 어떤 것을 변경하고나서 최고의 결과를 바라는 것이 아닌, 진짜 최적화를 할 수 있음을 의미합니다.

프로파일러 창의 레이아웃

게임의 데이터를 모으기 위해 프로파일러 창을 사용하기 전에, 먼저 프로파일러 창을 열고 레이아웃에 익숙해져봅시다.

  • 상단의 메뉴 바에서 Window > Profiler를 선택하여 프로파일러 창을 엽니다.
    그림 2 : 프로파일러 창 레이아웃
    [그림 2 : 프로파일러 창 레이아웃]

프로파일링 데이터가 기록되어야만 프로파일러 창에서 정보를 볼 수 있음을 꼭 기억하십시오. 우리가 처음 프로파일러 창을 열면, 실행 중인 게임으로부터 프로파일링 데이터를 기록하기 전까지는 특정 영역은 비어있습니다.

프로파일러(Profilers)

프로파일러 창의 왼쪽 열(column)에 프로파일러가 종류별로 있습니다. 각 프로파일러는 게임의 특정 부분에 대한 정보를 보여주고 있습니다. CPU 사용, GPU 사용, 렌더링, 메모리 사용, 오디오, 물리, 네트웍과 같은 프로파일러들로 구분되어 있죠.
그림 3 : 프로파일러 열
[그림 3 : 프로파일러 열]

프로파일링 데이터가 기록되면, 프로파일러 창의 위쪽 반에 각 프로파일러의 데이터를 시간 단위로 볼 수 있습니다. 성능은 시간에 따라 달라질 수 있고, 한 프레임 이상의 성능을 보는 데에 유용합니다. 어떤 문제는 지속적으로 발생할 수도 있고, 어떤 문제는 오직 한 프레임에만 발생할 수도 있고, 또 어떤 문제는 시간이 지날수록 점점 더 좋아지거나 점점 더 나빠질 수도 있습니다.
그림 4 : 프로파일러 데이터
[그림 4 : 프로파일러 데이터]

프로파일러 창의 아래쪽 반에는 현재 선택된 프로파일러의 현재 프레임에 대한 데이터에 대한 상세 정보를 볼 수 있습니다.
그림 5 : 프로파일러 상세정보
[그림 5 : 프로파일러 상세정보]

여기에 표시되는 데이터는 현재 어떤 프로파일러가 선택되었냐에 따라 다르게 보여집니다. 예를들어, 메모리 사용 프로파일러가 선택되었다면, 이 영역에는 어떤 에셋이 가장 많은 메모리를 사용하는지, 또 총 메모리 사용량은 얼마인지와 같은 정보들이 보여집니다. 만약 렌더링 프로파일러가 선택되었다면, 이 영역에는 렌더링되고 있는 오브젝트의 갯수나 수행되고 있는 렌더링 오퍼레이션의 갯수와 같은 통계가 보여질 것 입니다.

프로파일러는 많은 자세한 정보를 제공하지만, 우리는 프로파일링할 때마다 그러한 모든 정보가 다 필요한 것은 아닙니다; 사실, 대게는 한개나 두개 정도의 프로파일러만 사용하게 될 것 입니다. 예를들어, 느리게 돌아가는 게임이 있다면 CPU 사용 프로파일러를 보고 조사를 시작할 것 입니다.
그림 6 : CPU 사용 프로파일러
[그림 6 : CPU 사용 프로파일러]

CPU 사용 프로파일러는 우리 게임의 어떤 부분이 가장 많은 CPU 시간을 사용하는지에 대한 개요를 보여줍니다. 우리는 그 정보를 가지고 어떤 다른 프로파일러를 살펴봐야할지 결정할 수 있죠. 예를들어, 만약 물리 함수가 실행 시 긴 시간을 사용한다면, 물리 성능에 대한 상세 정보를 얻기 위해 물리 프로파일러를 사용하겠죠.

관심없는 정보를 보지 않기 위해, 특정 프로파일러를 숨길 수도 있습니다. 각 프로파일러의 오른쪽 상단에 있는 X아이콘을 클릭해서 프로파일러를 숨길 수 있습니다.
그림 7 : 프로파일러 숨기기
[그림 7 : 프로파일러 숨기기]

또한 프로파일러 창의 왼쪽 상단에 있는 Add Profiler를 클릭해서 프로파일러를 추가할 수도 있습니다.
그림 8 : 프로파일러 추가
[그림 8 : 프로파일러 추가]

프로파일러를 숨기거나 추가한다고 해서 이미 모은 데이터가 사라지는 것은 아닙니다. 단순히 표시하고 있는 데이터만 보였다가 숨겼다가 하는 것이지, 실제 데이터를 삭제하는 것은 아닙니다.

컨트롤(Controls)

화면 상단 바에는 프로파일러 창의 컨트롤들이 있습니다.
그림 9 : 상단 바 컨트롤
[그림 9 : 상단 바 컨트롤]

이 컨트롤들을 이용해서 프로파일링을 시작하거나 정지할 수도 있고, 프로파일링 특징들을 활성화 또는 비활성화할 수도 있으며, 프로파일러가 모은 데이터 사이를 이동하는데에도 사용할 수 있습니다.

이러한 컨트롤의 전형적인 사용은, 성능 문제를 포착하기 위해 적절한 시점에 프로파일링을 시작하고 원하는 데이터를 충분히 모았다면 프로파일링을 멈추는 것입니다. 그러고나서는 타임라인 컨트롤을 이용해서 성능 문제라고 보여지는 프레임으로 이동합니다. 그러면 화면 아래쪽 반에 해당 프레임의 데이터가 표시될 것입니다.

프로파일러 창을 이용해서 게임 프로파일링 데이터 기록하기

이제 우리는 프로파일러 창에 대해서 조금 더 이해하게 되었으니, 게임 데이터를 어떻게 기록하고, 게임이 어떻게 수행되는지를 이해하기 위해서 데이터를 어떻게 읽는지 배워봅시다.

프로파일러 창에서 데이터를 기록하는데에 약간의 비용이 든다는 것을 이해하는 것은 중요합니다. 이는 모든 프로파일링 툴에서 공통적인 부분입니다; 이러한 약간의 오버헤드없이 데이터를 기록하고 표시하는 것은 불가능한 일입니다. 이는 게임이 동작하는데에 있어서 중대한 변화를 초래하지는 않지만, 프로파일러 창이 기록을 하는동안 아주 약간의 성능에 영향을 미칠 수는 있습니다.

우리의 게임을 프로파일하는 방법은 2가지가 있습니다 : 첫번째는 유니티 에디터 상에서 프로파일링하는 방법이고, 두번째는 개발 빌드(development build)를 해서 유니티 에디터 밖에서 실행시키는 방법입니다. 개발 빌드는 일반적인 빌드와는 두가지 측면에서 다릅니다 : 첫번째는 개발 빌드는 게임이 실행될 때 프로파일러 창에 연결할 수 있다는 것이고, 두번째는 개발 빌드에 디버깅을 가능하게 하는 파일들이 포함된다는 것입니다.

거의 대부분의 경우에 유니티 에디터에서보다는 개발 빌드로 프로파일링하는 것이 좋습니다. 여기에는 두가지 이유가 있습니다. 첫번째 이유는, 유니티 에디터에서보다 독립된(standalone) 개발 빌드가 성능과 메모리 사용에 대한 데이터에서 더 정확하기 때문입니다. 프로파일러 창은 유니티 에디터에서 데이터를 기록하는데, 이는 결과를 왜곡시킬 수 있습니다. 두번째 이유는, 가능하다면 타겟 기기에서 게임을 테스트하는 것이 좋기 때문입니다; 예를들어, 만약 우리 게임이 안드로이드 게임이라면 당연히 안드로이드 기기에서 테스트를 해야하는 것입니다. 특정 성능 문제는 오직 특정 하드웨어나 특정 OS에서만 발생하기 때문에, 유니티 에디터에서만 테스트를 한다면 이러한 문제를 발견하지 못할 것입니다.

그렇긴 해도, 유니티 에디터에서 프로파일링하는 것이 유용할 때도 있습니다. 아주 정확한 결과보다는 대략적인 성능 문제를 빨리 파악하기 위해서 필요한 경우가 있죠. 예를들어, 어떤 게임 오브젝트가 성능 문제를 발생시키는지를 파악하기 위해서 런타임에 대량의 게임 오브젝트를 활성화하거나 비활성화할 수 있을 것입니다. 유니티 에디터에서 이런 부분을 테스트하는 것이 여러 개의 빌드를 만드는 것보다 훨씬 빠를 것입니다. 일단 대략적으로 어떤 부분에서 문제가 발생하는지 파악된다면, 저 정확한 문제 원인을 파악하고 해결하기 위해 개발 빌드를 프로파일링할 수 있을 것입니다.

유니티 에디터에서 프로파일링하기

유니티 에디터에서 우리 게임의 데이터를 프로파일링하기 위해서는, 다음 차례를 따라야합니다.

  • 프로파일링하고 싶은 프로젝트를 유니티에서 엽니다.
  • 상단 메뉴 바의 Window > Profiler 메뉴를 선택해서 프로파일러 창을 엽니다.
  • 프로파일러 창 상단의 툴 영역에서 Record를 선택합니다.
  • Play Mode로 들어갑니다.

이렇게하면, 게임에서 상호작용하는 동안 실시간으로 프로파일링 데이터를 모으고 표시해줄 것입니다.

게임을 개발 빌드로 프로파일링하기

타겟 디바이스에서 우리 게임의 프로파일링 데이터를 기록하기 위해서, 우리 게임의 개발 빌드를 만들고 프로파일러 창에 연결해야 합니다. 이는 타겟 플랫폼에 따라 어떻게 해야할지가 달라지게 됩니다.

Windows, OSX, Linux 그리고 WebGL

Windows, OSX, Linux 그리고 WebGL에서 개발 빌드를 실행하기 위해서는 다음과 같은 순서로 진행해야 합니다:

  • 프로파일링하고 싶은 프로젝트를 유니티에서 엽니다.
  • 상단 메뉴 바에서 Window > Profiler 를 선택해서 프로파일러 창을 엽니다.
  • 프로파일러 창의 툴 영역에서, Record를 선택합니다.
  • 상단 메뉴에서 빌드 설정(Build Settings) 창을 엽니다.(File > Build Settings).
  • Development Build를 체크하십시오.
  • Autoconnect Profiler를 체크하십시오.
  • Build and Run을 클릭하십시오.

그림 10 : 빌드 설정 창
[그림 10 : 빌드 설정 창]

게임이 타겟 디바이스에서 실행될 것입니다. 게임이 실행되면, 여러분이 게임과 상호작용하는 것이 유니티 에디터의 프로파일러 창에 표시될 것입니다.

iOS와 Android에 개발 빌드를 프로파일링하기

iOS와 Android에 개발 빌드를 프로파일러 창에 연결하는 것은 조금 더 복잡합니다. 왜냐하면 디바이스를 위한 빌드를 해야하고, 이 디바이스를 유니티 에디터에 연결해야하기 때문입니다.

iOS와 Android의 개발 빌드를 프로파일러 창에 연결하는 순차적인 방법은 유니티 매뉴얼의 문서를 참고하시기 바랍니다.

문제를 분석하기 위해서 프로파일러 창을 사용하기

이제 프로파일러 창이 어떻게 동작하는지에 대해 이해했으니, 이제 프로파일러 창을 이용해서 문제를 파악하는 방법과 어떻게 하면 이러한 문제를 해결하는데에 도움이 될 수 있는지를 알아야 합니다.

만약 우리 게임이 느리게 동작하거나, 프레임이 튀거나, 멈춤 현상이 발생한다면, 이 글이 프로파일러 창을 어떤게 사용하는지와 이러한 문제의 원인을 어떻게 찾는지에 대한 이야기를 해줄 것입니다.

더 읽어볼거리

Unity Learn: Introduction to the profiler

Unity Learn: Profiler overview for beginners

Unity Manual: Profiler

Unity Manual: The CPU Profiler

Unity Manual: The GPU Profiler

Unity Manual: The Rendering Profiler

Unity Manual: The Memory Profiler

Unity Manual: The Audio Profiler

Unity Manual: The Physics Profiler

Unity Script Reference: Profiler

원문 : https://blogs.unity3d.com/kr/2016/12/02/unity-expands-2d-offerings-with-anima2d/

유니티에서 우리는 개발자들을 도울 수 있는 방법과 가능한 최고의 툴을 제공할 수 있는 새로운 방법들을 항상 모색하고 있습니다. 그 목적을 당성하기 위해서, 유명한 뼈대 애니메이션 소프트웨어인 Anima2D가 2017년 1월에 무료로 유니티 개발자 커뮤니티에 올라오게 됩니다! 이 강력한 툴과 이 툴의 개발자 중 한명인 Sergi Valls를 우리 2D 팀에 맞이하게 된 것을 환영합니다.

2D 제작 경험의 개선

우리는 개발의 민주화에 대한 목표를 위해 공헌하고 있고, Anima2D는 우리의 툴셋과 2D 공간에서의 작업에 초점을 맞추고 있는 개발자들을 위한 워크플로우를 개선하는 데에 중요한 한 부분이 될 것 입니다. Sergi의 경험과 결합된 Anima2D의 2D 애니메이션과 2D 캐릭터 툴에 대한 독특한 접근 방식은 이러한 노력의 중추적인 부분이 될 것 입니다.

Anima2D

Anima2D 특징

  • 2D Bones
  • Sprite를 메쉬로 변환
  • SpriteMesh 에디터
  • 자동 weights
  • Inverse Kinematics
  • 자세를 저장 / 로드
  • 아틀라스 호환성
  • Animation을 Bones으로 굽기
  • Onion Skin
  • Avatar Masks 생성

유니티로 작업

이 에셋을 더 개선하기 위한 노력으로써, 12월에는 에셋 스토어에서 Anima2D를 일시적으로 내릴 것 입니다. 그리고 2017년 1월에 Unity 커뮤니티에 무료로 선보이게 되고, 이 때 문서에 수정이 있을 것이며 개발자들이 최고의 프로젝트를 만들 수 있도록 도와주기 위해 필수 지원을 할 예정입니다. 우리는 이것의 가치를 믿고, 여러분이 가능한 최대로 Anima2D를 활용할 수 있도록 도와드리고 싶기 때문에 이런 일을 하고 있습니다.

이 에셋에 대한 전체 문서를 보고 싶으시면, Anima2D User Guide 문서를 참고하세요.

Anima2D를 유니티 개발자 커뮤니티에 가져오는데에 있어서 Mandarina Games의 Joaquim Virgili와 Sergi Valls에게 감사를 표합니다.

이 글은 유니티 자습서의 글을 번역한 글입니다. 원문은 여기에서 볼 수 있습니다.




이 주제는 그렇게 새로운 내용은 아니지만, 매우 중요한 주제입니다. 코딩 습관에 대한 이야기이고, 이는 여러분의 삶을 훨씬 더 쉽게 만들 수 있습니다.

코딩 습관에 깔려있는 생각은 여러분이 코드를 작성할 때 어떤 가이드 라인을 떠올린다는 것 입니다. 이러한 가이드라인은 여러분의 코드가 유지보수 가능하고, 확장 가능하고, 읽기 쉬워서 리팩토링을 할 때의 고통을 덜어주도록 설계되어 있습니다.

특정 코드를 참조하는 클래스가 많아서 생각했던 것보다 훨씬 어려워진 코드 때문에, 여러분의 프로젝트의 해당 코드를 고치고 싶었던 적이 얼마나 되나요? - 이는 키보드 선을 뽑기 위해 컴퓨터 뒤를 봤는데, 수많은 선들이 서로 엉망진창으로 꼬여 있어서 키보드 선을 찾을 수 있다는 희망을 버리게 되는 상황과 비슷합니다.

그래서, 여기에 여러분의 코드에 엉킨 부분을 풀고, 단정된 형태를 유지할 수 있는 일반적인 가이드 라인을 제공합니다.

단일 원칙 Single Responsibility

주어진 클래스는 이상적으로 오직 하나의 일에만 책임을 져야합니다.

단일 원칙 뒤에 있는 생각은 다음과 같습니다.

각 클래스는 작은 일(task)을 하고 이러한 작은 일을 조합함으로써 보다 큰 목표를 해결할 수 있습니다.


유니티는 기능을 분리해서 재사용 가능한 부분들로 설계했고, 단일 원칙은 여기에서 가장 중요한 원칙 중 하나 일지도 모릅니다.

이 원칙에 대한 예를 들기 위해서, Player 클래스가 있다고 생각해 봅시다. Player는 입력, 물리, 무기, 체력, 인벤토리를 다룹니다.

Player가 책임을 지고 있는 부분이 꽤 많아 보입니다. 우리는 이를 여러 개의 다른 컴포넌트로 쪼개서 각 컴포넌트가 오직 하나 만을 수행하도록 해야합니다.

  • PlayerInput - 입력을 관리하는 책임
  • PlayerPhysics - 물리 시뮬레이션을 관리하는 책임
  • WeaponManager - 플레이어 무기를 관리하는 책임
  • Health - 플레이어의 체력을 관리하는 책임
  • PlayerInventory - 플레이어 인벤토리를 관리하는 책임

아, 훨씬 낫네요. 이제 이 클래스들은 모두 서로에게 큰 의존성을 가지고 있고, 여전히 약간의 문제가 있습니다. 이를 해결하기 위한 방법을 보죠.

의존 관계 역전 Dependency Inversion

만약 어떤 클래스가 다른 클래스의 의존한다면, 그 관계를 추상화 시키십시오.


의존 관계 역전의 뒤에 있는 생각은 다음과 같습니다.

어떤 클래스가 다른 클래스를 호출할 때마다, 우리는 그러한 호출을 어떤 종류의 추상화로 바꿔야하며, 이로 인해 각 클래스가 서로 다른 클래스로부터 독립적일 수 있습니다.


가장 바람직한 방법은 클래스 의존 관계를 인터페이스로 대체하는 것 입니다. 그래서 클래스 A가 클래스 B의 메서드를 호출하는 것보다는, 클래스 B가 구현하고 있는 ISomeInterface의 메서드를 호출하도록 합니다.

다른 방법은 클래스 B가 상속받는 부모 클래스를 도입하는 것 입니다. 그래서 클래스 A가 클래스 B를 직접적으로 의존하는게 아닌, 부모 클래스를 다루도록 하는 것 입니다.

물론, 가장 바람직하지 않는 방법은 클래스 A가 직접적으로 클래스 B에 의존하는 것 입니다. 이는 우리가 피하고 싶은 방향이죠.

우리의 이전 예에서, 컴포넌트들은 서로 상당히 강한 커플링을 가지고 있었습니다. PlayerInput은 PlayerPhysics에 대해 의존하고 있었을테고, WeaponManager는 Inventory에 의존하는 등 말이죠.

이 들을 추상화시켜 보죠.

  • IActorPhysics - 입력을 받아들일 수 있고, 아마 물리 시뮬레이션에 영향을 미칠 수 있는 클래스를 위한 인터페이스
  • IDamageable - 대미지를 입을 수 있는 클래스를 위한 인터페이스
  • IInventory - 아이템을 저장하고 가져올 수 있는 클래스를 위한 인터페이스

이제 우리의 PlayerPhysics는 IActorPhysics를 구현하고, Health는 IDamageable을 구현하고, PlayerInventory는 IInventory를 구현합니다.

그러면 이제 PlayerInput은 어떤 IActorPhysics의 존재에 의존하게 되고, WeaponManager는 어떤 IInventory의 존재에 의존하게 되고, 플레이어의 대미지를 다루게 되는 어떤 것은 어떤 IDamageable의 존재에 의존하게 됩니다.

의존 관계 역전은 단일 책임을 어느정도 보강하는데에 도움이 됩니다. PlayerInput은 플레이어가 어떤게 움직이는지 신경쓰지 않아도 되고, 무엇이 플레이어를 움직이는지도 신경쓰지 않아도 됩니다. 그냥 그런 기능을 약속하는 어떤 것이 있다는 사실만 알면됩니다.

모듈화

저는 유니티에서 개인적으로 이런 형태의 코드를 많이 보았습니다.

switch( behavior )
{
    case 1: // some behavior
    case 2: // another behavior
    case 3: // yet another behavior
    case 4: // the last behavior
}

물론 이 코드는 동작하지만, 더 나아질 수 있습니다. 이 코드는 실제로 모듈화해달라고 소리지르고 있습니다. 각각의 행동들은 모듈화될 수 있으며, 그렇게 하면 "행동"은 enum에서 모듈의 인스턴스로 바꿀 수 있습니다. ( 이 경우에 우리의 모듈은 delegate라고 하죠.) 그러면 코드는 이렇게 될 것 입니다.

behavior();

그리고 어딘가 다른 곳에 이 모듈을 할당할 수 있습니다 :

MyClass.behavior = someBehavior;

여기에서 가정상 someBehvior는 함수입니다. ( 만약 우리의 모듈이 클래스라면, 클래스의 인스턴스가 될 수도 있겠죠.)

우리가 상태 머신이나 메뉴 시스템을 만들고 있다면 이 개념을 특히나 유용하게 사용할 수 있죠. 모든 가능한 상태나 메뉴를 enum으로 정의하는 것보다, 쉽게 변경할 수 있는 모듈로 상태와 메뉴를 정의하는 것이 더 이치에 맞습니다. 이렇게 하면 우리는 enum에 새로운 항목을 추가할 필요도 없고, 무엇인가 추가할 때마다 switch case 문을 확장해야할 필요도 없습니다.

결론

이 글은 유일한 코딩 습관에 관한 내용은 아닙니다. 하지만 따라야할 굉장히 중요한 것이죠.

여러분이 항상 이 내용을 따르지는 않아도 됩니다 - 가끔은, 이렇게 하는게 과할 수도 있고, 이치에 맞지 않을 수도 있습니다. 하지만, 비판적인 생각을 연습하고 여러분의 코드가 이로 인해 이득을 얻을 수 있을지 결정해보세요. 명심하십시오. 이는 여러분의 코드 몇 줄을 줄여주는 그런게 아니라, 나중에 올 수 있는 두통으로부터 여러분을 지켜주는 것 입니다.

이 글은 유니티 자습서의 글을 번역한 글 입니다. 원문은 여기에서 확인할 수 있습니다.



이 글에서는 게임에서 물리를 사용할 때의 모범 사례를 약간 살펴볼 것이고, 왜 이렇게 써야하는지에 대한 증명도 다룰 것 입니다.

Layer와 Collision Matrix

따로 설정하지 않은 모든 게임 오브젝트는 기본적으로 Default 레이어로 생성이 되고 이는 모든 것과 충돌됨을 의미합니다. 이는 매우 비효율적입니다. 어떤 것끼리 서로 충돌을 할 지 설정을 하세요. 이렇게 하기 위해서는 오브젝트의 타입에 맞게 다른 레이어를 설정해야 합니다. 새로운 레이어가 생길 때마다 Collision Matrix에 새로운 행과 열이 생기게 됩니다. 이 매트릭스는 레이어들 간의 상호작용을 정의하게 됩니다. 기본적으로, 새로운 레이어를 추가하면, Collision Matrix는 새 레이어를 다른 모든 레이어와 충돌하게 끔 설정합니다. Collision Matrix를 제대로 설정함으로써 불필요한 충돌 처리를 피할 수 있습니다.

시연 목적으로 간단한 데모를 만들었는데, 여기에서는 하나의 박스 컨테이너 안에 2000 개의 오브젝트(빨간색 1000개와 초록색 1000개)를 생성합니다. 녹색 오브젝트는 같은 녹색 오브젝트와 컨테이너 벽과만 상호 작용을 해야하고, 빨간색의 경우도 마찬가지 입니다. 테스트 중 하나에서, 모든 인스턴스가 Default 레이어에 속하고, 충돌 리스너에 있는 게임 오브젝트 태그를 문자열 비교함으로써 상호 작용이 이루어지게 됩니다. 다른 테스트에서는, 각 오브젝트 타입은 각각의 레이어로 설정되고, Collision Matrix를 통해서 각 레이어의 상호작용 설정을 하게 됩니다. 이 경우에는 필요한 충돌만 발생하기 때문에 문자열 테스트가 필요없습니다.

그림 1 : Collision Matrix 설정
그림 1 : Collision Matrix 설정

아래 이미지는 시연에서 가져온 결과입니다. 이 시연에는 간단한 매니저 클래스가 있는데, 이 클래스는 충돌의 수를 세고, 5초 후에 자동으로 멈추게 합니다. 공통의 레이어를 사용하는 경우에 불필요한 여분의 충돌이 발생하는 부분이 매우 인상깊습니다.

그림 2 : 5초 동안의 충돌
그림 2 : 5초 동안의 충돌

더 자세한 데이터를 위해 물리 엔진의 프로파일러 데이터도 캡쳐했습니다.

그림 3 : (공통 레이어 vs 분리한 레이어) 물리 프로파일러 데이터
그림 3 : (공통 레이어 vs 분리한 레이어) 물리 프로파일러 데이터

프로파일러 데이터에서 볼 수 있듯이, 물리에서 CPU 사용량의 차이가 큰 것을 확인할 수 있습니다. 단일 레이어를 사용하게 되면 평균 27.7 ms 정도이고, 레이어를 분리해서 사용하게 되면 평균 17.6 ms 정도 입니다.

RAYCASTS

레이캐스팅은 물리 엔진에서 굉장히 유용하고 강력한 도구입니다. 이는 우리가 특정 방향으로 특정 길이의 광선(ray)을 쏠 수 있도록 해주고, 이를 통해서 어떤 것과 부딪혔는지를 알 수 있습니다. 하지만, 이는 비싼 동작입니다 ; 이 성능은 광선의 길이와 씬에서의 콜라이더의 타입에 크게 영향을 받습니다.

이를 사용하는 데에 도움이 될 수 있는 몇가지 힌트를 드리겠습니다.

  • 이는 명확합니다. 하지만, 작업을 진행하기 위한 광선은 최소한으로 사용하십시오.
  • 필요 이상의 광선 길이를 확장하지 마십시오. 광선이 길어질 수록, 더 많은 오브젝트가 테스트 되어야 합니다.
  • FixedUpdate() 함수 안에서 Raycast를 사용하지 마십시오. 가끔은 Update() 에서의 사용도 과잉 사용이 될 수 있습니다.
  • 여러분이 사용하고 있는 콜라이더의 타입을 알고 계십시오. 메쉬 콜라이더에 대한 레이캐스팅은 정말 비쌉니다.
    • 좋은 해결책은 자식에 기본 콜라이더(primitive colliders)를 사용하고, 대략적으로 매쉬와 비슷한 모양이 되도록 노력하는 것 입니다. 부모 Rigidbody 밑에 있는 모든 자식 콜라이더는 합성 콜라이더처럼 동작할 것 입니다.
    • 메쉬 콜라이더의 사용이 절실한 경우에는 최소한 그들을 볼록하게 되도록 사용하십시오.
  • 광선이 무엇을 맞춰야하는지를 확실히 하고, 항상 raycast 함수에 레이어 마스크를 지정하도록 하십시오.
    • 이는 공식 문서에 잘 설명되어 있지만 raycast 함수에 사용해야할 값은 layer id가 아닌 bitmask 값 입니다.
    • 따라서 만약 레이어 아이디가 10인 오브젝트를 맞추고 싶다면, 10이 아닌 1<<10 (1을 왼쪽으로 10만큼 비트 이동) 을 사용하세요.
    • 레이어 10이 아닌 나머지 모든 것들을 맞추고 싶은 경우에는, 비트 보수 연산자인 ~을 사용하세요. 그러면 비트 마스크의 각 비트의 역을 구할 수 있습니다.


어떤 오브젝트가 녹색 박스에서 충돌하는 광선을 쏘는 그런 간단한 시연을 하나 만들었습니다.

그림 4 : 간단한 Raycast 시연 씬
그림 4 : 간단한 Raycast 시연 씬

이 시연에서 저는 앞에서 말한 내용을 지지할 수 있는 프로파일러 데이터를 뽑아내기 위해 광선의 수와 길이를 조절해 보았습니다. 아래의 그래프를 보면 광선의 수와 길이가 성능에 얼마나 영향을 미치는지 알 수 있습니다.

그림 5 : 성능에 영향을 미치는 광선의 수
그림 5 : 성능에 영향을 미치는 광선의 수

그림 6 : 성능에 영향을 미치는 광선의 길이
그림 6 : 성능에 영향을 미치는 광선의 길이

시연의 목적으로, 기본 콜라이더를 메쉬 콜라이더로 변경하기로 결정했습니다.

그림 7 : 메쉬 콜라이더 씬 (콜라이더 당 110 개의 버텍스)
그림 7 : 메쉬 콜라이더 씬 (콜라이더 당 110 개의 버텍스)

그림 8 : 기본 콜라이더 vs 메쉬 콜라이더 물리 프로파일러 데이터
그림 8 : 기본 콜라이더 vs 메쉬 콜라이더 물리 프로파일러 데이터

프로파일 그래프에서 볼 수 있듯이, 메쉬 콜라이더에 대한 레이캐스팅은 물리 엔진이 프레임당 더 많은 작업을 하도록 만듭니다.

Physics 2D vs 3D

어떤 물리 엔진이 여러분의 프로젝트에 최고 적절한지 선택하십시오. 만약 2D 나 2.5D 게임(2D 평면에서 만드는 3D 게임)을 개발 중이라면, 3D 물리 엔진을 사용하는 것은 과한 선택입니다. 이 여분의 차원이 여러분의 프로젝트에서 불필요한 CPU 비용을 차지하게 됩니다. 두 물리 엔진의 성능 차이를 확인하고 싶다면, 저자가 이전에 작성한 글을 참고해 보세요.

http://x-team.com/2013/11/unity3d-v4-3-2d-vs-3d-physics/

RigidBody

RigidBody 컴포넌트는 오브젝트 간의 물리적 상호작용을 추가하기 위한 필수 컴포넌트 입니다. 콜라이더를 트리거로써만 사용하는 경우에도, OnTrigger 이벤트를 적절히 사용하기 위해서 게임 오브젝트에 RigidBody를 추가해야 합니다. RigidBody를 가지고 있지 않은 게임 오브젝트는 정적 콜라이더로 간주됩니다. 정적 콜라이더를 움직이려는 시도를 하게 되면, 물리 엔진이 물리 세계 전체를 다시 계산하도록 강제하기 때문에 극도로 비효율적으로 동작하게 됩니다. 다행히도, 프로파일러는 여러분이 이러한 시도를 할 때 CPU 프로파일러 탭에서 경고를 보여주기 때문에 이러한 문제를 알아차릴 수 있습니다. 정적 콜라이더를 움직일 때의 영향을 좀 더 확실히 시연해 보기 위해, 첫번째 데모의 움직이는 모든 오브젝트에서 RigidBody를 제거했고, 이에 대한 프로파일러 데이터를 캡쳐했습니다.

그림 9 : 움직이는 정적 콜라이더 경고
그림 9 : 움직이는 정적 콜라이더 경고

그림에서 볼 수 있듯이, 총 2000개의 경고가 생성되었고, 이는 하나하나가 움직이는 게임 오브젝트에 대한 것입니다. 또한 물리에 사용된 평균 CPU 량도 대략 17.6ms에서 35.85ms로 증가했습니다. 게임 오브젝트를 움직일 때 RigidBody를 붙이는 것은 필수적입니다. 만약 여러분이 게임 오브젝트를 직접적으로 조정하고 싶다면, rigidbody 속성 중에 kinematic을 마트하시면 됩니다.

Fixed TimeStep

TimeManager의 Fixed Timestep 값을 변경하는 것은, FixedUpdate()와 물리 업데이트 비율에 직접적인 영향을 미칩니다. 이 값을 변경함으로써 물리에서 정확성과 CPU 사용 시간 사이의 조절을 할 수 있습니다.

요약

이번에 다룬 주제는 설정과 구현이 쉽고, 여러분이 개발하는 대부분의 프로젝트는 물리 엔진을 사용할 것이기 때문에 성능의 차이를 가져올 수 있을 것 입니다.

+ Recent posts