feat(physics): sync runtime physx body state

This commit is contained in:
2026-04-15 12:47:40 +08:00
parent 7cbc992bd8
commit c5dcfaedd5
3 changed files with 176 additions and 10 deletions

View File

@@ -295,20 +295,61 @@ void ApplyDynamicBodyProperties(
}
}
void SyncActorBindingPose(ActorBinding& binding) {
void SyncShapeBindingState(
const Components::GameObject& actorOwner,
ShapeBinding& shapeBinding) {
if (!shapeBinding.shape || !shapeBinding.collider) {
return;
}
shapeBinding.shape->setLocalPose(
BuildShapeLocalPose(actorOwner, *shapeBinding.collider));
shapeBinding.shape->setGeometry(BuildColliderGeometry(*shapeBinding.collider).any());
shapeBinding.shape->setFlag(physx::PxShapeFlag::eSCENE_QUERY_SHAPE, true);
const bool isTrigger = shapeBinding.collider->IsTrigger();
shapeBinding.shape->setFlag(physx::PxShapeFlag::eSIMULATION_SHAPE, !isTrigger);
shapeBinding.shape->setFlag(physx::PxShapeFlag::eTRIGGER_SHAPE, isTrigger);
shapeBinding.shape->userData = shapeBinding.collider;
shapeBinding.sourceGameObject = shapeBinding.collider->GetGameObject();
if (shapeBinding.material) {
shapeBinding.material->setStaticFriction(
std::max(0.0f, shapeBinding.collider->GetStaticFriction()));
shapeBinding.material->setDynamicFriction(
std::max(0.0f, shapeBinding.collider->GetDynamicFriction()));
shapeBinding.material->setRestitution(
std::clamp(shapeBinding.collider->GetRestitution(), 0.0f, 1.0f));
}
}
bool BindingNeedsActorRebuild(const ActorBinding& binding) {
if (!binding.actor) {
return false;
}
const bool shouldUseDynamicActor =
binding.rigidbody != nullptr &&
binding.rigidbody->GetBodyType() != PhysicsBodyType::Static;
const bool usesDynamicActor = binding.dynamicActor != nullptr;
return shouldUseDynamicActor != usesDynamicActor;
}
void SyncActorBindingState(ActorBinding& binding) {
if (!binding.actor || !binding.owner) {
return;
}
for (ShapeBinding& shapeBinding : binding.shapes) {
if (shapeBinding.shape && shapeBinding.collider) {
shapeBinding.shape->setLocalPose(
BuildShapeLocalPose(*binding.owner, *shapeBinding.collider));
}
SyncShapeBindingState(*binding.owner, shapeBinding);
}
const physx::PxTransform targetPose = ToPxTransform(*binding.owner->GetTransform());
if (binding.dynamicActor) {
if (binding.rigidbody) {
ApplyDynamicBodyProperties(*binding.dynamicActor, *binding.rigidbody);
}
if (binding.rigidbody && binding.rigidbody->GetBodyType() == PhysicsBodyType::Kinematic) {
binding.dynamicActor->setKinematicTarget(targetPose);
}
@@ -450,7 +491,7 @@ void PhysXWorldBackend::Step(float fixedDeltaTime) {
return;
}
SyncActorPosesToScene();
SyncActorStateToScene();
m_native->scene->simulate(fixedDeltaTime);
m_native->scene->fetchResults(true);
@@ -515,7 +556,7 @@ bool PhysXWorldBackend::Raycast(
return false;
}
SyncActorPosesToScene();
SyncActorStateToScene();
physx::PxRaycastBuffer hitBuffer;
const physx::PxHitFlags hitFlags = physx::PxHitFlag::ePOSITION | physx::PxHitFlag::eNORMAL;
@@ -570,14 +611,21 @@ size_t PhysXWorldBackend::GetShapeCount() const {
#endif
}
void PhysXWorldBackend::SyncActorPosesToScene() {
void PhysXWorldBackend::SyncActorStateToScene() {
#if XCENGINE_ENABLE_PHYSX
if (!m_native) {
return;
}
for (const auto& [_, binding] : m_native->actorsByOwner) {
if (BindingNeedsActorRebuild(binding)) {
RebuildSceneState();
break;
}
}
for (auto& [_, binding] : m_native->actorsByOwner) {
SyncActorBindingPose(binding);
SyncActorBindingState(binding);
}
#endif
}

View File

@@ -43,7 +43,7 @@ public:
private:
void RebuildSceneState(Components::Component* ignoredComponent = nullptr);
void SyncActorPosesToScene();
void SyncActorStateToScene();
PhysicsWorldCreateInfo m_createInfo = {};
bool m_initialized = false;