260219 Unity PhysX 충돌검출 심층분석
19 Feb 2026
🔍 260219 Unity PhysX 충돌검출 심층분석
📝 작성일: 2026-02-19
💡 분류: Game Physics / Collision Detection / Unity Engine
💡 키워드: Unity, PhysX, Collision Detection, Broad Phase, Narrow Phase, CCD, GJK, EPA, Collider
📚 목차
- PhysX 엔진 개요
- 충돌 검출 아키텍처 (Collision Detection Pipeline)
- Unity Collider 종류 및 특성
- Unity 충돌 검출 API
- 충돌 검출 모드 및 설정
- 성능 최적화 기법
- 고급 기능 및 활용 사례
- 실제 활용 패턴
- 참고 자료
🧭 1. PhysX 엔진 개요
🧠 1.1 NVIDIA PhysX란?
NVIDIA PhysX는 NVIDIA가 개발하고 유지보수하는 오픈소스 실시간 물리 시뮬레이션 엔진이다. 원래 NovodeX라는 이름으로 개발되었으며, 2004년 Ageia에 인수된 후 2008년 NVIDIA에 최종 인수되었다. 현재 PhysX SDK 5.x까지 발전하였으며, BSD-3 라이선스로 오픈소스화되어 있다.
PhysX는 다음과 같은 핵심 기능을 제공한다.
- 강체 역학(Rigid Body Dynamics): 질량, 관성, 힘, 토크 기반 시뮬레이션
- 충돌 검출(Collision Detection): Broad Phase / Narrow Phase 이중 구조
- 조인트 시스템(Joints): 다양한 물리적 연결 구속 조건
- 천 시뮬레이션(Cloth): 직물 물리
- 파티클 시스템(Particles): 유체 및 입자 시뮬레이션
- 차량 물리(Vehicle): 전용 차량 역학 모델
- SDF(Signed Distance Field) 충돌: PhysX 5.x에서 추가된 비볼록 형상 지원
🕰️ 1.2 Unity에서의 PhysX 통합 역사
Unity 엔진은 초기부터 NVIDIA PhysX를 기본 3D 물리 엔진으로 채택하였다. 주요 버전별 통합 이력은 다음과 같다.
| Unity 버전 | PhysX 버전 | 주요 변화 |
|---|---|---|
| Unity 4.x | PhysX 2.x | 초기 통합, 기본적인 충돌/물리 |
| Unity 5.0 (2015) | PhysX 3.3 | 대규모 아키텍처 업그레이드, 새로운 Solver |
| Unity 2018.2 | PhysX 3.4.1 | 실험적 빌드로 제공, PCM 접촉 생성 도입 |
| Unity 2019.3 (2019) | PhysX 4.1 | 새로운 Broad Phase(ABP), Temporal GI Solver, Speculative CCD |
| Unity 2022.x | PhysX 4.x (개선) | ContactModifyEvent, 개선된 Contact Dispatch |
| Unity 6 (6000.x) | PhysX 4.x 기반 | 안정화 및 최적화, Physics 설정 UI 개편 |
PhysX 3.4에서 4.1로의 전환(Unity 2019.3)이 가장 큰 도약이었다. 이 업그레이드를 통해 ABP(Automatic Box Pruning) Broad Phase 알고리즘, Temporal Gauss-Seidel(TGS) Solver, Speculative CCD 등 핵심 기능이 추가되었다.
💡 참고: Physics updates in Unity 2019.3 - Unity Blog, Unity Forum - PhysX 4.x Switch
🧠 1.3 Unity 6에서의 PhysX 현황
Unity 6(6000.x 시리즈)에서는 PhysX가 여전히 기본이자 유일한 내장 3D 물리 엔진이다. Edit > Project Settings > Physics > GameObject SDK에서 PhysX만 선택 가능하다. PhysX 5.x로의 전환은 아직 Unity 메인 릴리스에 포함되지 않았으나, 커뮤니티에서는 PhysX 5.6과 Unity를 통합하는 실험적 시도가 진행되고 있다.
PhysX 5.x가 가져올 주요 변화는 다음과 같다.
- PABP(Parallel Automatic Box Pruning): 멀티스레드 Broad Phase
- GPU Broadphase: GPU 가속 Sweep-and-Prune
- SDF 충돌: Convex Decomposition 없이 비볼록 형상 직접 충돌 지원
- Speculative + Sweep CCD 동시 활성화: 두 CCD 방식의 하이브리드 사용
⚖️ 1.4 PhysX vs Havok (Unity Physics) 비교
Unity는 ECS/DOTS 기반 프로젝트를 위해 두 가지 대안적 물리 엔진을 제공한다.
| 비교 항목 | Built-in PhysX | Unity Physics (ECS) | Havok Physics for Unity |
|---|---|---|---|
| 아키텍처 | MonoBehaviour 기반 | ECS/DOTS 기반 | ECS/DOTS 기반 |
| 상태 관리 | 상태 유지(Stateful) | 상태 비저장(Stateless) | 상태 유지(Stateful) |
| 성능 특성 | 단일 스레드 위주 | Burst/Job System 최적화 | 지능적 캐싱, AAA급 안정성 |
| 결정론성 | 비결정론적 | 결정론적(Deterministic) | 결정론적 |
| 적합 시나리오 | 일반적 게임 개발 | 네트워크 동기화, 커스터마이징 | 대규모 오픈월드, AAA 타이틀 |
| 데이터 프로토콜 | 독자적 | 공통 ECS 프로토콜 | 공통 ECS 프로토콜 |
| 라이선스 | Unity에 포함 | Unity에 포함 | 별도 라이선스 |
Unity Physics와 Havok Physics는 동일한 ECS 데이터 프로토콜을 공유하므로, 게임 코드나 컨텐츠를 재작성하지 않고도 두 엔진 간 전환이 가능하다. Unity Physics는 상태 비저장 방식으로 네트워크 시나리오에 유리하고, Havok은 상태 유지 기반의 지능적 캐싱으로 대규모 씬에서 우수한 성능을 보인다.
💡 참고: Unity Physics Design Philosophy, Physics for ECS - Unity Learn
🏗️ 2. 충돌 검출 아키텍처
🏗️ 2.1 전체 파이프라인 구조
PhysX의 충돌 검출은 크게 세 단계로 구성된다.
[Simulation Step]
|
v
+------------------+
| 1. Broad Phase | -- AABB 기반 대략적 겹침 검출 (후보 쌍 생성)
+------------------+
|
v
+------------------+
| 2. Narrow Phase | -- 정밀 형상 교차 검사 (실제 접촉점 계산)
+------------------+
|
v
+------------------+
| 3. Resolution | -- 접촉 응답 (힘 계산, 위치 보정)
+------------------+
|
v
[Integration] -- 속도/위치 업데이트
이 파이프라인은 매 Physics 시뮬레이션 스텝(기본 Fixed Timestep 0.02초, 즉 50Hz)마다 실행된다.
🔹 2.2 Broad Phase (넓은 범위 검출)
Broad Phase의 목적은 씬 내 모든 Collider의 AABB(Axis-Aligned Bounding Box)를 비교하여, 실제로 겹칠 가능성이 있는 후보 쌍(Candidate Pairs)을 빠르게 걸러내는 것이다. 이 단계에서는 정밀한 형상 교차 검사를 수행하지 않는다.
PhysX가 지원하는 Broad Phase 알고리즘은 다음과 같다.
▫️ 2.2.1 SAP (Sweep and Prune) - eSAP
가장 전통적인 알고리즘으로, 각 축을 따라 AABB의 시작점과 끝점을 정렬한 후 순차적으로 순회하며 겹침을 검출한다.
- 장점: 많은 오브젝트가 Sleep 상태일 때 매우 효율적 (증분 업데이트)
- 단점: 모든 오브젝트가 동시에 움직이거나, 대량의 오브젝트가 추가/제거될 때 성능이 급격히 저하
- 적합 시나리오: 정적 오브젝트가 대다수이고, 움직이는 오브젝트가 소수인 경우
▫️ 2.2.2 MBP (Multi-Box Pruning) - eMBP
PhysX 3.3에서 도입된 알고리즘으로, 공간을 여러 영역(Region)으로 분할하고 각 영역 내에서 독립적으로 Pruning을 수행한다.
- 장점: SAP의 성능 저하 문제를 해결, 모든 오브젝트가 움직이는 경우에도 안정적
- 단점: 사용자가 수동으로 월드 바운드(Broadphase Region)를 정의해야 함
- 적합 시나리오: 대규모 동적 씬, 월드 크기가 예측 가능한 경우
▫️ 2.2.3 ABP (Automatic Box Pruning) - eABP
PhysX 4.0에서 도입되었으며, MBP의 성능 이점을 유지하면서 SAP의 편의성(자동 월드 바운드 관리)을 결합한 알고리즘이다.
- 장점: MBP 수준의 성능 + 자동 월드 바운드 관리
- 단점: MBP 대비 약간의 오버헤드 (자동 관리 비용)
- 적합 시나리오: 대부분의 일반적인 게임 씬 (PhysX 4.x+ 기본값으로 권장)
Unity 2019.3 이후 ABP가 기본 Broad Phase 알고리즘으로 설정되어 있으며, Project Settings > Physics에서 변경할 수 있다.
▫️ 2.2.4 PABP (Parallel Automatic Box Pruning) - ePABP
PhysX 5.0에서 도입된 ABP의 멀티스레드 변형이다.
- 장점: 대규모 씬에서 병렬 처리를 통한 성능 향상
- 단점: 메모리 사용량 증가
- 적합 시나리오: 수천~수만 개의 동적 오브젝트가 존재하는 대규모 시뮬레이션
🎮 2.2.5 GPU Broadphase
PhysX 5.x에서 제공하는 GPU 가속 증분 Sweep-and-Prune 방식이다. 전통적 SAP의 이점과 GPU 병렬 처리의 장점을 결합한다.
🔹 2.3 Narrow Phase (좁은 범위 검출)
Broad Phase에서 생성된 후보 쌍에 대해, 실제 형상 간의 정밀 교차 검사를 수행하고 접촉점(Contact Point)을 생성하는 단계이다.
🧠 2.3.1 PCM (Persistent Contact Manifold) - PhysX 기본값
PhysX 3.4 이후 기본 Narrow Phase 알고리즘으로 채택된 PCM(Persistent Contact Manifold)은 거리 기반 충돌 검출 시스템이다.
PCM 동작 원리:
1. GJK 알고리즘으로 두 형상 간 최단 거리 또는 관통 깊이 계산
2. EPA 알고리즘으로 관통 시 최소 분리 벡터 계산
3. 접촉점 매니폴드를 프레임 간 재활용 (Persistent)
4. 새 프레임에서는 기존 접촉점 유효성 검증 후 필요시만 재계산
PCM의 핵심 장점은 프레임 간 접촉점을 재활용하여 Narrow Phase 비용을 크게 절감하는 것이다. Unity에서는 PxSceneFlag::eENABLE_PCM으로 제어된다.
🧠 2.3.2 GJK (Gilbert-Johnson-Keerthi) 알고리즘
두 볼록 형상(Convex Shape) 간의 최단 거리를 반복적으로 계산하는 알고리즘이다.
GJK 핵심 원리:
- 두 형상의 민코프스키 차(Minkowski Difference)를 직접 계산하지 않음
- 대신, 서포트 함수(Support Function)를 이용하여 심플렉스(Simplex)를 반복 구축
- 심플렉스가 원점을 포함하면 두 형상이 교차 -> EPA로 전환
- 심플렉스가 원점을 포함하지 않으면 비교차 -> 최단 거리 반환
GJK는 임의의 볼록 형상에 대해 일반적으로 적용 가능하며, 반복 횟수가 O(1)~O(n) 수준으로 매우 빠르다. PhysX는 내부적으로 Primitive Collider 쌍에 대해 전용 최적화된 GJK 변형을 사용한다.
▫️ 2.3.3 EPA (Expanding Polytope Algorithm)
GJK가 두 형상의 교차를 확인한 후, 관통 깊이(Penetration Depth)와 관통 방향(Penetration Normal)을 계산하는 알고리즘이다.
EPA 동작 흐름:
1. GJK로부터 원점을 포함하는 심플렉스를 전달받음
2. 심플렉스를 폴리토프(Polytope)로 확장
3. 폴리토프의 면 중 원점에 가장 가까운 면을 찾음
4. 해당 면 방향으로 새로운 서포트 포인트를 추가하여 폴리토프 확장
5. 수렴할 때까지 반복 -> 최소 관통 벡터(MTV) 산출
EPA의 결과인 최소 관통 벡터(Minimum Translation Vector)는 충돌 응답(Collision Resolution) 단계에서 오브젝트를 분리하는 데 직접 사용된다.
🧠 2.3.4 SAT (Separating Axis Theorem)
두 볼록 형상 사이에 분리축(Separating Axis)이 존재하면 두 형상은 교차하지 않는다는 정리에 기반한 알고리즘이다.
- PhysX의 레거시 Narrow Phase(PCM 이전)에서 주로 사용
- Box-Box, Box-Convex 등 특정 형상 쌍에 대해 전용 최적화 구현
- PCM 도입 이후에도 일부 특수 케이스에서 내부적으로 활용
💡 참고: Toptal - Video Game Physics Part II, Collision detection with SAT, GJK and EPA
🧠 2.4 Collision Filtering (충돌 필터링)
PhysX는 3단계 필터링 시스템을 구현한다. 가장 효율적인 것부터 순서대로 나열하면 다음과 같다.
- PxPairFilteringMode: Broadphase 단계에서 직접 키네마틱 쌍을 필터링. KEEP, SUPPRESS, KILL 모드 지원
- PxSimulationFilterShader: 사용자 정의 C 함수로 Broadphase 쌍을 처리. 외부 메모리 접근 불가하여 GPU 실행에 적합
- PxSimulationFilterCallback: 가장 유연하지만 가장 느림. Broadphase 이후 실행되며 전체 메모리 접근 가능
Unity에서는 이 3단계 시스템이 Layer Collision Matrix로 추상화되어 제공된다.
🔹 2.5 Contact Manifold 및 Collision Resolution
Narrow Phase에서 생성된 접촉점 집합(Contact Manifold)은 Solver로 전달되어 충돌 응답에 사용된다.
Contact Manifold -> Solver 처리 흐름:
1. 접촉점별 법선(Normal), 관통 깊이(Depth), 위치(Position) 정보 수집
2. 구속 조건(Constraint) 생성: 접촉 법선 방향 구속 + 마찰 구속
3. Solver 반복(Iteration): 구속 조건 만족하도록 속도/위치 보정
- PGS (Projected Gauss-Seidel): 기본 Solver
- TGS (Temporal Gauss-Seidel): PhysX 4.x+, 더 안정적
4. 최종 속도/위치 적분(Integration)
Unity에서 Solver Type은 Project Settings > Physics에서 선택 가능하다. TGS Solver는 조인트 안정성과 스태킹(Stacking) 시나리오에서 PGS보다 우수한 성능을 보인다.
💻 3. Unity Collider 종류 및 특성
⚡ 3.1 성능 순위별 Collider 분류
Unity 공식 문서에서 제시하는 Collider 성능 순위(가장 효율적인 순)는 다음과 같다.
| 순위 | Collider 타입 | 특성 | 권장 사용 |
|---|---|---|---|
| 1 | Sphere Collider | 가장 단순하고 효율적 | 둥근 오브젝트, 범용 상호작용 |
| 2 | Capsule Collider | Sphere보다 약간 복잡하지만 효율적 | 캐릭터, 기둥형 오브젝트 |
| 3 | Box Collider | 효율적이고 유연함 | 직육면체, 블록형 오브젝트 |
| 4 | Convex Mesh Collider | Primitive보다 비용 높음 | 복잡한 형상, 동적 오브젝트 |
| 5 | Non-Convex Mesh Collider | 가장 비용이 높음 | 정적 환경 지오메트리만 |
💻 3.2 Primitive Colliders
Box Collider
- 6면 검사로 교차 판정, 매우 빠름
- Size, Center 속성으로 크기/위치 조절
- 건물, 벽, 상자 등 직육면체 형태에 적합
Sphere Collider
- 중심점과 반지름만으로 교차 판정, 가장 빠름
- Radius, Center 속성
- 구형 오브젝트, 근접 감지 영역, 폭발 범위 등에 적합
Capsule Collider
- 원통 + 양쪽 반구로 구성
- Radius, Height, Direction, Center 속성
- 캐릭터 컨트롤러, 팔다리, 탄환 등에 적합
🎮 3.3 Mesh Collider
Mesh Collider는 3D 메시의 실제 폴리곤 형상을 충돌 영역으로 사용한다.
Convex Mesh Collider (Is Convex = true)
- 최대 255개 삼각형으로 제한
- 오목한 부분을 채워 볼록 껍질(Convex Hull) 생성
- 동적 Rigidbody에 부착 가능
- 다른 Convex/Primitive Collider와 충돌 가능
Non-Convex Mesh Collider (Is Convex = false)
- 메시의 실제 형상 그대로 사용
- 정적(Static) 또는 키네마틱(Kinematic) 오브젝트만 가능
- 두 Non-Convex Mesh Collider 간 충돌 불가
- 면이 단방향(One-sided)이므로 내부에서 외부로 통과 가능
Convex Decomposition (볼록 분해)
복잡한 오목 형상을 여러 볼록 형상으로 분해하여 동적 오브젝트에서도 정밀한 충돌을 구현하는 기법이다.
- V-HACD: 고전적 볼록 분해 알고리즘
- CoACD: 최신 볼록 분해 알고리즘 (커뮤니티에서 Unity 플러그인 제공)
💻 3.4 Terrain Collider
Unity Terrain 시스템과 연동되는 전용 Collider이다.
- Terrain Data의 높이맵(Heightmap)을 기반으로 충돌 영역 생성
- 트리/디테일 오브젝트에는 별도 Collider 필요
- 내부적으로 높이맵 기반 최적화된 Narrow Phase 사용
💻 3.5 Wheel Collider
차량 물리 시뮬레이션 전용 Collider이다.
- 내장 서스펜션, 타이어 마찰 모델, 슬립 기반 물리 시뮬레이션
- 레이캐스트 기반 지면 검출 (실제 메시 형상이 아닌 레이 사용)
motorTorque,brakeTorque,steerAngle등 차량 전용 프로퍼티- WheelHit 구조체로 접촉 정보 접근
💻 3.6 Compound Collider (복합 Collider) 전략
단일 Rigidbody에 여러 자식 Collider를 부착하여 복잡한 형상을 근사하는 방법이다.
[GameObject with Rigidbody]
|-- [Child] Box Collider (몸통)
|-- [Child] Sphere Collider (머리)
|-- [Child] Capsule Collider (팔)
|-- [Child] Capsule Collider (다리)
- Mesh Collider보다 성능이 우수하면서 형상 근사가 가능
- 동적 오목 형상에 대한 효과적 대안
- 히트박스 시스템 구현의 기본 패턴
🧠 4. Unity 충돌 검출 API
🧠 4.1 Collision 콜백 (물리적 충돌)
두 오브젝트가 물리적으로 충돌할 때 호출되는 콜백이다. 최소한 하나의 오브젝트에 Rigidbody가 부착되어 있어야 하고, 두 Collider 모두 isTrigger = false여야 한다.
// 충돌 시작 시 1회 호출
void OnCollisionEnter(Collision collision)
{
// collision.contacts: 접촉점 배열
// collision.relativeVelocity: 상대 속도
// collision.impulse: 충돌 충격량 (Unity 2018.3+)
// collision.gameObject: 상대 오브젝트
ContactPoint contact = collision.GetContact(0);
Vector3 hitPoint = contact.point;
Vector3 hitNormal = contact.normal;
float separation = contact.separation;
}
// 충돌 지속 중 매 Fixed Update마다 호출
void OnCollisionStay(Collision collision) { }
// 충돌 종료 시 1회 호출
void OnCollisionExit(Collision collision) { }
ContactPoint 구조체 주요 필드:
point: 접촉 위치 (World Space)normal: 접촉 법선 (첫 번째 Collider 기준 외부 방향)separation: 두 Collider 간 거리 (음수면 관통)thisCollider/otherCollider: 접촉에 관여한 Collider 참조
🔹 4.2 Trigger 콜백 (영역 감지)
Collider의 isTrigger = true일 때 사용되는 콜백이다. 물리적 충돌 응답은 발생하지 않고, 영역 진입/이탈만 감지한다.
void OnTriggerEnter(Collider other)
{
// other: 트리거 영역에 진입한 Collider
if (other.CompareTag("Player"))
{
// 플레이어가 영역에 진입
}
}
void OnTriggerStay(Collider other) { }
void OnTriggerExit(Collider other) { }
주의사항: Trigger 콜백이 발생하려면 두 오브젝트 중 최소 하나에 Rigidbody(또는 Kinematic Rigidbody)가 부착되어 있어야 한다.
💻 4.3 Physics Cast 계열 API
특정 형상을 특정 방향으로 투사(Cast)하여 경로상의 충돌을 검출하는 API이다.
// Raycast: 직선 광선 투사
bool hit = Physics.Raycast(origin, direction, out RaycastHit hitInfo, maxDistance, layerMask);
// SphereCast: 구 형상 투사
bool hit = Physics.SphereCast(origin, radius, direction, out RaycastHit hitInfo, maxDistance);
// BoxCast: 박스 형상 투사
bool hit = Physics.BoxCast(center, halfExtents, direction, out RaycastHit hitInfo,
orientation, maxDistance, layerMask);
// CapsuleCast: 캡슐 형상 투사
bool hit = Physics.CapsuleCast(point1, point2, radius, direction, out RaycastHit hitInfo,
maxDistance, layerMask);
각 Cast API는 NonAlloc 변형을 제공하여 GC 할당을 방지한다.
// NonAlloc: 미리 할당된 배열 재사용 (GC 프리)
RaycastHit[] results = new RaycastHit[10];
int count = Physics.RaycastNonAlloc(origin, direction, results, maxDistance, layerMask);
💻 4.4 Physics Overlap 계열 API
특정 영역 내 존재하는 모든 Collider를 검출하는 API이다.
// OverlapSphere: 구 영역 내 모든 Collider 검출
Collider[] colliders = Physics.OverlapSphere(center, radius, layerMask);
// OverlapBox: 박스 영역 내 모든 Collider 검출
Collider[] colliders = Physics.OverlapBox(center, halfExtents, orientation, layerMask);
// OverlapCapsule: 캡슐 영역 내 모든 Collider 검출
Collider[] colliders = Physics.OverlapCapsule(point0, point1, radius, layerMask);
// NonAlloc 변형 (권장)
Collider[] buffer = new Collider[50];
int count = Physics.OverlapSphereNonAlloc(center, radius, buffer, layerMask);
💡 성능 팁:
Physics.OverlapSphere는 매 호출마다 배열을 새로 할당하므로 GC 부담이 있다. 프레임마다 호출하는 경우 반드시Physics.OverlapSphereNonAlloc을 사용해야 한다.
💻 4.5 고급 쿼리 API
// ComputePenetration: 두 Collider 간 최소 분리 벡터 계산
bool overlapping = Physics.ComputePenetration(
colliderA, positionA, rotationA,
colliderB, positionB, rotationB,
out Vector3 direction, out float distance
);
// 제약: 하나 이상의 Collider가 Box/Sphere/Capsule/Convex Mesh여야 함
// 용도: 커스텀 캐릭터 컨트롤러의 디페네트레이션(Depenetration)
// ClosestPoint: 특정 위치에서 Collider 표면의 최근접점 계산
Vector3 closest = Physics.ClosestPoint(point, collider, colliderPosition, colliderRotation);
// 위치가 Collider 내부/경계면이면 입력 위치 그대로 반환
💡 참고: Unity API - Physics.ComputePenetration, Unity API - Physics.ClosestPoint
🗄️ 4.6 Layer Collision Matrix 및 QueryTriggerInteraction
Layer Collision Matrix는 Edit > Project Settings > Physics에서 설정하며, 어떤 레이어 간에 충돌을 허용할지를 행렬로 정의한다.
Player Enemy Bullet Environment Trigger
Player O O O O O
Enemy O X O O O
Bullet O O X O X
Environment O O O X O
Trigger O O X O X
QueryTriggerInteraction은 Physics 쿼리(Raycast, Overlap 등)가 Trigger Collider를 어떻게 처리할지 제어한다.
public enum QueryTriggerInteraction
{
UseGlobal = 0, // Physics.queriesHitTriggers 전역 설정 따름
Ignore = 1, // Trigger 무시
Collide = 2 // Trigger 포함
}
// 사용 예: Trigger를 무시하는 Raycast
Physics.Raycast(ray, out hit, maxDist, layerMask, QueryTriggerInteraction.Ignore);
💡 참고: Unity API - QueryTriggerInteraction, Unity Manual - Layer-based collision detection
🛠️ 5. 충돌 검출 모드 및 설정
🔹 5.1 Discrete Collision Detection
기본 모드이며, 각 물리 시뮬레이션 스텝의 시작과 끝 위치에서만 충돌을 검사한다.
프레임 N 프레임 N+1
[A]-------> -----[A]
[B] [B]
터널링 발생: A가 B를 완전히 통과해 버림
- 성능: 가장 가볍고 빠름
- 한계: 고속 이동 오브젝트가 얇은 Collider를 통과(Tunneling)할 수 있음
- 적합 시나리오: 저속 오브젝트, 두꺼운 Collider, 성능이 중요한 경우
🔹 5.2 Continuous Collision Detection (CCD)
고속 이동 오브젝트의 터널링을 방지하기 위해 물리 스텝 사이의 경로를 예측하여 충돌을 검출한다.
▫️ 5.2.1 Sweep-based CCD
오브젝트의 이동 경로를 따라 형상을 Sweep하여 최초 충돌 시점을 정밀하게 계산한다.
Continuous 모드:
- Dynamic Rigidbody가 Static Collider와의 터널링만 방지
- Dynamic-Dynamic 간에는 Discrete로 처리
- Box, Sphere, Capsule Collider만 지원
Continuous Dynamic 모드:
- Dynamic Rigidbody가 Static 및 Dynamic Collider 모두와의 터널링 방지
- 가장 높은 정확도, 가장 높은 비용
PhysX 설정 파라미터:
ccdMaxPasses: Sweep 반복 횟수 (기본 1, 높을수록 정밀하지만 비용 증가)setMinCCDAdvanceCoefficient(): CCD 전진 계수 (기본 0.15, 0~1 범위)eENABLE_CCD_FRICTION: CCD 중 마찰 적용 여부 (기본 비활성)
▫️ 5.2.2 Speculative CCD (Continuous Speculative)
Sweep 대신 오브젝트의 선형/각속도를 기반으로 AABB를 확장하여, 다음 프레임에서 가능한 모든 접촉을 예측하는 방식이다.
일반 AABB: 확장된 AABB (Speculative):
+---+ +----------+
| A | | |
+---+ | A -> |
| |
+----------+
이동 방향으로 AABB를 확장하여 잠재적 충돌 감지
- 장점:
- Sweep-based보다 저렴한 연산 비용
- 빠른 각운동(회전)에 의한 누락 접촉도 감지
- 키네마틱 액터에도 적용 가능 (Sweep CCD는 불가)
- 모든 Collider 타입에서 작동
- 단점:
- Solver의 가속도에 의해 완전한 관통이 발생하면 실패할 수 있음
- 물리적으로 완벽하게 정확한 결과를 보장하지 않음
- “유령 충돌(Ghost Collision)” 현상 가능 (실제로 충돌하지 않을 오브젝트와 반응)
Unity 권장: Continuous Speculative가 대부분의 경우 최적의 CCD 모드이며, 유사하거나 더 나은 터널링 방지 성능을 더 낮은 비용으로 제공한다.
PhysX 5.x 하이브리드: PhysX 5.0부터 Sweep-based CCD와 Speculative CCD를 동시에 활성화할 수 있어, 두 방식의 장점을 결합할 수 있다.
💡 참고: Unity Manual - Continuous collision detection, Unity Manual - Speculative CCD, PhysX 5.4.1 - Advanced Collision Detection
⚖️ 5.3 충돌 검출 모드 비교 요약
| 모드 | 터널링 방지 대상 | 지원 Collider | 비용 | 비고 |
|---|---|---|---|---|
| Discrete | 없음 | 모두 | 최저 | 기본값 |
| Continuous | Static만 | Box/Sphere/Capsule | 중간 | Sweep 기반 |
| Continuous Dynamic | Static + Dynamic | Box/Sphere/Capsule | 최고 | Sweep 기반 |
| Continuous Speculative | Static + Dynamic | 모두 | 중~저 | AABB 확장 기반 (권장) |
🧠 5.4 Fixed Timestep과 충돌 검출
Unity의 물리 시뮬레이션은 Fixed Timestep(기본 0.02초 = 50Hz)마다 실행된다.
// Fixed Timestep 설정
Time.fixedDeltaTime = 0.02f; // 50Hz (기본값)
Time.fixedDeltaTime = 0.01f; // 100Hz (더 정밀하지만 2배 비용)
// 수동 시뮬레이션 제어
Physics.autoSimulation = false; // 자동 시뮬레이션 비활성화
Physics.Simulate(Time.fixedDeltaTime); // 수동으로 시뮬레이션 스텝 실행
Fixed Timestep을 줄이면 더 정밀한 충돌 검출이 가능하지만, 시뮬레이션 비용이 비례하여 증가한다. CCD를 사용하는 것이 Timestep을 줄이는 것보다 일반적으로 효율적이다.
⚡ 6. 성능 최적화 기법
🚀 6.1 Layer Collision Matrix 최적화
가장 비용이 낮고 효과가 큰 최적화 기법이다.
최적화 전: 모든 레이어 간 충돌 활성 (기본값)
-> N개 레이어에 대해 N*(N+1)/2 쌍 검사
최적화 후: 필요한 쌍만 활성
-> 불필요한 Broad Phase 후보 쌍 자체를 제거
실천 가이드라인:
- 프로젝트 초기에 레이어 구조를 설계
- “Player”, “Enemy”, “Bullet”, “Environment”, “Trigger”, “UI” 등 명확한 레이어 분리
- 주기적으로 매트릭스를 검토하여 불필요한 활성 쌍 비활성화
- 동일 레이어 내 충돌이 불필요한 경우 대각선 체크 해제
💻 6.2 Collider 단순화
성능 비용 순서:
Sphere < Capsule < Box << Convex Mesh <<< Non-Convex Mesh
실전 지침:
- 동적 오브젝트: Primitive Collider 또는 Compound Collider 사용
- 정적 환경: Non-Convex Mesh Collider 허용
- 복잡한 동적 형상: Convex Decomposition 또는 Compound Collider
⚖️ 6.3 Static vs Dynamic Collider
Static Collider: Collider만 있고 Rigidbody 없음
-> PhysX가 정적 데이터 구조에 저장, 매우 효율적
-> 절대 Transform을 직접 이동시키지 말 것! (Broadphase 전체 재구축 유발)
Dynamic Collider: Collider + Rigidbody
-> Rigidbody를 통해 이동해야 최적 성능
-> MovePosition/MoveRotation 또는 AddForce 사용
Kinematic Collider: Collider + Rigidbody (isKinematic = true)
-> 코드로 직접 Transform 제어 가능
-> 움직이지만 물리 힘의 영향을 받지 않는 오브젝트용
핵심 주의점: Rigidbody 없이 Collider만 있는 오브젝트의 Transform을 매 프레임 변경하면, PhysX 내부에서 정적 지오메트리가 매번 재구축되어 심각한 성능 저하가 발생한다.
🏢 6.4 Rigidbody Sleep 상태 활용
PhysX는 운동 에너지가 임계값 이하로 떨어진 Rigidbody를 자동으로 Sleep 상태로 전환한다.
// Sleep 관련 API
rigidbody.sleepThreshold = 0.005f; // Sleep 진입 임계값 (기본 0.005)
rigidbody.WakeUp(); // 강제 깨움
rigidbody.Sleep(); // 강제 Sleep
bool isSleeping = rigidbody.IsSleeping();
// 최적화 팁: WakeUp()을 매 프레임 호출하지 말 것
// Sleep 상태의 Rigidbody는 Broad Phase에서 거의 비용 0
🎮 6.5 Physics.BakeMesh
런타임에 Mesh Collider를 생성하면 메시 쿠킹(Cooking) 과정에서 CPU 스파이크가 발생한다.
// 사전 베이킹으로 런타임 스파이크 방지
Physics.BakeMesh(mesh.GetInstanceID(), convex: false);
// 빌드 시 자동 베이킹: Player Settings > Prebake Collision Meshes (기본 활성)
// 에디터에서 씬/프리팹 저장 시 자동 베이킹
// 프로시저럴 메시의 경우: 로딩 화면에서 BakeMesh 호출 권장
🛠️ 6.6 Broadphase 설정 튜닝
Unity Project Settings > Physics에서 Broad Phase 알고리즘을 변경할 수 있다.
| 설정 | 적합 시나리오 |
|---|---|
| Automatic Box Pruning (기본) | 대부분의 게임 |
| Sweep and Prune | 정적 오브젝트 대다수, 이동 오브젝트 소수 |
| Multi Box Pruning | 대규모 월드, 수동 영역 관리 가능 시 |
⚡ 6.7 Profiler를 이용한 물리 성능 분석
Unity Profiler의 Physics 모듈에서 확인할 수 있는 핵심 지표:
- Physics.Processing: 전체 물리 시뮬레이션 시간
- Physics.Simulation: 시뮬레이션 스텝 실행 시간
- Broadphase: Broad Phase 소요 시간
- NarrowPhase: Narrow Phase 소요 시간
- Solver: 충돌 응답 Solver 시간
- Contacts: 활성 접촉점 수
- Active Rigidbodies: 활성(비-Sleep) Rigidbody 수
Physics Debug Visualization(Window > Analysis > Physics Debugger)으로 Collider 형상, 접촉점, AABB를 시각적으로 확인할 수 있다.
🚀 6.8 ECS/DOTS 기반 최적화 (Unity Physics)
전통적 PhysX (MonoBehaviour):
- 단일 스레드 위주 처리
- GC 할당 발생 (콜백 기반)
- 비결정론적
Unity Physics (ECS):
- Burst Compiler로 네이티브 코드 수준 최적화
- Job System으로 멀티스레드 병렬 처리
- 결정론적 시뮬레이션
- GC 할당 없음 (NativeArray 기반)
대규모 물리 시뮬레이션이 필요한 경우 ECS 기반 Unity Physics로의 마이그레이션이 근본적 성능 개선을 가져올 수 있다. 2025년 기준 Broadphase의 증분 업데이트(Incremental BVH)가 도입되어, 대규모 씬에서 소수만 변경되는 경우 극적인 성능 향상이 가능하다.
💡 참고: Unity Physics Changelog 1.3.14, Physics development status - May 2025
🏢 7. 고급 기능 및 활용 사례
🔹 7.1 ContactModifyEvent (Unity 2022.2+)
Unity 2022.2에서 도입된 Contact Modification API는 PhysX의 접촉 수정 기능을 Unity 스크립트에서 직접 활용할 수 있게 해준다.
// 1. Collider에 수정 가능 플래그 설정
collider.hasModifiableContacts = true;
// 2. 콜백 등록
Physics.ContactModifyEvent += OnContactModify;
// 3. 접촉 수정 콜백 구현
void OnContactModify(PhysicsScene scene, NativeArray<ModifiableContactPair> pairs)
{
for (int i = 0; i < pairs.Length; i++)
{
ModifiableContactPair pair = pairs[i];
for (int j = 0; j < pair.contactCount; j++)
{
// 접촉점 위치, 법선, 분리 거리 수정 가능
pair.SetNormal(j, Vector3.up);
pair.SetSeparation(j, 0.01f);
pair.SetMaxImpulse(j, 100f);
}
}
}
// CCD 전용 버전도 제공
Physics.ContactModifyEventCCD += OnContactModifyCCD;
성능: 전통적인 OnCollisionEnter 콜백 대비 약 4배 빠른 접촉 데이터 읽기 성능을 제공한다. NativeArray를 통한 직접 접근이 마샬링 오버헤드를 제거하기 때문이다.
활용 예시:
- 컨베이어 벨트: 접촉점에 목표 속도 설정
- 단방향 플랫폼: 특정 방향의 접촉만 허용
- 소프트 충돌: 최대 임펄스 제한
- 커스텀 마찰 모델: 접촉별 마찰 계수 동적 변경
💡 참고: Unity API - Physics.ContactModifyEvent, WaveAccess - Contacts Modification API
🔹 7.2 Ragdoll 물리
래그돌은 캐릭터의 각 뼈(Bone)에 Rigidbody와 Collider를 부착하고, CharacterJoint로 연결하여 물리 기반 자연스러운 쓰러짐/날아감 애니메이션을 구현하는 기법이다.
래그돌 구성 요소:
- 각 주요 뼈마다: Rigidbody + Collider (보통 Capsule) + CharacterJoint
- 머리, 몸통, 상완, 전완, 허벅지, 종아리, 발 등 10~15개 노드
전환 패턴:
1. 일반 상태: Animator 활성, Rigidbody.isKinematic = true
2. 래그돌 상태: Animator 비활성, Rigidbody.isKinematic = false
3. 블렌딩: 래그돌 -> 애니메이션 부드러운 전환 (Active Ragdoll)
주의사항: 래그돌 Collider가 서로 겹치면 PhysX가 이를 분리하려 시도하면서 뼈가 비정상적으로 변형될 수 있다.
💻 7.3 차량 물리 (WheelCollider)
[System.Serializable]
public class AxleInfo
{
public WheelCollider leftWheel;
public WheelCollider rightWheel;
public bool motor; // 구동축 여부
public bool steering; // 조향축 여부
}
public class CarController : MonoBehaviour
{
public List<AxleInfo> axleInfos;
public float maxMotorTorque;
public float maxSteeringAngle;
void FixedUpdate()
{
float motor = maxMotorTorque * Input.GetAxis("Vertical");
float steering = maxSteeringAngle * Input.GetAxis("Horizontal");
foreach (AxleInfo info in axleInfos)
{
if (info.steering)
{
info.leftWheel.steerAngle = steering;
info.rightWheel.steerAngle = steering;
}
if (info.motor)
{
info.leftWheel.motorTorque = motor;
info.rightWheel.motorTorque = motor;
}
}
}
}
WheelCollider는 내부적으로 레이캐스트 기반 지면 검출과 슬립 기반 타이어 마찰 모델을 사용하며, 서스펜션 시뮬레이션까지 내장되어 있다.
🏢 7.4 BIM/건축 분야에서의 Clash Detection 활용
BIM(Building Information Modeling)에서의 Clash Detection은 건축 모델의 각 분야(건축, 구조, 기계, 전기, 배관 등) 3D 요소 간 물리적 간섭을 사전에 검출하는 프로세스이다.
Unity PhysX를 BIM Clash Detection에 활용하는 접근법:
BIM 모델 (IFC/Revit)
|
v
[Unity로 임포트] -- FBX/glTF/IFC 파서
|
v
[Collider 자동 생성] -- MeshCollider 또는 Compound Collider
|
v
[Physics.OverlapBox / ComputePenetration]
|
v
[Clash Report 생성] -- 간섭 위치, 관련 요소, 심각도 분류
Clash 유형과 PhysX 활용:
- Hard Clash: 두 요소가 물리적으로 겹침 ->
Physics.ComputePenetration으로 관통 깊이 계산 - Soft Clash: 최소 이격 거리 미확보 ->
Physics.ClosestPoint로 최근접 거리 계산 - Clearance Clash: 유지보수 접근 공간 부족 ->
Physics.OverlapBox로 영역 내 간섭 검출
💡 참고: BIM Clash Detection - Autodesk, Clash Detection in BIM - United-BIM
⚖️ 7.5 ECS 기반 Unity Physics vs 기존 PhysX
Built-in PhysX:
+ 풍부한 API, 성숙한 에코시스템
+ WheelCollider, Cloth, Ragdoll 등 전용 기능
+ 대부분의 Unity 에셋/튜토리얼 호환
- 단일 스레드 병목
- GC 할당 (콜백)
- 비결정론적
Unity Physics (ECS):
+ Burst + Job System 병렬 처리
+ 결정론적 시뮬레이션 (네트워크 동기화)
+ GC 프리
+ 커스터마이징 용이 (소스 접근 가능)
- API 상대적 미성숙
- 전용 기능 부족 (래그돌, 차량 등 직접 구현 필요)
- 학습 곡선 높음
🏢 8. 실제 활용 패턴
🔹 8.1 히트박스 시스템 (Hit Detection)
격투/슈팅 게임에서의 공격 판정 시스템이다.
public class HitboxSystem : MonoBehaviour
{
[Header("히트박스 설정")]
public LayerMask hitLayer;
public float attackRadius = 1.0f;
private Collider[] hitBuffer = new Collider[20];
public void PerformAttack(Vector3 attackOrigin)
{
// NonAlloc으로 GC 방지
int hitCount = Physics.OverlapSphereNonAlloc(
attackOrigin, attackRadius, hitBuffer, hitLayer,
QueryTriggerInteraction.Collide
);
for (int i = 0; i < hitCount; i++)
{
IDamageable target = hitBuffer[i].GetComponent<IDamageable>();
if (target != null)
{
// 가장 가까운 접촉점 계산
Vector3 hitPoint = Physics.ClosestPoint(
attackOrigin, hitBuffer[i],
hitBuffer[i].transform.position,
hitBuffer[i].transform.rotation
);
target.TakeDamage(10f, hitPoint);
}
}
}
}
🔹 8.2 근접 감지 (Proximity Detection)
Trigger Collider를 이용한 영역 기반 감지 시스템이다.
public class ProximityDetector : MonoBehaviour
{
public float detectionRadius = 10f;
private SphereCollider triggerZone;
private HashSet<Transform> detectedObjects = new HashSet<Transform>();
void Start()
{
triggerZone = gameObject.AddComponent<SphereCollider>();
triggerZone.isTrigger = true;
triggerZone.radius = detectionRadius;
}
void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Enemy"))
{
detectedObjects.Add(other.transform);
OnEnemyDetected(other.transform);
}
}
void OnTriggerExit(Collider other)
{
if (other.CompareTag("Enemy"))
{
detectedObjects.Remove(other.transform);
OnEnemyLost(other.transform);
}
}
void OnEnemyDetected(Transform enemy) { /* 경고 UI 표시 등 */ }
void OnEnemyLost(Transform enemy) { /* 경고 해제 등 */ }
}
🔹 8.3 지형 위 오브젝트 배치
Raycast를 이용한 지형 표면 스냅 배치 시스템이다.
public class TerrainPlacer : MonoBehaviour
{
public LayerMask terrainLayer;
public bool PlaceOnTerrain(Vector3 worldPosition, out Vector3 placedPosition, out Quaternion placedRotation)
{
Ray ray = new Ray(worldPosition + Vector3.up * 100f, Vector3.down);
if (Physics.Raycast(ray, out RaycastHit hit, 200f, terrainLayer))
{
placedPosition = hit.point;
// 지형 법선에 맞춰 회전
placedRotation = Quaternion.FromToRotation(Vector3.up, hit.normal);
return true;
}
placedPosition = worldPosition;
placedRotation = Quaternion.identity;
return false;
}
}
🔹 8.4 물리 기반 파괴 시스템
충돌 충격량 기반의 오브젝트 파괴 시스템이다.
public class Destructible : MonoBehaviour
{
public float destructionThreshold = 50f;
public GameObject fracturedPrefab;
void OnCollisionEnter(Collision collision)
{
// 충돌 충격량으로 파괴 여부 판단
float impactForce = collision.impulse.magnitude / Time.fixedDeltaTime;
if (impactForce > destructionThreshold)
{
// 파편 생성
GameObject fractured = Instantiate(fracturedPrefab,
transform.position, transform.rotation);
// 파편에 충돌 힘 전달
foreach (Rigidbody rb in fractured.GetComponentsInChildren<Rigidbody>())
{
rb.AddExplosionForce(impactForce * 0.5f,
collision.GetContact(0).point, 5f);
}
Destroy(gameObject);
}
}
}
🧠 8.5 대규모 오브젝트 충돌 처리 전략
수천 개 이상의 오브젝트가 존재하는 대규모 씬에서의 최적화 전략을 정리한다.
1. 공간 분할 (Spatial Partitioning)
- Unity Physics의 BVH (Bounding Volume Hierarchy) 활용
- 필요 시 커스텀 옥트리/그리드 구현
2. LOD 기반 물리 (Physics LOD)
- 원거리: 충돌 검출 비활성 또는 단순 Collider
- 중거리: Primitive Collider만 활성
- 근거리: 정밀 Mesh Collider 활성
3. 분할 시뮬레이션
- Physics.autoSimulation = false
- 프레임별로 영역을 나누어 순차 시뮬레이션
- 또는 Physics Scene 분리 (Multi-Scene Physics)
4. 배치 처리
- OverlapNonAlloc 계열 API로 GC 최소화
- 결과를 프레임에 분산 처리 (시간 분할)
🔗 9. 참고 자료
🔹 공식 문서
🧠 NVIDIA PhysX 문서
| 출처 | URL |
|---|---|
| PhysX 5.4.0 - Rigid Body Collision | https://nvidia-omniverse.github.io/PhysX/physx/5.4.0/docs/RigidBodyCollision.html |
| PhysX 5.4.1 - Advanced Collision Detection | https://nvidia-omniverse.github.io/PhysX/physx/5.4.1/docs/AdvancedCollisionDetection.html |
| PhysX 5.5.0 - Advanced Collision Detection | https://nvidia-omniverse.github.io/PhysX/physx/5.5.0/docs/AdvancedCollisionDetection.html |
| PhysX SDK - NVIDIA Developer | https://developer.nvidia.com/physx-sdk |
| PhysX - Wikipedia | https://en.wikipedia.org/wiki/PhysX |
🔹 Unity 블로그 및 커뮤니티
| 출처 | URL |
|---|---|
| Physics updates in Unity 2019.3 | https://blog.unity.com/technology/physics-updates-in-unity-2019-3 |
| Physics changes in Unity 2022.2 | https://unity.com/blog/engine-platform/physics-changes-in-unity-2022-2 |
| Physics development status (May 2025) | https://discussions.unity.com/t/physics-development-status-and-next-milestones-may-2025/1637988 |
| ECS Physics vs PhysX Test | https://discussions.unity.com/t/ecs-physics-vs-physx-test/948446 |
| Unity Forum - PhysX 4.x Switch | https://discussions.unity.com/t/did-unity-switch-to-physx-4-x-sdk/925300 |
| Contacts Modification API (WaveAccess) | https://medium.com/waveaccess/contacts-modification-api-in-unity-d65deba6f7c |
| CoACD Convex Decomposition Plugin | https://discussions.unity.com/t/free-better-convex-mesh-collider-generator-coacd/931964 |
| ClosestPoint and ContactPoint Tutorial | https://www.immersivelimit.com/tutorials/closestpoint-and-contactpoint-collision-in-unity |
🧠 알고리즘 및 학술 자료
| 출처 | URL |
|---|---|
| Video Game Physics Part II (Toptal) | https://www.toptal.com/game/video-game-physics-part-ii-collision-detection-for-solid-objects |
| Collision detection with SAT, GJK and EPA | https://glushchenkoblog.wordpress.com/2017/08/29/primitives-collision-detection-with-sat-gjk-and-epa/ |
| Building a Collision Engine - GJK | https://blog.hamaluik.ca/posts/building-a-collision-engine-part-1-2d-gjk-collision-detection/ |
| Newcastle University - Broad/Narrow Phase | https://research.ncl.ac.uk/game/mastersdegree/gametechnologies/physicstutorials/6accelerationstructures/Physics%20-%20Spatial%20Acceleration%20Structures.pdf |
| PhysX Creator Blog - GJK/EPA History | http://www.codercorner.com/blog/?p=1303 |
리서치 요청
md 파일 생성
백그라운드에서 sub agent 로 진행
Unity PhysX 기반 충돌 검출 기능