Sleeping
- 물체가 일정 기간동안 움직이지 않으면, 미래에도 계속 그 상태를 유지할 것이라고 가정하고, 시뮬레이션에서 제외시켜서 메모리를 아낄 수 있다.
- 이 상태를 잠자는 상태(Sleeping)이라고 하며, 아래 코드에서 PxRigidDynamic 객체가 잠자는 상태인지 확인할 수 있다.
bool PxRigidDynamic::isSleeping() const;
- 간혹 Actor가 잠들거나 깨어날 때 보내는 이벤트를 수신하는 게 편리할 수 있음
- 이벤트를 받으려면 Actor에 아래 플래그가 설정되어 있어야 한다.
void PxSimulationEventCallback::onWake(PxActor** actors, PxU32 count) = 0;
void PxSimulationEventCallback::onSleep(PxActor** actors, PxU32 count) = 0;
- Actor는 일정 시간동엔 운동 에너지가 주어진 임계값보다 낮아지면 자는 상태가 된다.
- 기본적으로 동적인 RigidActor마다 활성 카운터가 있으며, Actor의 운동 에너지가 지정된 임계값 이하인 경우,
시뮬레이션 time step으로 감소한다.
- 활성 카운터가 0이 되면 Actor는 잘 준비를 한다.
- 하지만 활성 카운터가 0이라고 해서 Actor가 반드시 자는 것은 아니며, 다른 요소에 의해 더 오래 깨어 있을 수 있음
- Actor가 깨어 있는 최소 유지 시간은 아래 코드에서 세팅이 가능하다.
void PxRigidDynamic::setSleepThreshold(PxReal threshold);
PxReal PxRigidDynamic::getSleepThreshold() const;
void PxRigidDynamic::setWakeCounter(PxReal wakeCounterValue);
PxReal PxRigidDynamic::getWakeCounter() const;
* Kinematic 물체는 '수면 상태' 규칙이 약간 다르다
- Kinematic 물체는 목표 위치가 지정되지 않은 경우에만 수면 상태가 된다.
- 따라서 Kinematic 물체에 대해선 setWakeCounter를 사용할 수 없다.
- 대신 Kinematic 물체의 Wake Counter는 목표 위치가 지정되었는지 여부에 따라 달라진다.
만약, 동적 Actor가 자고 있다면, 다음 상태가 보장된다.
- Wake counter가 0이다.
- 선속도, 각속도가 0이다.
- 미처리된 힘 업데이트가 없다.
RigidBody가 Scene에 삽입될 때, 위의 모든 조건이 성립하면 잠자고 있다고 간주된다.
일반적으로, 동적 Actor는 다음 중 하나 이상을 만족하는 경우, 깨어있음이 보장된다.
- Wake counter가 양수다.
- 선속도 및 각속도가 0이 아니다.
- 0이 아닌 힘 또는 토크가 적용되어있다.
따라서 결과적으로 다음 호출은 자동으로 동적 Actor를 깨운다.
- PxRigidDynamic::setWakeCounter() // Wake counter 값이 0보다 큰 경우
- PxRigidDynamic::setLinearVelocity(), PxRigidDynamic::setAngularVelocity() // 속도가 0이 아닌 경우
- PxRigidBody::addForce(), PxRigidBody::addTorque() // 토크가 0이 아닌 경우
또한, 다음 호출 및 이벤트로도 깨어난다.
- PxRigidDynamic::setKinematicTarget() // kinematic actor인 경우 깨어남(wake counter를 양수로 설정하기 때문)
- PxRigidActor::setGlobalPose() // autowake 매개변수가 true(기본값)인 경우
- PxActorFlag::eDISABLE_SIMULATION을 설정해서 PxRigidActor의 시뮬레이션이 비활성화된 경우
- PxScene::resetFiltering()
- PxShape::setSimulationFilterData() // 필터링으로 Shape pair 유형이 suppressed, trigger 및 contact 사이를 전환하는 경우
* 충돌 검사에서 suppressed는 충돌이 감지되지 않도록 설정된 상태
* trigger는 충돌 검사는 수행하지만 물리적 상호작용 발생x
* contant는 충돌 검사를 수행하며 물리적 상호작용 발생o
- 깨어 있는 Actor와의 접촉
- 장면에서 접촉하는 Actor가 제거되는 경우
- 정적 Actor와의 접촉이 끊어진 경우
- 동적 Actor와의 접촉이 끊어지고, 이후 시뮬레이션에서 이 Actor가 깨어있음이 확인된 경우
*PxScene::removeActor()와 PxRigidActor::detachShape()에서 객체를 제거할 때,
이전 시뮬레이션 단계에서 제거된 객체와 접촉하고 있던 객체를 깨울 것인지 여부를 지정할 수 있다
* Actor가 자고 있는 경우 다음 메서드를 통해 명시적으로 깨우거나 재울 수 있다.
void PxRigidDynamic::wakeUp();
void PxRigidDynamic::putToSleep();
* kinematic actor에는 PxRigidDynamic::putToSleep() 메서드를 사용할 수 없다
- kinematic actor의 sleep 상태는 target pos가 설정되어 있는지 여부에 따라 결정된다.
Kinematic Actors
- 때로는 힘이나 제약 조건을 사용하여 Actor를 제어하는 것이 유연하지 않을 수 있다.
- 예를 들면 이동하는 플랫폼이나, 캐릭터 컨트롤러는 종종 물리 법칙에 관계없이 액터의 위치를 조작하거나, 정확하게 특정 경로를 따라가야 한다.
- Kinematic Actor는 이런 제어 방식을 제공한다.
- Kinematic Actor는 PxRigidDynamic::setKinematicTarget() 함수를 통해 제어된다.
- 각 시뮬레이션 단계마다, PhysX는 Actor를 대상 위치로 이동시키며, 외부 힘, 중력, 충돌 등과 상관없이 작동한다.
- 따라서, 원하는 경로를 따라 이동하려면 매 time step 마다 setKinematicTarget() 함수를 호출해야 한다.
- kinematic actor의 움직임은 충돌한 동적 Actor에 영향을 미치며, 이 Actor는 무한한 질량을 가진 것처럼 다른 Actor를 밀어내게 된다.
Kinematic Actor를 만들려면?
- 먼저 일반적인 동적 Actor를 만들고, 그 Actor에 kinematic flag를 설정하면 된다.
PxRigidBody::setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC, true);
- kinematic actor를 되돌리려면, 같은 함수를 사용하되, 두 번째 인자를 false로 두면 된다.
- kinematic actor는 모든 동적 Actor와 마찬가지로 질량을 제공해야 하지만,
- 이 Actor가 kinematic mode일 경우 실제로 사용되지 않는다.
*주의사항
- PxRigidDynamic::setKinematicTarget()과 PxRigidActor::setGlobalPose()의 차이점을 이해해야 한다.
- setGlobalPose()는 원하는 위치로 배치시키기는 하지만, 해당 Actor를 다른 Actor와 적절하게 상호작용시키지 않는다.
- 특히 setGlobalPose()를 사용하면 kinematic actor가 다른 동적 Actor를 밀어내지 않고 그냥 지나가게 된다.
- 따라서 setGlobalPose() 함수는 그냥 kinematic actor를 새 위치로 순간이동 시킬때만 사용해야 한다.
*kinematic actor는 동적 actor를 밀어낼 수 있지만 아무 것도 kinematic actor를 밀어내지 않는다.
Kinematic 표면 속도
- Kinematic 표면 속도는 kinematic actor의 global pose를 설정하는 것외에도,
- PxRigidDynamic::setKinematicSurfaceVelocity() 메소드를 사용하여, kinematic 표면 속도를 설정할 수 있다.
- 이 메서드는 해당 rigidbody가 kinematic으로 설정된 경우에만 호출이 가능하다
- 이 속도를 설정하면 해당 객체와 충돌하는 다른 객체들이 이동하는 것처럼 보이지만, 실제로 kinematic actor의 위치나 방향이 변경되지 않는다.
- 예를 들면 컨베이어 벨트나 회전하는 표면을 예시로 들 수 있음
Active Actors
-Scene 내에서 발생하는 actor transform 변화를 외부의 Render Mesh와 연동시키는 효율적인 방법을 제공한다.
- fetchResults() 메소드가 호출되면, 해당 scene 내에서 이동한 actor의 배열이 생성된다.
- 이 방법은 actor 각각을 조사하는 것보다 더 효율적이다
// update scene
scene.simulate(dt);
scene.fetchResults();
// retrieve array of actors that moved
PxU32 nbActiveActors;
PxActor** activeActors = scene.getActiveActors(nbActiveActors);
// update each render object with the new transform
for (PxU32 i=0; i < nbActiveActors; ++i)
{
MyRenderObject* renderObject = static_cast<MyRenderObject*>(activeActors[i]->userData);
renderObject->setTransform(activeActors[i]->getGlobalPose());
}
*active actors 배열이 생성되려면 scene의 플래그가 PxSceneFlag::eENABLE_ACTIVE_ACTORS 플래그가 설정되어 있어야 한다.
*kinematic actor의 target은 사용자에 의해 설정되기 때문에, kinematics는 PxSceneFlag::eEXCLUDE_KINEMATICS_FROM_ACTIVE_ACTORS 플래그를 설정해서 리스트에서 제거할 수 있다.
축 잠금 (Axis locking)
- PhysX에서는 PxRigidDynamicLockFlag를 이용해서 특정 월드 공간 축을 따라 이동하거나 회전하는 것을 제한할 수 있다.
- 아래 코드는 PxRigidDynamic을 2차원 시뮬레이션으로 제한하는 방법을 보여준다.
- 이 경우 PxRigidDynamic이 Z축을 기준으로 회전하고 X, Y축으로만 이동하도록 한다.
PxRigidDynamic* dyn = physics.createRigidDynamic(PxTransform(PxVec3(0.f, 2.5f, 0.f)));
...
//Lock the motion
dyn->setRigidDynamicLockFlags(
PxRigidDynamicLockFlag::eLOCK_LINEAR_Z |
PxRigidDynamicLockFlag::eLOCK_ANGULAR_X |
PxRigidDynamicLockFlag::eLOCK_ANGULAR_Y);
- 위와 같은 방법을 통해 3차원 공간 어떤 조합이든 이동 또는 회전을 제한할 수 있다.
'PhysX > [NVIDIA] PhysX_Tutorial' 카테고리의 다른 글
10. PhysX - Character Controllers - 2 (0) | 2023.03.05 |
---|---|
9. PhysX - Character Controllers - 1 (1) | 2023.03.04 |
7. PhysX - RigidBody Dynamics - 1 (0) | 2023.03.04 |
6. PhysX - RigidBody 충돌 - 2 (0) | 2023.03.03 |
5. PhysX - RigidBody 충돌 - 1 (0) | 2023.03.03 |
댓글