본문 바로가기
PhysX/[NVIDIA] PhysX_Tutorial

12. Scene Query - 1

by 헛둘이 2023. 3. 21.

Scene Query

- 씬의 Actor와 연결된 Geometry에 대한 충돌 쿼리를 수행하는 기능을 제공한다.

- raycast, sweeping, overlap 총 3가지 유형의 쿼리가 있고, 각각 1개 또는 여러 개의 결과를 반환할 수 있다.

- 보다 정밀한 검사는 Geometry Query에서 수행된다.

- PxScene은 두 개의 다른 검사 구조를 사용하는데 하나는 정적 Actor, 다른 하나는 동적 Actor이다.

 


Raycast

- PxScene::raycast() 쿼리는 사용자가 정의한 레이를 전체 씬과 투영한다.

- 이 방법을 통해 주어진 레이를 따라 가장 가까운 교차점을 찾을 수 있다.

- 아래는 예제 코드이다.

PxScene* scene;
PxVec3 origin = ...;                 // [in] Ray origin
PxVec3 unitDir = ...;                // [in] Normalized ray direction
PxReal maxDistance = ...;            // [in] Raycast max distance
PxRaycastBuffer hit;                 // [out] Raycast results

// Raycast against all static & dynamic objects (no filtering)
// The main result from this call is the closest hit, stored in the 'hit.block' structure
bool status = scene->raycast(origin, unitDir, maxDistance, hit);
if (status)
    applyDamage(hit.block.position, hit.block.normal);

- 이 코드에서는 PxRaycastBuffer를 사용해서 레이캐스트 쿼리 결과를 반환받는다.

- raycast() 호출은 충돌이 있었을 경우 true를 반환한다.

- hit.hadBlock도 충돌이 있었을 경우 true로 설정된다.

- raycast의 결과는 position, normal, maxDistance, shape, actor 등을 포함한다.

- 이 결과를 사용하기 위해선 이전의 geometry query처럼 flag를 적절하게 설정해주어야 한다.

 

 

 

Sweeps

- PxScene::sweep()은 Geometry의 raycast와 유사하다.

- PxGeometry의 Shape는 지정된 초기 위치에서 최대 길이와 방향으로 스위핑되어 Scene 객체와 충돌하는 지점을 찾는다.

- 허용되는 Geometry는 Box, Sphere, Capsule, Convex이다.

- 그리고 PxSweepBuffer를 통해 sweep 쿼리에서 결과를 반환받는다.

- 아래는 예제 코드이다.

PxSweepBuffer hit;              // [out] Sweep results
PxGeometry sweepShape = ...;    // [in] swept shape
PxTransform initialPose = ...;  // [in] initial shape pose (at distance=0)
PxVec3 sweepDirection = ...;    // [in] normalized sweep direction
bool status = scene->sweep(sweepShape, initialPose, sweepDirection, sweepDistance, hit);

 

Overlaps

- PxScene::overlap() 쿼리는 씬에서 지정된 Shape에 둘러싸인 영역(Bounds)을 검색해서 겹치는 객체가 있는지 찾는다

- 영역은 Box, Sphere, Capsule, Convex이다.

- PxOverlapBuffer를 통해 overlap() 쿼리의 결과를 반환받는다.

PxOverlapBuffer hit;            // [out] Overlap results
PxGeometry overlapShape = ...;  // [in] shape to test for overlaps
PxTransform shapePose = ...;    // [in] initial shape pose (at distance=0)

PxOverlapBuffer hit;
bool status = scene->overlap(overlapShape, shapePose, hit);

 


Touching and blocking hits

 

- 여러 결과를 반환하는 쿼리에서 쿼리가 검출한 충돌 중에 어떤 것이 레이캐스트나 스윕 경로르 막는 충돌인지,

아니면 단순히 충돌한 것인지 구분해서 이것을 Touching Hit / Blocking Hit으로 구분한다.

- 이 구분은 사용자가 필터링 로직을 구현해서 결정할 수 있다.

 

Blocking Hit

- Raycast나 Sweep 경로에서 더 이상 진행할 수 없는 충돌을 의미함

 

Touching Hit

- Raycast나 Sweep이 계속 진행할  수 있도록 충돌이 감지된 것을 의미함

 

- 따라서 여러 개의 결과가 있을 경우, 가장 가까운 Blocking Hit이 있다면, 해당 Hit과 가장 가까운 Touching Hit을 함께 반환한다.

- Blocking Hit이 없다면 모든 Touching Hit을 반환한다.

 

 

 

Query Mode

- 쿼리 모드에는 '가장 가까운 히트(Closest Hit)'와 어떤 히트든 상관없이 '모든 히트(Any Hit)'가 존재한다.

 

Closest Hit

- '가장 가까운 히트(Closest Hit)' 모드는 쿼리가 가장 가까운 거리의 Blocking Hit를 찾아서 PxHitBuffer::block 멤버에 보고하는 기본 모드이다.

- 이 모드는 raycasts, sweeps, overlaps 모두에서 사용된다.

 

Any Hit

- '모든 히트(Any Hit)' 모드는 가장 가까운 Hit를 찾을 필요가 없다는 것을 쿼리 시스템에 알리는 Hint로 적용된다.

- 주로 boolean blocking / non-blocking queries에서 자주 사용된다.

- 시나리오에 따라 3배 이상의 성능 향상 효과가 있음

- 이 모드를 활성화하려면 PxQueryFlag::eANY_HIT 필터 데이터 플래그를 사용해서 PxQueryFilterData에 설정하면 된다.

PxQueryFilterData fd;
fd.flags |= PxQueryFlag::eANY_HIT; // note the OR with the default value
bool status = scene->raycast(origin, unitDir, maxDistance, hit,
                             PxHitFlags(PxHitFlag::eDEFAULT), fdAny);

 

*boolean blocking / non-blocking queries란?

- 쿼리가 물체 간의 차단 여부를 확인하는 것을 목적으로 하는 쿼리 유형

- boolean blocking query는 적어도 하나의 Blocking Hit을 발견할 때 true를 반환하고,

- non-blocking query는 모든 객체가 차단되지 않았을 때 true를 반환한다.

 


Multiple Hits

- raycast, overlap, sweep 세 가지 쿼리 타입은 모두 씬의 다른 객체들과 다중 충돌이 발생할 수 있다.

- raycast에서 이 모드를 활성화하려면, PxRaycastBuffer 생성자를 호출할 때 사용자가 제공한 버퍼를 매개변수로 전달하여 호출하면 된다.

- 이렇게 하면 raycast 쿼리의 멀티히트 모드가 활성화되고, PxRaycastBuffer::touches 배열에 모든 히트가 'touching' 타입으로 기록된다.

- 아래는 예제 코드이다.

PxScene* scene;
PxVec3 origin = ...;                 // [in] Ray origin
PxVec3 unitDir = ...;                // [in] Normalized ray direction
PxReal maxDistance = ...;            // [in] Raycast max distance

const PxU32 bufferSize = 256;        // [in] size of 'hitBuffer'
PxRaycastHit hitBuffer[bufferSize];  // [out] User provided buffer for results
PxRaycastBuffer buf(hitBuffer, bufferSize); // [out] Blocking and touching hits stored here

// Raycast against all static & dynamic objects (no filtering)
// The main result from this call are all hits along the ray, stored in 'hitBuffer'
scene->raycast(origin, unitDir, maxDistance, buf);
for (PxU32 i = 0; i < buf.nbTouches; i++)
    animateLeaves(buf.touches[i]);

- 같은 매커니즘으로 PxOverlapBuffer, PxOverlapHit[]와 PxSweepBuffer, PxSweepHit[]를 사용할 수 있다.

 

 

Multiple Hits With Blocking Hits

- 우리는 지금까지 Touching Hits만을 생각하고 있었는데, 만약 Blocking Hit이 Touching Hits와 함께 발생했다면?

- Blocking Hit은 PxHitBuffer::block 멤버에 보고되고, touch 버퍼에는 더 가까운 Touching Hits만 포함된다.

- 이런 조합은 총알이 창문을 통과하다가 벽을 만나 벽에 부딪히는 시나리오 등에서 유용하다.

// same initialization code as in the snippet for multiple hits
bool hadBlockingHit = scene->raycast(origin, unitDir, maxDistance, buf);
if (hadBlockingHit)
    drawWallDecal(buf.block);
for (PxU32 i = 0; i < buf.nbTouches; i++)
{
    assert(buf.touches[i].distance <= buf.block.distance);
    animateLeaves(buf.touches[i]);
}

- PxRaycastBuffer 생성자에 Touch Buffer가 전달되면, 기본적으로 모든 Hit은 Touching Hit으로 가정된다.

- 그리고 필터 콜백에서 Hit이 Blocking이라는 것을 나타내기 위해 PxQueryHitType::eBLOCK을 반환해야 한다.

- overlap() 쿼리의 경우 PxQueryFlag::eNO_BLOCK 플래그가 설정되었더라도, Blocking Hit이 검출되었더라도 모든 Touching Hits가 기록된다.

 

 


Filtering

- 필터링은 Shape가 씬 쿼리 결과에서 제외되는 방식과, 결과가 보고되는 방식을 제어한다.

- 모든 3개의 쿼리 유형(raycast, overlap, sweep)은 다음 필터링 매개 변수를 지원한다.

- PxQueryFlags 및 PxFilterData를 모두 포함하는 PxQueryFilterData 구조

- 옵션으로 PxQueryFilterCallback

 

PxQueryFlag::eSTATIC 및 PxQueryFlag::eDYNAMIC

- 이 플래그를 사용하여 정적 또는 동적 Shape만을 포함하도록 쿼리 결과를 필터링할 수 있다.

 -이것은 모든 정적/동적 Shape를 필터링하는 가장 효율적인 방법이다.

- 예를 들어 폭발 효과가 일어나는 지역에 모든 동적 모양에 힘을 적용하려면,

- 구체적인 Overlap 쿼리를 사용하고, PxQueryFlag::eDYNAMIC 플래그를 사용하여 모든 정적 모양을 제거할 수 있다.

- 기본적으로는 정적 / 동적 Shape 모두가 쿼리 결과에 포함된다.

- 아래 내용은 예제 코드임

PxScene* scene;
PxVec3 origin = ...;                 // [in] Ray origin
PxVec3 unitDir = ...;                // [in] Normalized ray direction
PxReal maxDistance = ...;            // [in] Raycast max distance
PxRaycastBuffer hit;                 // [out] Raycast results

// [in] Define filter for static objects only
PxQueryFilterData filterData(PxQueryFlag::eSTATIC);

// Raycast against static objects only
// The main result from this call is the boolean 'status'
bool status = scene->raycast(origin, unitDir, maxDistance, hit, PxHitFlag::eDEFAULT, filterData);

 

PxQueryFlag::ePREFILTER 및 PxQueryFlag::ePOSTFILTER

- 씬 쿼리는 총 세 단계로 수행된다

1. Bload phase : 전체 씬 공간 분할 구조를 탐색해서 mid phase 및 narrow phase의 후보를 찾는다.

2. Mid phase : 삼각형 메시와 height field 내부의 구조를 탐색해서 broad phase에서 보고된 메시의 일부를 찾는다.

3. Narrow phase : Raycast Query의 경우 Ray Test, Sweep Query 및 Overap Query의 정확한 Shape Test 및 Overlap Test를 수행한다.

 

- 쿼리에서 사용자 지정  필터링을 구현하려면 PxQueryFlag::ePREFILTER 및 PxQueryFlag::ePOSTFILTER 플래그를 설정하고, 필요한 필터링 로직으로 PxQueryFilterCallback을 상속받으면 된다.

 

- ePREFILTER는 Mid phase와 Narrow phase 이전에 발생하며, 정확한 충돌 테스트를 들어가기 전에 Shape를 효율적으로 제거할 수 있다.

- ePOSTFILTER는 Narrow phase 이후에 발생하며, PxRaycastHit.position 등을 활용하여 폐기해야 하는지 여부를 결정할 수 있다.

- 이런 결과는 필터링 콜백에서 접근할 수 있고, 입력 인수로 hit을 받는다.

- 예를 들어 레이캐스트 (PxRaycastHit) 쿼리의 데이터에 액세스하려면 static_cast<PxRaycastHit&>(hit)을 사용한다

- 오버랩(PxOverlapHit) 및 스윕(PxSweepHit)에 대해서도 동일하게 적용한다.

 

필터링 콜백은 PxQueryHitType 결과를 반환한다.

- eNONE : Hit을 폐기해야 함을 나타낸다.

- eBLOCK : Hit이 차단되었음을 나타낸다.

- eTOUCH : Hit이 접촉했음을 나타낸다.

 

- raycast(), sweep() 또는 overlap 쿼리에서 PxHitCallback::nbTouches 및 PxHitCallback::touches 매개변수를 사용해서 호출한 경우에는 가장 가까운 eBLOCK 타입 Hit보다 같거나 더 가까운 (touchDistance <= blockDistance) eTOUCH 타입 Hit이 보고된다.

- 예를 들어 Raycast Query에서 모든 Hit을 기록하려면 항상 eTOUCH를 반환해야 한다.

 

*필터 콜백에서 eTOUCH를 반환하려면 hit 버퍼 쿼리 매개 변수가 0이 아닌 ::touches 배열을 가지고 있어야 한다.

- 그렇지 않으면 PhysX는 확인된 빌드에서 오류를 생성하고 모든 Hit을 폐기한다.

 

*overlap()에서 사용자 정의 필터에서 eBLOCK을 반환해서는 안된다

- 그렇게 하면 정의되지 않은 동작이 발생하며 경고가 발생한다.

- PxQueryFlag::eNO_BLOCK 플래그가 설정된 경우 eBLOCK은 자동으로 eTOUCH로 변환되고 경고가 억제된다.

 

PxQueryFlag::eANY_HIT

- 이 플래그를 사용하면 쿼리가 가장 먼저 만난 Hit을 Blocking Hit으로 강제할 수 있다.

- 시나리오에 따라 성능이 3배 이상 빨라질 수 있음

 

PxQueryFlag::eNO_BLOCK

- 이 플래그는 필터에서 반환된 eBLOCK 값을 eTOUCH로 덮어쓰거나 Blocking Hit이 일어나지 않을 거라고 예측되는 경우 사용한다.

- 이 경우 필터 콜백 반환 값에 관계없이 모든 Hit이 Touching Hit으로 보고된다.

* 이 플래그를 사용할 때 쿼리에 제공된 Hit Callback/Buffer 객체는 PxHitBuffer::touches 버퍼가 비어있지 않아야 한다.

* 이 플래그는 PREFILTER 후 필터 함수에서 반환된 값들을 덮어쓰므로, 이전에 Blocking으로 반환된 적중도 Touch로 반환된다.

 

 

 

 

'PhysX > [NVIDIA] PhysX_Tutorial' 카테고리의 다른 글

11. Geometry Query  (0) 2023.03.20
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

댓글