PhysX의 Geometry Query란 쉽게 말해 Geometry에 대한 충돌 검색 기능이라고 한다
Raycast - 레이(빛 줄기)를 Geometry와 테스트한다
Swift - 한 Geometry를 다른 Geometry와 교차하는 첫 번째 점을 찾기 위해 라인을 따라 이동하는 것
Overlap - 두 개의 Geometry가 교차하는지 여부를 결정한다
MTD(Minimal Translational Distance Queries) - 두 개의 Geometry를 테스트하여, 최소 거리로 분리할 수 있는 방향을 찾는 것 (충돌한 Geometry를 적절히 이동시켜서 겹침을 없앨 수 있는 최소 거리 및 이동 방향을 계산하는 기능)
Raycast Query
- 하나의 점에서 출발해서 지정된 방향으로 라인 세그먼트를 따라 추적한다
*라인 세그먼트란 선을 의미하며, 시작점과 끝점을 가진다
- 라인 세그먼트를 따라 추적 중에 다른 Geometry와 충돌할 경우 그 충돌 지점을 반환한다.
- PhysX는 모든 종류의 Geometry에 대해 Raycast를 지원하므로, Raycast Query를 사용하면
어떤 Geometry와 충돌하는지를 빠르게 검출할 수 있다.
- 아래 코드는 Raycast Query를 사용하는 예시이다.
PxRaycastHit hitInfo;
PxU32 maxHits = 1;
PxHitFlags hitFlags = PxHitFlag::ePOSITION|PxHitFlag::eNORMAL|PxHitFlag::eUV;
PxU32 hitCount = PxGeometryQuery::raycast(origin, unitDir,
geom, pose,
maxDist,
hitFlags,
maxHits, &hitInfo);
- origin : 레이의 시작점
- unitDir : 레이의 방향을 정의하는 단위 벡터
- maxDist : 레이를 따라 검색할 최대 거리 (0~inf 범위 내에 있어야 함)
- geom : 테스트할 Geometry
- pose : geom의 위치
- hitFlags : 쿼리에서 반환해야 할 값을 지정하고 쿼리를 처리하는 옵션
- maxHits : 반환할 최대 충돌 수
- hitInfo : PxRaycastHit 구조체를 받으며, 레이캐스트 결과 저장
반환 결과는 찾은 교차점의 수
각 교차점마다 PxRaycastHit가 생성되며, PxRaycastHit의 멤버는 아래와 같다.
PxRigidActor* actor;
PxShape* shape;
PxVec3 position;
PxVec3 normal;
PxF32 distance;
PxHitFlags flags;
PxU32 faceIndex;
PxF32 u, v;
- 이 멤버를 전부 다 채울 필요는 없음
- 쿼리는 입력된 hitFlags에 해당하는 flags가 설정된 경우에만 출력되는 구조체의 필드를 채운다
ex) PxHitFlag::ePOSITION이 설정되면 쿼리는 PxRaycastHit::position 필드를 채우고, PxRaycastHit::flags에 PxHitFlag::ePOSITION 플래그를 설정한다
- 이 때 입력에서 eNORMAL 및 ePOSITION 플래그를 생략하면 더 빠른 쿼리 결과를 얻을 수 있다.
- 초기에 Geometry와 교차하지 않는 raycast의 경우 필드는 다음과 같이 채워진다.
- actor와 shape는 채워지지 않는다. (이 필드는 Scene 레벨에서의 Raycast에서 채워진다)
- position : PxHitFlag::ePOSITION : 교차점의 위치
- normal : PxHitFlag::eNORMAL : 교차점 표면에서의 노멀벡터(법선벡터)
- distance : 교차가 발생한 레이의 길이
- flags : 구조체의 어떤 필드가 유효한지를 지정한다
- faceindex : 레이가 교차한 면의 인덱스
- u, v는 교차점의 삼각형 내 바리센트릭 좌표
*바리센트릭 좌표란? 삼각형 내 교차점의 위치를 삼각형의 세 꼭지점으로 표현한 좌표
Sphere, Capsule, Box, Convex
- 위 도형들에 대한 Raycast의 경우 최대 1개의 결과가 반환된다.
* 만약 레이의 원점이 물체 내부에 있다면?
- 충돌 거리는 0으로 설정된다.
- 충돌 법선은 레이의 반대 방향으로 설정되고, PxHitFlag::eNORMAL 플래그가 출력에 설정됨
- 충돌 위치는 레이의 원점으로 설정되며, PxHitFlag::ePOSITION 플래그가 출력에 설정됨
* 레이의 시작점 및 끝 점이 물체 표면과 매우 가까우면 레이와 물체 사이에 정확한 교차점을 찾기 어려울 수 있음
- 이 경우 레이의 시작점 또는 끝점이 물체의 내부 또는 외부에 있는 것으로 처리될 수 있으며, 이는 물체 유형에 따라 다름
Plane
- Raycast에서 평면은 경계를 포함한 무한한 단면으로 취급된다.
- 평면도 최대 1개의 결과만 반환되며, 레이의 시작점이 평면 뒤쪽에 위치하는 경우, 레이와 평면이 교차해도 충돌이 감지되지 않는다.
* 평면도 마찬가지로 레이의 시작점 및 끝점이 평면과 매우 가까운 경우, 레이는 양쪽 중 어느 한 쪽에 있는 것으로 처리될 수 있다.
Overlap Query
- Overlap Query란 두 개의 Geometry가 서로 겹치는지 확인하는 것
- 그 중 하나의 Geometry는 Box, Sphere, Capsule, Convex이며, 다른 하나는 모든 유형일 수 있음
- 다음 코드에서 Overlap 쿼리를 처리한다
bool isOverlapping = overlap(geom0, pose0, geom1, pose1);
- 오버랩 쿼리는 충돌 검사와는 달리, 겹치는지 여부만 판별하며, 겹칠 경우 bool 값을 반환한다
- PxOverlapBuffer 클래스를 사용해서 결과를 수집하며, 이 클래스는 결과 목록에 각 Overlap에 대한 정보를 저장하는 버퍼이다.
Penetration Depth
- 두 Geometry가 교차(intersect)하는 경우 PhysX는 물체를 분리하기 위해 필요한 최소 거리와 방향을 계산할 수 있다.
- 이런 양은 때로 최소 변위 거리 (MTD)로 참조되기도 한다.
- 적어도 한 객체는 Box, Sphere, Capsule, Convex여야 한다.
- 아래는 침투깊이 쿼리를 사용하는 코드이다.
bool isPenetrating = PxGeometryQuery::computePenetration(direction, depth,
geom0, pose0,
geom1, pose1);
- direction : 두 번째 Geometry에서 첫 번째 Geometry가 분리되기 위해 이동해야 하는 방향으로 설정됨
- distance : 첫 번째 오브젝트가 분리되기 위해 이동해야 하는 거리로 설정된다
- geom0 : 첫 번째 지오메트리
- pose0 : 첫 번째 지오메트리의 Transform
- geom1 : 두 번째 지오메트리
- pose1 : 두 번째 지오메트리의 Transform
- 이 함수는 두 Geometry가 교차하면, 이들이 서로 분리될 때 필요한 최소한의 방향과 거리를 계산해서 벡터로 반환한다.
- 이 벡터를 사용해서 첫 번째 오브젝트를 움직이면, 두 오브젝트는 서로 분리된다.
- 이 때 함수는 true를 반환하며, 이 때 반환된 depth는 첫 번째 오브젝트를 이동할 때 필요한 최소 거리
- 만약 두 오브젝트가 교차하지 않는다면 함수는 false를 반환하며, 반환된 방향 및 거리 필드의 값은 정의되지 않음
PxU32 nb;
bool status = PxComputeTriangleMeshPenetration(direction, depth,
geom, geomPose,
meshGeom, meshPose,
maxIter, &nb);
PxU32 nb;
bool status = PxComputeHeightFieldPenetration(direction, depth,
geom, geomPose,
heightFieldGeom, heightFieldPose,
maxIter, &nb);
- 여기서 maxIter는 알고리즘의 최대 반복 횟수이며, nb는 수행된 반복 횟수이다.
- 오버랩이 감지되지 않으면 함수는 false를 반환한다.
- 최대 maxIter회 시도하지만 디페네이션 벡터가 찾아지면 더 이상 반복하지 않는다. (보통 maxIter = 4가 좋은 결과가 나옴)
- 위 함수들은 디페네이션 벡터를 대략적으로 계산하며, Geometry와 Mesh/Height Field 사이의 오버랩 양이 적을 때 가장 잘 작동한다.
Sweep
- Sweep은 일종의 검색 작업으로, 하나의 물체를 다른 물체 위를 스캔하면서 충돌이 발생하는 위치를 찾아내는 작업
- Sweep Query는 한 개의 Geomtry가 다른 Geometry에 충돌하는 위치를 찾기 위해 공간을 추적하고,
충돌 지점과 관련된 정보를 보고한다.
- 마찬가지로 첫 번째 Geometry가 Sphere, Box, Capsule, Convex일 경우에만 지원한다.
- 아래는 사용하는 예제 코드이다.
PxSweepHit hitInfo;
PxHitFlags hitFlags = PxHitFlag::ePOSITION|PxHitFlag::eNORMAL;
PxReal inflation = 0.0f;
PxU32 hitCount = PxGeometryQuery::sweep(unitDir, maxDist,
geomToSweep, poseToSweep,
geomSweptAgainst, poseSweptAgainst,
hitInfo,
hitFlags,
inflation);
- unitDir : 스윕의 방향을 정의하는 단위 벡터
- maxDist : 스윕할 최대 거리 (이 거리는 0~inf 사이의 범위여야 한다)
- geomToSweep : 스윕할 Geometry (지원되는 Geometry는 Box, Sphere, Capsule, Convex)
- poseToSweep : 스윕할 Geometry의 초기 위치
- geomSweptAgainst : 스윕 대상이 되는 Geometry (유형 상관x)
- poseSweptAgainst : 스윕 대상 Geometry의 위치
- hitInfo : 반환 결과이며, 스윕은 최대 하나의 충돌 결과를 반환한다.
- hitFlags : 충돌 결과 처리 방법 및 충돌 발생시 반환할 데이터 결정
- inflation : 첫 번째 geometry를 모서리가 둥근 상태가 되도록 해주는 기능(Geometry 주변에 여유 공간을 확보해준다)
(주로 물체가 지형을 따라 이동할 대, 지형의 경사면의 돌출 부분과 충돌하지 않도록 하기 위해 사용한다)
- Raycast와 마찬가지로 hitFlags에서 플래그가 설정되면 출력 구조체의 필드가 채워진다.
- 아래는 PxSweepHit 구조체의 멤버이다.
PxRigidActor* actor;
PxShape* shape;
PxVec3 position;
PxVec3 normal;
PxF32 distance;
PxHitFlags flags;
PxU32 faceIndex;
- actor와 shape는 채워지지 않음 (Scene Query에서 사용됨)
- position(PxHitFlags::ePOSITION) : 교차점의 위치
두 개의 상자가 면과 면이 만나는 경우와 같이 여러 충돌점이 있는 경우는 임의로 하나의 점을 선택한다.
- normal(PxHitFlags::eNORMAL) : 충돌 지점의 노멀 벡터(법선 벡터)
어떤 물체가 다른 물체와 충돌할 때, 두 물체는 서로 닿아 있는데, 이 때 충돌 지점에서 법선은 두 물체가 닿아 있는 방향을 가리키는 선이 된다.
- distance : 교차가 발생한 ray의 거리
- flags : 구조체의 어떤 필드가 유효한지 지정
- faceIndex : 스윕에 의해 충돌한 face의 인덱스
'PhysX > [NVIDIA] PhysX_Tutorial' 카테고리의 다른 글
12. Scene Query - 1 (0) | 2023.03.21 |
---|---|
10. PhysX - Character Controllers - 2 (0) | 2023.03.05 |
9. PhysX - Character Controllers - 1 (1) | 2023.03.04 |
8. PhysX - RigidBody Dynamics - 2 (0) | 2023.03.04 |
7. PhysX - RigidBody Dynamics - 1 (0) | 2023.03.04 |
댓글