언리얼에서 제공하는 AVolume이 기하를 표현하는 방법을 살펴보자
볼륨은 3D 영역을 구획하는 액터로 실제 기하 정보는 부모 클래스인 ABrush에 존재한다.

ABrush가 실제로 사용하는 PrimitiveComponent로 렌더링/물리(충돌)을 담당한다.
Model을 하드레퍼런싱 하고 있는데, Model 정보가 변경 되면 내부 정보를 싱크 맞추기 위해 업데이트한다.
Physics가 사용하는 Collision정보이다.
UBrushComponent::BuildSimpleBrushCollision() 를 통해 Model 정보를 빌드한다.


단순 Collision Shape 집합으로 Box, Sphere, Capsule, Convex로 구분해 분류한다.
해당 정보를 통해 Chaos 물리를 사용한다.

리프까지 내려간 뒤 AddConvex를 하는것을 볼 수 있다.

Brush의 실제 BSP 지오메트리 저장소로 모든 Polygon정보와 BSPTree를 구성한다.
원본 Polygon 정보를 그대로 보관한다.
이는 지오메트리 편집 시 사용된다. (따라서 에디터 전용이다.)
해당 정보를 FBspNode로 변환하여 런타임에 사용된다.
BSP Tree의 노드로 UPolys를 BspBuild하여 Node로 저장한다.


공간 전체를 평면 하나로 두 쪽으로 자르는 일을 재귀적으로 반복해서, 공간을 이진 트리로 표현하는 기법
평면 하나는 공간을 정확히 두 반공간(front/back)으로 나눈다.
각 반공간을 또 자르면 트리가 되고, 내부 노드는 분할 평면, 리프는 더 이상 자르지 않은 공간 조각이 된다.
평면으로만 잘랐으므로 리프 영역은 항상 볼록(convex)하다.

"점 P가 어느 조각에 있나?"는 루트부터 평면 부호 검사(앞? 뒤?)만 반복하면 리프에 떨어진다.
전체 폴리곤을 뒤질 필요 없이 트리 깊이만큼의 내적 연산으로 끝난다.
볼륨 내부 판정(EncompassesPoint)류 쿼리의 원형이다.

브러시를 월드에서 빼는(Subtract) 연산을 생각하자.
브러시 폴리곤들을 월드 BSP에 흘려보내면 각 조각이 "월드 솔리드 내부에 있음 / 빈 공간에 있음"으로 분류된다.
Subtract에서는 솔리드 내부에 들어간 브러시 폴리 조각이 뒤집혀 새 표면이 되고, 반대로 브러시 내부에 들어간 월드 폴리 조각은 제거된다.

리프가 항상 볼록하다는 성질의 실용적 결과: 오목한 임의 형상도 BSP를 만들고 솔리드 리프만 모으면 겹침 없는 볼록 조각 목록이 된다.
물리 엔진(Chaos)은 볼록체를 좋아하므로, 이것이 브러시/볼륨 충돌 캐시(FKConvexElem)를 만드는 방법이다.

언리얼식 BSP는 분할 평면을 따로 두지 않고 입력 폴리곤 자신을 스플리터로 쓴다(auto-partitioning).
그래서 어떤 폴리곤을 먼저 고르느냐가 트리 품질을 좌우한다.
스플리터 평면에 걸치는 폴리곤은 둘로 쪼개져(SP_Split) 개수가 늘고, 분할을 아끼면 트리가 한쪽으로 길어진다.
UE의 FindBestSplit이 이 둘을 Balance 가중치로 점수화해 고른다.
