physics notes

based on https://github.com/TorqueGameEngines/Torque3D/pull/1165 and after further talks with @AtomicWalrus:
use the massbox or bounds box based  mRigid.setObjectInertia method
to reduce recirulating, combine resolvecollision and resolvecontacts
clamp seperation force for contact resolution
gravity normalized to earth standard (9.8,not 20)
take delta-time into account *once* for kinetic energy vs gravity rest checks
and for debug purposes, expose mRigid.atRest to the inspector to see if it's truly at reast or grinding calcs to minimal effect
This commit is contained in:
AzaezelX 2023-12-28 21:04:16 -06:00
parent 4c58a3601f
commit 3c7d2b1b6a
4 changed files with 57 additions and 22 deletions

View file

@ -900,9 +900,11 @@ bool RigidShape::onNewDataBlock(GameBaseData* dptr, bool reload)
mRigid.restitution = mDataBlock->body.restitution;
mRigid.setCenterOfMass(mDataBlock->massCenter);
// Ignores massBox, just set sphere for now. Derived objects
// can set what they want.
mRigid.setObjectInertia();
// Set inertial tensor, default for the RigidShape is sphere
if (mDataBlock->massBox.x > 0 && mDataBlock->massBox.y > 0 && mDataBlock->massBox.z > 0)
mRigid.setObjectInertia(mDataBlock->massBox);
else
mRigid.setObjectInertia(mObjBox.maxExtents - mObjBox.minExtents);
scriptOnNewDataBlock();
@ -1115,9 +1117,9 @@ void RigidShape::updatePos(F32 dt)
if (mCollisionList.getCount())
{
F32 k = mRigid.getKineticEnergy();
F32 G = mNetGravity * dt;
F32 G = mNetGravity;
F32 Kg = 0.5 * mRigid.mass * G * G;
if (k < sRestTol * Kg && ++restCount > sRestCount)
if (k < sRestTol * Kg* dt && ++restCount > sRestCount)
mRigid.setAtRest();
}
else
@ -1222,10 +1224,6 @@ void RigidShape::updateForces(F32 dt)
mRigid.force = force;
mRigid.torque = torque;
// If we're still atRest, make sure we're not accumulating anything
if ((force.lenSquared() < mDataBlock->contactTol)&& (force.lenSquared() < mDataBlock->contactTol))
mRigid.setAtRest();
}
@ -1260,8 +1258,8 @@ bool RigidShape::updateCollision(F32 dt)
}
// Resolve collisions
bool collided = resolveCollision(mRigid,mCollisionList);
resolveContacts(mRigid,mCollisionList,dt);
bool collided = resolveCollision(mRigid,mCollisionList, dt);
//resolveContacts(mRigid,mCollisionList,dt);
return collided;
}
@ -1271,11 +1269,12 @@ bool RigidShape::updateCollision(F32 dt)
Handle collision impacts, as opposed to contacts. Impulses are calculated based
on standard collision resolution formulas.
*/
bool RigidShape::resolveCollision(Rigid& ns,CollisionList& cList)
bool RigidShape::resolveCollision(Rigid& ns,CollisionList& cList, F32 dt)
{
PROFILE_SCOPE(RigidShape_resolveCollision);
// Apply impulses to resolve collision
bool collided = false;
Point3F t, p(0, 0, 0), l(0, 0, 0);
for (S32 i = 0; i < cList.getCount(); i++)
{
Collision& c = cList[i];
@ -1288,9 +1287,7 @@ bool RigidShape::resolveCollision(Rigid& ns,CollisionList& cList)
F32 vn = mDot(v, c.normal);
// Only interested in velocities greater than sContactTol,
// velocities less than that will be dealt with as contacts
// "constraints".
if (vn < -mDataBlock->contactTol)
if (mFabs(vn) > mDataBlock->contactTol)
{
// Apply impulses to the rigid body to keep it from
@ -1313,8 +1310,44 @@ bool RigidShape::resolveCollision(Rigid& ns,CollisionList& cList)
queueCollision(col, v - col->getVelocity());
}
}
// velocities less than that will be dealt with as contacts
// "constraints".
else
{
// Penetration force. This is actually a spring which
// will seperate the body from the collision surface.
F32 zi = 2 * mFabs(mRigid.getZeroImpulse(r, c.normal) / dt);
F32 s = mMax((mDataBlock->collisionTol - c.distance) * zi - ((vn / 2.0) * zi),0.0f);
Point3F f = c.normal * s;
// Friction impulse, calculated as a function of the
// amount of force it would take to stop the motion
// perpendicular to the normal.
Point3F uv = v - (c.normal * vn);
F32 ul = uv.len();
if (s > 0 && ul)
{
uv /= -ul;
F32 u = ul * ns.getZeroImpulse(r, uv) / dt;
s *= mRigid.friction;
if (u > s)
u = s;
f += uv * u;
}
// Accumulate forces
p += f;
mCross(r, f, &t);
l += t;
}
}
}
// Contact constraint forces act over time...
ns.linMomentum += p * dt;
ns.angMomentum += l * dt;
ns.updateVelocity();
return collided;
}
@ -1350,7 +1383,7 @@ bool RigidShape::resolveContacts(Rigid& ns,CollisionList& cList,F32 dt)
// Penetration force. This is actually a spring which
// will seperate the body from the collision surface.
F32 zi = 2 * mFabs(mRigid.getZeroImpulse(r,c.normal));
F32 zi = 2 * mFabs(mRigid.getZeroImpulse(r,c.normal) / dt);
F32 s = (mDataBlock->collisionTol - c.distance) * zi - ((vn / mDataBlock->contactTol) * zi);
Point3F f = c.normal * s;
@ -1362,7 +1395,7 @@ bool RigidShape::resolveContacts(Rigid& ns,CollisionList& cList,F32 dt)
if (s > 0 && ul)
{
uv /= -ul;
F32 u = ul * ns.getZeroImpulse(r,uv);
F32 u = ul * ns.getZeroImpulse(r,uv) / dt;
s *= mRigid.friction;
if (u > s)
u = s;
@ -1693,6 +1726,8 @@ 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),
"Debug read of the rest state. do not set");
Parent::initPersistFields();
}