로비 디더

카메라-플레이어 사이 장애물을 반투명 처리하는 디더링 시스템의 물리 엔진 비용을 분석하고, 쿼리 방식·계산 주기 두 축에서 개선안을 측정 — PhysicsFixedUpdate 0.2~0.4ms 감소, GC 할당 약 30% 감소.
제목
기존 구조
Kinematic Rigidbody + BoxCollider(Trigger) 방식. 매 프레임 콜라이더의 크기/위치/회전이 바뀌므로 PhysX 가 Broadphase 트리에서 이 콜라이더를 매번 재배치하고, 씬의 모든 트리거 콜라이더와의 겹침을 상시 검사한다. 콜라이더가 살아있는 한 물리 엔진이 계속 일하는 구조.
개선 가설
"필요한 순간만 PhysX BVH 를 읽기 전용 쿼리하면 Broadphase 재배치 비용이 사라진다."
OverlapBox / RaycastAll 둘 다 PhysX 내부 BVH 를 즉시 조회하는 read-only API. 상시 등록된 콜라이더가 없으므로 매 프레임 Broadphase 갱신이 필요 없고, 쿼리를 호출하는 그 순간만 비용이 발생한다.
추가로 계산 주기도 함께 변경했다. 디더링은 시야 가림 판정이고, 카메라 / 플레이어가 한 프레임에 크게 움직이지 않으므로 30프레임 간격(약 0.5초)로 충분.
측정 결과 (S21 / 상옵 60FPS)
| 방식 | PhysicsFixedUpdate 평균 | 피크 측정 | GC 할당 수 |
|---|---|---|---|
| 기존 콜라이더 (매 프레임) | 0.50~0.90 ms | 0.91 ms @ PL 18ms | 495,748 |
| OverlapBox (30프레임) | 0.30~0.50 ms | 0.37 ms @ PL 17ms | 352,203 |
| Raycast (30프레임) | 0.30~0.50 ms | 0.48 ms @ PL 16ms | 367,052 |
분석 — 진짜 효과는 어디서 왔는가
수치만 보면 "Broadphase 비용 제거가 컸다"라고 결론지을 법한데, 실제로는 계산 주기 단축의 영향이 더 컸다.
- 쿼리 방식 변경(콜라이더→OverlapBox)을 매 프레임으로 유지했다면 절감폭이 훨씬 작았을 것
- GC 절감 30% 도 30프레임 간격이라는 호출 수 자체 감소가 주 원인 (495K→352K)
- 측정 편차도 있어 단일 시점 비교는 위험 — 누적 평균으로 판단
엔지니어링 관점에서 의미 있는 발견: 알고리즘 자체를 갈아엎기 전에 호출 빈도부터 줄이는 것이 1차 옵션. PhysX 같은 잘 만들어진 엔진의 단일 쿼리 비용은 이미 작고, 비대해 보였던 게 누적 호출 빈도 문제였던 케이스.
결정
RaycastAll(카메라→플레이어 방향, 거리=세그먼트 길이) + 30프레임 간격 채택.
- OverlapBox 와 평균 성능 동일하지만 의미 단위(시선 차단 = ray)와 더 맞음
- 줌 레벨별 거리/반경 설정은
cameras.proto데이터 그대로 활용
회고
- 측정 편차가 컸다 — 같은 씬에서도 카메라 워크에 따라 ±0.2ms 흔들림. 누적 평균과 피크를 같이 봐야 신뢰 가능.
- "콜라이더 기반은 비싸 보이니 raycast 로 바꾸자" 같은 직관에 빠지지 않고, 변경 축을 두 개로 분해해서 (쿼리 방식 / 호출 주기) 각각 측정한 것이 의미 있었음.
- 정작 큰 절감은 호출 주기에서 나왔다 — 단순한 변경(상수 하나)이 구조 변경보다 효과가 컸음을 인정하는 정직한 결론
Implementation
- 01
기존 콜라이더 기반 (매 프레임)


- 02
OverlapBox 쿼리 (30 프레임 간격)


- 03
Raycast 쿼리 (30 프레임 간격)

