From 4c083d713d1691bf83b5d24e6449dd8e110a31f7 Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Sat, 13 Dec 2025 17:41:21 -0600 Subject: [PATCH] physics findings rigid: main finding is rigid needs to take delta into account for integration (aka interpolation) also used POINT_EPSILON for thresholds for consistency for rigidshape/item/player, main finding was length calcs for the search area were all over the place, so we now derive the extended length of the cached area based on the velocity and the object's radius itself rather than guessin per class atrest gravity calc suplimental syncing between rigidshape and vehicle **remindernote POINT_EPSILO is 0.0001 --- Engine/source/T3D/item.cpp | 4 ++-- Engine/source/T3D/player.cpp | 2 +- Engine/source/T3D/rigid.cpp | 13 +++++++------ Engine/source/T3D/rigid.h | 2 +- Engine/source/T3D/rigidShape.cpp | 6 +++--- Engine/source/T3D/vehicles/vehicle.cpp | 2 +- 6 files changed, 15 insertions(+), 14 deletions(-) diff --git a/Engine/source/T3D/item.cpp b/Engine/source/T3D/item.cpp index 3681774da..18f52ff5c 100644 --- a/Engine/source/T3D/item.cpp +++ b/Engine/source/T3D/item.cpp @@ -658,9 +658,9 @@ void Item::updateWorkingCollisionSet(const U32 mask, const F32 dt) { // It is assumed that we will never accelerate more than 10 m/s for gravity... // - Point3F scaledVelocity = mVelocity * dt; + Point3F scaledVelocity = mVelocity * dt * TickSec; F32 len = scaledVelocity.len(); - F32 newLen = len + (10 * dt); + F32 newLen = len + (mDataBlock->getShape()->mRadius * dt * TickSec); // Check to see if it is actually necessary to construct the new working list, // or if we can use the cached version from the last query. We use the x diff --git a/Engine/source/T3D/player.cpp b/Engine/source/T3D/player.cpp index 3c187ea0d..96dcf0d1e 100644 --- a/Engine/source/T3D/player.cpp +++ b/Engine/source/T3D/player.cpp @@ -6097,7 +6097,7 @@ void Player::updateWorkingCollisionSet() // box by the possible movement in that tick. Point3F scaledVelocity = mVelocity * TickSec; F32 len = scaledVelocity.len(); - F32 newLen = len + (10.0f * TickSec); + F32 newLen = len + (mDataBlock->getShape()->mRadius * TickSec); // Check to see if it is actually necessary to construct the new working list, // or if we can use the cached version from the last query. We use the x diff --git a/Engine/source/T3D/rigid.cpp b/Engine/source/T3D/rigid.cpp index adb453879..83b9eb8b4 100644 --- a/Engine/source/T3D/rigid.cpp +++ b/Engine/source/T3D/rigid.cpp @@ -47,8 +47,8 @@ Rigid::Rigid() friction = 0.5f; atRest = false; - sleepLinearThreshold = 0.0004f; - sleepAngThreshold = 0.0004f; + sleepLinearThreshold = POINT_EPSILON; + sleepAngThreshold = POINT_EPSILON; sleepTimeThreshold = 0.75f; sleepTimer = 0.0f; } @@ -71,7 +71,7 @@ void Rigid::integrate(F32 delta) linVelocity = linMomentum * oneOverMass; // 2. advance orientation if ang vel significant - F32 angle = angVelocity.len(); + F32 angle = angVelocity.len()*delta; if (mFabs(angle)> POINT_EPSILON) { QuatF dq; @@ -101,7 +101,7 @@ void Rigid::integrate(F32 delta) } // 5. refresh ang velocity - updateAngularVelocity(); + updateAngularVelocity(delta); // 6. CoM update @@ -138,7 +138,7 @@ void Rigid::updateCenterOfMass() void Rigid::applyImpulse(const Point3F &r, const Point3F &impulse) { - if (impulse.lenSquared() < mass) return; + if ((impulse.lenSquared() - mass) < POINT_EPSILON) return; wake(); // Linear momentum and velocity @@ -304,7 +304,8 @@ void Rigid::trySleep(F32 dt) // If there is active force/torque, don’t sleep if (!force.isZero() || !torque.isZero()) { - sleepTimer = 0.0f; return; + sleepTimer = 0.0f; + return; } const F32 linV2 = linVelocity.lenSquared(); diff --git a/Engine/source/T3D/rigid.h b/Engine/source/T3D/rigid.h index c9fa9197e..ad66c0e0c 100644 --- a/Engine/source/T3D/rigid.h +++ b/Engine/source/T3D/rigid.h @@ -105,7 +105,7 @@ public: // void setSleepThresholds(F32 linVel2, F32 angVel2, F32 timeToSleep); void wake(); - TORQUE_FORCEINLINE void updateAngularVelocity() { invWorldInertia.mulV(angMomentum, &angVelocity); } + TORQUE_FORCEINLINE void updateAngularVelocity(F32 delta) { Point3F deltaVel = angVelocity * delta; invWorldInertia.mulV(angMomentum, &deltaVel); } }; diff --git a/Engine/source/T3D/rigidShape.cpp b/Engine/source/T3D/rigidShape.cpp index b43d9adfb..129c0dcf9 100644 --- a/Engine/source/T3D/rigidShape.cpp +++ b/Engine/source/T3D/rigidShape.cpp @@ -1138,7 +1138,7 @@ void RigidShape::updatePos(F32 dt) // Update collision information based on our current pos. bool collided = false; - if (!mDisableMove) + if (!mRigid.atRest && !mDisableMove) { collided = updateCollision(dt); @@ -1151,7 +1151,7 @@ void RigidShape::updatePos(F32 dt) { F32 k = mRigid.getKineticEnergy(); F32 G = mNetGravity* dt * TickMs / mDataBlock->integration; - F32 Kg = mRigid.mass * G * G; + F32 Kg = mRigid.mass * G * G * TickSec; if (k < sRestTol * Kg && ++restCount > sRestCount) mRigid.setAtRest(); } @@ -1447,7 +1447,7 @@ void RigidShape::updateWorkingCollisionSet(const U32 mask) // working list is updated on a Tick basis, which means we only expand our box by // the possible movement in that tick, plus some extra for caching purposes Box3F convexBox = mConvex.getBoundingBox(getTransform(), getScale()); - F32 len = (mRigid.linVelocity.len() + 50) * TickSec; + F32 len = (mRigid.linVelocity.len() + mDataBlock->getShape()->mRadius) * TickSec; F32 l = (len * 1.1) + 0.1; // fudge factor convexBox.minExtents -= Point3F(l, l, l); convexBox.maxExtents += Point3F(l, l, l); diff --git a/Engine/source/T3D/vehicles/vehicle.cpp b/Engine/source/T3D/vehicles/vehicle.cpp index 18ea38e10..c1750b61d 100644 --- a/Engine/source/T3D/vehicles/vehicle.cpp +++ b/Engine/source/T3D/vehicles/vehicle.cpp @@ -827,7 +827,7 @@ void Vehicle::updatePos(F32 dt) { F32 k = mRigid.getKineticEnergy(); F32 G = mNetGravity* dt * TickMs / mDataBlock->integration; - F32 Kg = 0.5 * mRigid.mass * G * G; + F32 Kg = mRigid.mass * G * G * TickSec; if (k < sRestTol * Kg && ++restCount > sRestCount) mRigid.setAtRest(); }