From ea6beee59391b2f630a4f7491bba4ac03e458182 Mon Sep 17 00:00:00 2001 From: atdunbg Date: Sat, 3 Oct 2026 17:51:11 +0800 Subject: [PATCH] fix(physics): editor drag teleports dynamic bodies SyncScene only reconciled static/kinematic transforms into Jolt bodies; dragging a dynamic entity (esp. while paused, where Writeback never runs) moved the visual but left the body -- and the collider debug wireframe -- at the old pose. Dynamic bodies now get the same drag reconciliation (teleport + zero velocity + activate), and Writeback syncs lastPos/lastRot to the body pose so physics motion is never misread as editor dragging (which would teleport the body back). --- Engine/include/Engine/Physics/PhysicsWorld.h | 2 +- Engine/src/Physics/PhysicsWorld.cpp | 26 +++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/Engine/include/Engine/Physics/PhysicsWorld.h b/Engine/include/Engine/Physics/PhysicsWorld.h index 9a7c76f..6011b79 100644 --- a/Engine/include/Engine/Physics/PhysicsWorld.h +++ b/Engine/include/Engine/Physics/PhysicsWorld.h @@ -119,7 +119,7 @@ namespace Engine { }; void SyncScene(); // 对账:孤儿清理 / 创建 / 参数同步 - void Writeback() const; // 动态体 → TransformComponent(标脏) + void Writeback(); // 动态体 → TransformComponent(标脏)+ lastPos/lastRot 对账基线 void UpdateAccels(f32 dt); // 速度差分 → BodyRecord.lastAccel(step 率) void CollectDebugData(); // 按 m_DebugBits 收集调试图元(渲染帧率) void CreateBody(u32 entityBits, ECS::RigidBodyComponent& rb, diff --git a/Engine/src/Physics/PhysicsWorld.cpp b/Engine/src/Physics/PhysicsWorld.cpp index d488f73..2365e64 100644 --- a/Engine/src/Physics/PhysicsWorld.cpp +++ b/Engine/src/Physics/PhysicsWorld.cpp @@ -393,6 +393,22 @@ namespace Engine { bi.SetRestitution(id, rb.restitution); if (rb.type == ECS::RigidBodyComponent::BodyType::Dynamic) { bi.SetGravityFactor(id, rb.gravityScale); + // 编辑器拖动 Dynamic 体(暂停期/物理未步进的帧)→ 传送 + + // 清速度(UE 编辑器语义:编辑器操作权威于物理 body,拖动 = + // 重新放置)。物理模拟中 Writeback 每步同步 lastPos/lastRot + // → 本比对只在真正拖动帧为真,不会打断自由模拟 + if (rec.lastPos != tr.GetPosition() || + rec.lastRot != tr.GetRotationQuat()) { + bi.SetPositionAndRotation( + id, + JPH::RVec3(tr.GetPosition().x, tr.GetPosition().y, tr.GetPosition().z), + ToJolt(tr.GetRotationQuat()), + JPH::EActivation::Activate); + bi.SetLinearVelocity(id, JPH::Vec3(0.0f, 0.0f, 0.0f)); + bi.SetAngularVelocity(id, JPH::Vec3(0.0f, 0.0f, 0.0f)); + rec.lastPos = tr.GetPosition(); + rec.lastRot = tr.GetRotationQuat(); + } } else if (rec.lastPos != tr.GetPosition() || rec.lastRot != tr.GetRotationQuat()) { // 编辑器拖动静态/运动学体 → 传送 body @@ -994,7 +1010,7 @@ namespace Engine { // ---- 写回:动态体姿态 → Transform(标脏,帧循环统一 Compose)---- - void PhysicsWorld::Writeback() const { + void PhysicsWorld::Writeback() { auto ® = m_Scene.GetRegistry(); const auto &bi = m_System->GetBodyInterface(); @@ -1012,6 +1028,14 @@ namespace Engine { const JPH::Vec3 vel = bi.GetLinearVelocity(id); rb.velocity = glm::vec3(vel.GetX(), vel.GetY(), vel.GetZ()); + + // lastPos/lastRot 同步到 body 姿态:否则下帧 SyncScene 把物理 + // 位移误判为编辑器拖动 → teleport 回旧位置死循环 + const u32 bits = static_cast(entt::to_integral(e)); + if (auto it = m_Bodies.find(bits); it != m_Bodies.end()) { + it->second.lastPos = tr.GetPosition(); + it->second.lastRot = tr.GetRotationQuat(); + } } } } // namespace Engine