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;
friction = 0.5f;
atRest = false;
sleepLinearThreshold = 0.0004f;
sleepAngThreshold = 0.0004f;
sleepTimeThreshold = 0.75f;
sleepTimer = 0.0f;
}
void Rigid::clearForces()
@ -57,9 +62,18 @@ void Rigid::clearForces()
//-----------------------------------------------------------------------------
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();
if (angle != 0.0f) {
if (mFabs(angle)> POINT_EPSILON)
{
QuatF dq;
F32 sinHalfAngle;
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
Point3F lp = linPosition - worldCenterOfMass;
dq.mulP(lp,&linPosition);
dq.mulP(lp, &linPosition);
linPosition += worldCenterOfMass;
}
// Update angular momentum
angMomentum = angMomentum + torque * delta;
// 3. advance position
linPosition += linVelocity * delta;
// Update linear position, momentum
linPosition = linPosition + linVelocity * delta;
linMomentum = linMomentum + force * delta;
linVelocity = linMomentum * oneOverMass;
// 4. rebuild world inertia
if (mFabs(angle) > POINT_EPSILON)
{
updateInertialTensor();
}
// Update dependent state variables
updateInertialTensor();
updateVelocity();
// 5. refresh ang velocity
updateAngularVelocity();
// 6. CoM update
updateCenterOfMass();
// 7. check if we can sleep
trySleep(delta);
}
void Rigid::updateVelocity()
@ -118,7 +139,7 @@ void Rigid::updateCenterOfMass()
void Rigid::applyImpulse(const Point3F &r, const Point3F &impulse)
{
if (impulse.lenSquared() < mass) return;
atRest = false;
wake();
// Linear momentum and velocity
linMomentum += impulse;
@ -278,6 +299,47 @@ void Rigid::translateCenterOfMass(const Point3F &oldPos,const Point3F &newPos)
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)
{
mCross(angVelocity, r, v);

View file

@ -61,11 +61,18 @@ public:
F32 oneOverMass; ///< 1 / mass
F32 restitution; ///< Collision restitution
F32 friction; ///< Friction coefficient
// sleep threshold parameters
F32 sleepLinearThreshold; ///< M/S ^ 2
F32 sleepAngThreshold; ///< R/S ^ 2
F32 sleepTimeThreshold; ///< Seconds
F32 sleepTimer;
bool atRest;
private:
void translateCenterOfMass(const Point3F &oldPos,const Point3F &newPos);
void trySleep(F32 dt);
public:
//
Rigid();
@ -94,6 +101,11 @@ public:
bool checkRestCondition();
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);
cmat = mConvex.getTransform();
SceneObject* mounted;
for (mounted = getMountList(); mounted; mounted = mounted->getMountLink())
mounted->disableCollision();
mCollisionList.clear();
CollisionState *state = mConvex.findClosestState(cmat, getScale(), mDataBlock->collisionTol);
if (state && state->mDist <= mDataBlock->collisionTol)
@ -1260,9 +1263,12 @@ bool RigidShape::updateCollision(F32 dt)
//resolveDisplacement(ns,state,dt);
mConvex.getCollisionInfo(cmat, getScale(), &mCollisionList, mDataBlock->collisionTol);
}
// Resolve collisions
bool collided = resolveCollision(mRigid,mCollisionList, dt);
for (mounted = getMountList(); mounted; mounted = mounted->getMountLink())
mounted->enableCollision();
return collided;
}
@ -1682,7 +1688,7 @@ void RigidShape::initPersistFields()
docsURL;
addField("disableMove", TypeBool, Offset(mDisableMove, RigidShape),
"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");
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
// good while the vehicle is being interpolated.
//extendWheels();
extendWheels(isClientObject());
// Update wheel angular position and slip, this is a client visual
// 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.material = rInfo.material;
wheel->surface.object = rInfo.object;
wheel->slipping = false;
}
else
{
@ -1475,35 +1476,36 @@ void WheeledVehicle::writePacketData(GameConnection *connection, BitStream *stre
{
Parent::writePacketData(connection, stream);
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)
{
Parent::readPacketData(connection, stream);
mBraking = stream->readFlag();
Wheel* wend = &mWheel[mDataBlock->wheelCount];
for (Wheel* wheel = mWheel; wheel < wend; wheel++)
{
stream->read(&wheel->avel);
stream->read(&wheel->Dy);
stream->read(&wheel->Dx);
wheel->slipping = stream->readFlag();
if (wheel->tire && wheel->spring) {
// Update angular position
wheel->apos += (wheel->avel) / M_2PI;
wheel->apos -= mFloor(wheel->apos);
if (wheel->apos < 0)
wheel->apos = 1 - wheel->apos;
}
}
// Rigid state is transmitted by the parent...
setPosition(mRigid.linPosition,mRigid.angPosition);
mDelta.pos = mRigid.linPosition;
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();
}