본문 바로가기
Unity3D/Tip

유니티 2D에서 Collider와 Rigidbody 최적화에 관하여

by 니키티스 2021. 8. 9.

***테스트 결과와 결론이 궁금하신 분들은 마지막 3줄 요약을 확인해주세요!

개요

불과 얼마 전까지, Rigidbody는 물리 연산을 사용하기 때문에 중력 같은 물리 처리가 필요 없다면 Rigidbody를 부착하지 않는 것이 더 효율적이라 생각했다.

 

그러나 최적화 팁을 보면 오히려 반대였다.

 

★ 10. Unity 최적화 기법 :: 큰 꿈을 그리는 프로그래머의 공간. (tistory.com)

 

★ 10. Unity 최적화 기법

Unity 3D :: 게임 최적화 기법 [최적화의 시작은 병목 파악부터] # CPU  - 너무 많은 DP CALL  - 복잡한 스크립트나 물리 연산 # Vertex Processing  - 너무 많은 버텍스들  - 버텍스당 너무 많은 연산 (Verte..

loadofprogrammer.tistory.com

 

콜라이더만 존재하고 Rigidbody 컴포넌트가 부착되지 않은 것을 정적 콜라이더(Static collider)라고 한다.

내 예상으로는 Rigidbody를 부착시키지 않았으니 정적 콜라이더가 더 효율적이라고 생각했다.

그러나 정적 콜라이더를 이동시키면 성능 저하가 심하다는 글을 찾게 되었다.

Unity 5 이후로 정적 콜라이더의 이동을 최적화하였지만 지금도 여전히 성능 저하가 생긴다는 것이다.

 

그래서 실제로 얼마나 성능 저하가 발생하는지 테스트해보기로 했다.

 

테스트 결과는 마지막 문단에 정리해놓았다.

 

발단

상황은 다음과 같았다.

 

타워 디펜스류 프로젝트를 진행하면서 총알이 적이나 오브젝트, 타워에 부딪히면 튕기게 하는 작업이 필요했다. 

그러기 위해서는 리지드바디를 이용해야 했다.

유니티 공식 문서(콜라이더 - Unity 매뉴얼 (unity3d.com). 충돌 및 트리거 처리를 나타내는 충돌 액션 매트릭스.

유니티 공식 문서에 따르면 정적 콜라이더는 리지드바디 콜라이더와 충돌할 수 있었다.

따라서 총알에는 정적 콜라이더를 넣고, 움직이는 적에게는 리지드바디 콜라이더를 넣으면 된다고 판단했다.

 

그러나 테스트를 위해 몬스터를 300마리쯤 생성하고 전투하게 했더니 이상한 일이 일어났다.

 

2D 게임에 그래픽 처리도 단순한 게임이었는데 60 fps를 넘지 못하는 경우가 발생한 것이다.

 

프로파일러를 돌려보니 그 원인에는 기존에 짠 코드가 비효율적인 것도 있었고, 충돌로 인해 프레임 드롭이 심각한 점도 있었다.

 

대체 뭐가 문제인지 구글링 하던 차. 정적 콜라이더(static collider)를 이동시키면 성능 저하가 생길 수 있다는 글을 발견하게 되었다.

 

 

테스트 환경

테스트 버전은 Unity 2019.4.2f1이고, 2D 환경에서 다음 상황을 실험해보기로 했다.

  • 정적 콜라이더(Static collider)를 이동시켰을 때
  • 리지드바디 콜라이더를 이동시켰을 때
  • 키네마틱 리지드바디 콜라이더를 이동시켰을 때

여기서 정적 콜라이더는 Rigidbody 없이 Collider만 부착한 경우이고

리지드바디 콜라이더는 Rigidbody(혹은 Rigidbody2D) 컴포넌트를 부착하고 Body Type을 Dynamic으로 설정한 것이다.

키네마틱 리지드바디는 Rigidbody(혹은 Rigidbody2D) 컴포넌트를 부착하고 Body Type을 Kinematic으로 설정한 것이다.

 

테스트 과정

테스트는 두 과정으로 나눠보기로 했다.

 

  1. 정적 콜라이더, 리지드바디 콜라이더, 키네마틱 리지드바디 콜라이더를 충분히 많이 생성한다.
  2. 10초간 이동시켜본다.
  3. 평균 프레임을 측정하고, 프로파일러를 통해 확인해본다.

다만 Rigidbody의 경우 Transform 컴포넌트를 통해 이동시키는 것과 Rigidbody 컴포넌트를 통해 이동시키는 것의 성능이 다르다는 말이 있었다.

그래서 어떤 컴포넌트를 사용하느냐에 따라 얼마나 차이 나는지도 테스트해보기로 했다.

 

소스코드

ObjectGenerator 클래스: 테스트할 오브젝트를 생성한다.

ObjectGenerator 클래스는 테스트용 오브젝트를 지정한 개수만큼 생성한다.

 

Mover 클래스: 오브젝트를 움직인다. Transform 컴포넌트를 이용한다.
RigidbodyMover 클래스: 오브젝트를 움직인다. 리지드바디 컴포넌트를 사용한다.

Mover, RigidbodyMover 클래스는 오브젝트를 움직일 때 사용한다.

 

스페이스바를 눌러 움직일 수 있다.

 

정적 콜라이더는 Mover를 통해, 리지드바디 콜라이더와 키네마틱 리지드바디 콜라이더는 Mover로 1회, RigidbodyMover로 1회 테스트한다.

 

FPSCounter 클래스: 평균 프레임을 측정한다.

FPSCounter 클래스는 스페이스 바를 누르고 있는 동안의 평균 프레임을 측정한다.

 

작성할 때 다음 글의 소스 코드를 이용하였다.

FPS Counter - Unity Forum

 

FPS Counter

Hello everybody. I have made myself this simple fps counter script that display's the current frame count in a simple ui text. So my question is kind...

forum.unity.com

 

Mover, RigidbodyMover 오브젝트는 BoxCollider2D를 부착하도록 하였다.

 

개별 테스트 결과

100개 오브젝트 생성 시

1. 정적 콜라이더(Static collider)

이동 도중 중단했을 때 프로파일러

2. 리지드바디 콜라이더(Dynamic rigidbody collider) - Transform.Traslate 사용 시

시작시 오브젝트가 물리 충돌로 인해 퍼진다.
이동 중이지 않을 때 프로파일러
이동 중일 때 프로파일러

3. 키네마틱 리지드바디 콜라이더(Kinematic Rigidbody collider) - Transform.Translate 사용 시

Rigidbody를 사용할 때와 달리 충돌되지 않는다.
이동중이지 않을 때 프로파일러
이동 중일 때 프로파일러

4. 리지드바디 콜라이더(Dynamic rigidbody collider) - Rigidbody2D.MovePosition 사용 시

이동 중이지 않을 때 프로파일러
이동 중일 때 프로파일러

 

5. 키네마틱 리지드바디 콜라이더(Kinematic rigidbody collider) - Rigidbody2D.MovePosition 사용 시

이동 중이지 않을 때 프로파일러
이동 중일 때 프로파일러. Kinematic은 Rigidbody.MovePosition을 사용하면 업데이트가 띄엄띄엄 이루어진다.

 

300개 오브젝트 생성 시

300개부터는 로그만 띄우도록 하였다. 대신 5회씩 테스트하였다.

1. 정적 콜라이더

2. 리지드바디 콜라이더(Dynamic rigidbody collider) - Transform.Traslate 사용 시

3. 키네마틱 리지드바디 콜라이더(Kinematic Rigidbody collider) - Transform.Translate 사용 시

4. 리지드바디 콜라이더(Dynamic rigidbody collider) - Rigidbody2D.MovePosition 사용 시

5. 키네마틱 리지드바디 콜라이더(Kinematic rigidbody collider) - Rigidbody2D.MovePosition 사용 시

 

1000개 오브젝트 생성 시

1. 정적 콜라이더

오브젝트가 많아지자 렉이 현저하게 나타났다. 테스트를 진행할 때 Game 화면을 Maximize하지 않았는데, Maximize한 상태에서는 30~60프레임으로 나타난 걸로 보아 인스펙터로 인한 프레임 저하도 있는 것 같다.

2. 리지드바디 콜라이더(Dynamic rigidbody collider) - Transform.Traslate 사용 시

생성 시간이 10초 이상 걸릴 정도로 생성이 오래 걸린다. 초기에 같은 위치에서 생성되어 서로 충돌이 일어나기 때문인 것으로 보인다.

3. 키네마틱 리지드바디 콜라이더(Kinematic Rigidbody collider) - Transform.Translate 사용 시

4. 리지드바디 콜라이더(Dynamic rigidbody collider) - Rigidbody2D.MovePosition 사용 시

5. 키네마틱 리지드바디 콜라이더(Kinematic rigidbody collider) - Rigidbody2D.MovePosition 사용 시

키네마틱 리지드바디는 프레임은 높게 나타났지만 실제 움직임은 뚝뚝 끊겨 보이는 문제가 있었다.

 

 

정리

오브젝트를 10초간 이동시킬 때 평균 프레임은 다음과 같다.

콜라이더 종류 100개 오브젝트(Fps)
(3회 측정)
300개 오브젝트(Fps)
(5회 측정)
1000개 오브젝트(Fps)
(5회 측정)
속도 순위
정적 콜라이더 235.4156 177.3874 19.4086 5-4-5
리지드바디
(Transform.Translate)
244.4581 223.2507 29.5173 3-2-3
키네마틱 리지드바디
(Transform.Translate)
244.5342 152.8789 22.4402 2-5-4
리지드바디
(Rigidbody.MovePosition)
241.8148 216.9457 89.6673 4-3-2
키네마틱 리지드바디
(Rigidbody.MovePosition)
248.3943 227.2545 144.6594
(다소 끊김)
1-1-1

 

오브젝트 수가 적을 때(100개) 성능은 아래와 같다.

키네마틱(MovePosition) > 키네마틱(Translate) > 리지드바디(Translate) > 리지드바디(MovePosition) > 정적 콜라이더

오브젝트 수가 많을 때(1000개) 성능은 아래와 같다.

키네마틱(MovePosition) >> 리지드바디(MovePosition) >> 리지드바디(Translate) > 키네마틱(Translate) > 정적 콜라이더

 

여기서 오브젝트가 100개일 땐 3 프레임 차이로 MovePosition보다 Translate가 더 성능이 나은 것으로 나타났다.

반면 오브젝트가 1000개일 땐 약 60 프레임 차이로 MovePosition이 성능이 우월한 것으로 나타났다.

 

이건 테스트 횟수가 적기 때문에 Translate의 성능이 더 나은 것처럼 보인 것 같다. 오브젝트 수가 적을 땐 차이가 근소하고, 오브젝트 수가 많아지면 MovePosition이 훨씬 성능이 나으므로 Rigidbody.MovePosition을 사용하는 것이 낫다.

 

결론

정적 콜라이더를 이동시키면 프레임 저하가 굉장히 심하다는 점을 알 수 있었다.

 

즉, 움직이는 콜라이더 물체는 리지드바디를 부착하는 것이 더 좋다.

 

그리고 리지드바디(1000개 기준 89.7 fps)보다 키네마틱 리지드바디(1000개 기준 144.7 fps)가 더 빨랐다. 사실적인 충돌이나 물리 처리가 필요하지 않다면 키네마틱 리지드바디를 사용하는 편이 성능에 유리하다.

 

전반적으로 Transform.Translate보다 Rigidbody.MovePosition을 사용할 때 프레임이 더 높았다.

더 나은 성능을 위해서는 Transform.position이나 Transform.Translate보다 Rigidbody.MovePosition, Rigidbody.position, Rigidbody.velocity를 사용하는 편이 낫다고 한다.

이 함수 사이에서도 차이점이 있다고 하는데 궁금한 사람은 직접 검색해보길 바란다.

 

다만 테스트를 하면서 리지드바디가 키네마틱 리지드바디를 쓸 때보다 더 움직임이 부드러웠는데, 원인을 알 수 없었다.

 

3줄 요약

  1. 움직이는 콜라이더는 성능을 위해 리지드바디를 꼭 부착하자.
  2. 리지드바디에서 물리 처리가 필요하지 않다면 Kinematic을 사용하자.
  3. Transform.Translate나 Transform.position보다 Rigidbody.MovePosition, Rigidbody.position이 성능에 좋다.

댓글