Merge pull request #1537 from Azaezel/alpha41/wonkyWheels

skip transmitting server authorative wheel spin
This commit is contained in:
Brian Roberts 2025-08-24 14:29:44 -05:00 committed by GitHub
commit 5a6ff8d118
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 113 additions and 31 deletions

View file

@ -46,6 +46,11 @@ Rigid::Rigid()
restitution = 0.3f; restitution = 0.3f;
friction = 0.5f; friction = 0.5f;
atRest = false; atRest = false;
sleepLinearThreshold = 0.0004f;
sleepAngThreshold = 0.0004f;
sleepTimeThreshold = 0.75f;
sleepTimer = 0.0f;
} }
void Rigid::clearForces() void Rigid::clearForces()
@ -57,9 +62,18 @@ void Rigid::clearForces()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void Rigid::integrate(F32 delta) void Rigid::integrate(F32 delta)
{ {
// Update Angular position if (atRest && force.isZero() && torque.isZero())
return;
// 1. advance momentum
angMomentum += torque * delta;
linMomentum += force * delta;
linVelocity = linMomentum * oneOverMass;
// 2. advance orientation if ang vel significant
F32 angle = angVelocity.len(); F32 angle = angVelocity.len();
if (angle != 0.0f) { if (mFabs(angle)> POINT_EPSILON)
{
QuatF dq; QuatF dq;
F32 sinHalfAngle; F32 sinHalfAngle;
mSinCos(angle * delta * -0.5f, sinHalfAngle, dq.w); mSinCos(angle * delta * -0.5f, sinHalfAngle, dq.w);
@ -73,22 +87,29 @@ void Rigid::integrate(F32 delta)
// Rotate the position around the center of mass // Rotate the position around the center of mass
Point3F lp = linPosition - worldCenterOfMass; Point3F lp = linPosition - worldCenterOfMass;
dq.mulP(lp,&linPosition); dq.mulP(lp, &linPosition);
linPosition += worldCenterOfMass; linPosition += worldCenterOfMass;
} }
// Update angular momentum // 3. advance position
angMomentum = angMomentum + torque * delta; linPosition += linVelocity * delta;
// Update linear position, momentum // 4. rebuild world inertia
linPosition = linPosition + linVelocity * delta; if (mFabs(angle) > POINT_EPSILON)
linMomentum = linMomentum + force * delta; {
linVelocity = linMomentum * oneOverMass; updateInertialTensor();
}
// Update dependent state variables // 5. refresh ang velocity
updateInertialTensor(); updateAngularVelocity();
updateVelocity();
// 6. CoM update
updateCenterOfMass(); updateCenterOfMass();
// 7. check if we can sleep
trySleep(delta);
} }
void Rigid::updateVelocity() void Rigid::updateVelocity()
@ -118,7 +139,7 @@ void Rigid::updateCenterOfMass()
void Rigid::applyImpulse(const Point3F &r, const Point3F &impulse) void Rigid::applyImpulse(const Point3F &r, const Point3F &impulse)
{ {
if (impulse.lenSquared() < mass) return; if (impulse.lenSquared() < mass) return;
atRest = false; wake();
// Linear momentum and velocity // Linear momentum and velocity
linMomentum += impulse; linMomentum += impulse;
@ -278,6 +299,47 @@ void Rigid::translateCenterOfMass(const Point3F &oldPos,const Point3F &newPos)
objectInertia(2,1) = objectInertia(1,2); objectInertia(2,1) = objectInertia(1,2);
} }
void Rigid::trySleep(F32 dt)
{
// If there is active force/torque, dont sleep
if (!force.isZero() || !torque.isZero())
{
sleepTimer = 0.0f; return;
}
const F32 linV2 = linVelocity.lenSquared();
const F32 angV2 = angVelocity.lenSquared();
if (linV2 < sleepLinearThreshold && angV2 < sleepAngThreshold)
{
sleepTimer += dt;
if (sleepTimer >= sleepTimeThreshold)
{
setAtRest();
}
}
else
{
sleepTimer = 0.0f;
}
}
void Rigid::setSleepThresholds(F32 linVel2, F32 angVel2, F32 timeToSleep)
{
sleepLinearThreshold = linVel2;
sleepAngThreshold = angVel2;
sleepTimeThreshold = timeToSleep;
}
void Rigid::wake()
{
if (atRest)
{
atRest = false;
sleepTimer = 0.0f;
}
}
void Rigid::getVelocity(const Point3F& r, Point3F* v) void Rigid::getVelocity(const Point3F& r, Point3F* v)
{ {
mCross(angVelocity, r, v); mCross(angVelocity, r, v);

View file

@ -61,11 +61,18 @@ public:
F32 oneOverMass; ///< 1 / mass F32 oneOverMass; ///< 1 / mass
F32 restitution; ///< Collision restitution F32 restitution; ///< Collision restitution
F32 friction; ///< Friction coefficient F32 friction; ///< Friction coefficient
// sleep threshold parameters
F32 sleepLinearThreshold; ///< M/S ^ 2
F32 sleepAngThreshold; ///< R/S ^ 2
F32 sleepTimeThreshold; ///< Seconds
F32 sleepTimer;
bool atRest; bool atRest;
private: private:
void translateCenterOfMass(const Point3F &oldPos,const Point3F &newPos); void translateCenterOfMass(const Point3F &oldPos,const Point3F &newPos);
void trySleep(F32 dt);
public: public:
// //
Rigid(); Rigid();
@ -94,6 +101,11 @@ public:
bool checkRestCondition(); bool checkRestCondition();
void setAtRest(); void setAtRest();
//
void setSleepThresholds(F32 linVel2, F32 angVel2, F32 timeToSleep);
void wake();
TORQUE_FORCEINLINE void updateAngularVelocity() { invWorldInertia.mulV(angMomentum, &angVelocity); }
}; };

View file

@ -1253,6 +1253,9 @@ bool RigidShape::updateCollision(F32 dt)
mRigid.getTransform(&mat); mRigid.getTransform(&mat);
cmat = mConvex.getTransform(); cmat = mConvex.getTransform();
SceneObject* mounted;
for (mounted = getMountList(); mounted; mounted = mounted->getMountLink())
mounted->disableCollision();
mCollisionList.clear(); mCollisionList.clear();
CollisionState *state = mConvex.findClosestState(cmat, getScale(), mDataBlock->collisionTol); CollisionState *state = mConvex.findClosestState(cmat, getScale(), mDataBlock->collisionTol);
if (state && state->mDist <= mDataBlock->collisionTol) if (state && state->mDist <= mDataBlock->collisionTol)
@ -1260,9 +1263,12 @@ bool RigidShape::updateCollision(F32 dt)
//resolveDisplacement(ns,state,dt); //resolveDisplacement(ns,state,dt);
mConvex.getCollisionInfo(cmat, getScale(), &mCollisionList, mDataBlock->collisionTol); mConvex.getCollisionInfo(cmat, getScale(), &mCollisionList, mDataBlock->collisionTol);
} }
// Resolve collisions // Resolve collisions
bool collided = resolveCollision(mRigid,mCollisionList, dt); bool collided = resolveCollision(mRigid,mCollisionList, dt);
for (mounted = getMountList(); mounted; mounted = mounted->getMountLink())
mounted->enableCollision();
return collided; return collided;
} }
@ -1682,7 +1688,7 @@ void RigidShape::initPersistFields()
docsURL; docsURL;
addField("disableMove", TypeBool, Offset(mDisableMove, RigidShape), addField("disableMove", TypeBool, Offset(mDisableMove, RigidShape),
"When this flag is set, the vehicle will ignore throttle changes."); "When this flag is set, the vehicle will ignore throttle changes.");
addField("isAtRest", TypeBool, Offset(mRigid.atRest, RigidShape), addProtectedField("isAtRest", TypeBool, Offset(mRigid.atRest, RigidShape), &defaultProtectedNotSetFn, &defaultProtectedGetFn,
"Debug read of the rest state. do not set"); "Debug read of the rest state. do not set");
Parent::initPersistFields(); Parent::initPersistFields();
} }

View file

@ -821,7 +821,7 @@ void WheeledVehicle::advanceTime(F32 dt)
// Stick the wheels to the ground. This is purely so they look // Stick the wheels to the ground. This is purely so they look
// good while the vehicle is being interpolated. // good while the vehicle is being interpolated.
//extendWheels(); extendWheels(isClientObject());
// Update wheel angular position and slip, this is a client visual // Update wheel angular position and slip, this is a client visual
// feature only, it has no affect on the physics. // feature only, it has no affect on the physics.
@ -1201,6 +1201,7 @@ void WheeledVehicle::extendWheels(bool clientHack)
wheel->surface.pos = rInfo.point; wheel->surface.pos = rInfo.point;
wheel->surface.material = rInfo.material; wheel->surface.material = rInfo.material;
wheel->surface.object = rInfo.object; wheel->surface.object = rInfo.object;
wheel->slipping = false;
} }
else else
{ {
@ -1475,35 +1476,36 @@ void WheeledVehicle::writePacketData(GameConnection *connection, BitStream *stre
{ {
Parent::writePacketData(connection, stream); Parent::writePacketData(connection, stream);
stream->writeFlag(mBraking); stream->writeFlag(mBraking);
Wheel* wend = &mWheel[mDataBlock->wheelCount];
for (Wheel* wheel = mWheel; wheel < wend; wheel++)
{
stream->write(wheel->avel);
stream->write(wheel->Dy);
stream->write(wheel->Dx);
stream->writeFlag(wheel->slipping);
}
} }
void WheeledVehicle::readPacketData(GameConnection *connection, BitStream *stream) void WheeledVehicle::readPacketData(GameConnection *connection, BitStream *stream)
{ {
Parent::readPacketData(connection, stream); Parent::readPacketData(connection, stream);
mBraking = stream->readFlag(); mBraking = stream->readFlag();
Wheel* wend = &mWheel[mDataBlock->wheelCount]; Wheel* wend = &mWheel[mDataBlock->wheelCount];
for (Wheel* wheel = mWheel; wheel < wend; wheel++) for (Wheel* wheel = mWheel; wheel < wend; wheel++)
{ {
stream->read(&wheel->avel); if (wheel->tire && wheel->spring) {
stream->read(&wheel->Dy); // Update angular position
stream->read(&wheel->Dx); wheel->apos += (wheel->avel) / M_2PI;
wheel->slipping = stream->readFlag(); wheel->apos -= mFloor(wheel->apos);
if (wheel->apos < 0)
wheel->apos = 1 - wheel->apos;
}
} }
// Rigid state is transmitted by the parent... // Rigid state is transmitted by the parent...
setPosition(mRigid.linPosition,mRigid.angPosition); setPosition(mRigid.linPosition,mRigid.angPosition);
mDelta.pos = mRigid.linPosition; mDelta.pos = mRigid.linPosition;
mDelta.rot[1] = mRigid.angPosition; mDelta.rot[1] = mRigid.angPosition;
// Stick the wheels to the ground. This is purely so they look
// good while the vehicle is being interpolated.
extendWheels(isClientObject());
updateWheelThreads();
} }