Added experimental implicit gyroscopic force implementation, one by Michael Ewert, and another by Cooper (from OpenDE)
Will also add Erin Catto's local implicit version from the GDC 2015 tutorial Added demo for btGeneric6DofSpring2Constraint, thanks to Gabor Puhr Add gfxBridge.autogenerateGraphicsObjects method for Bullet 2 demos in new framework (need to implement all Bullet 2 collision shape types...) Use 1,1,1 for local scaling in btStaticPlaneShape
This commit is contained in:
@@ -87,7 +87,7 @@ void btRigidBody::setupRigidBody(const btRigidBody::btRigidBodyConstructionInfo&
|
||||
setMassProps(constructionInfo.m_mass, constructionInfo.m_localInertia);
|
||||
updateInertiaTensor();
|
||||
|
||||
m_rigidbodyFlags = 0;
|
||||
m_rigidbodyFlags = BT_ENABLE_GYROPSCOPIC_FORCE_IMPLICIT_EWERT;
|
||||
|
||||
|
||||
m_deltaLinearVelocity.setZero();
|
||||
@@ -257,12 +257,41 @@ void btRigidBody::updateInertiaTensor()
|
||||
}
|
||||
|
||||
|
||||
|
||||
btVector3 btRigidBody::getLocalInertia() const
|
||||
{
|
||||
|
||||
btVector3 inertiaLocal;
|
||||
const btVector3 inertia = m_invInertiaLocal;
|
||||
inertiaLocal.setValue(inertia.x() != btScalar(0.0) ? btScalar(1.0) / inertia.x() : btScalar(0.0),
|
||||
inertia.y() != btScalar(0.0) ? btScalar(1.0) / inertia.y() : btScalar(0.0),
|
||||
inertia.z() != btScalar(0.0) ? btScalar(1.0) / inertia.z() : btScalar(0.0));
|
||||
return inertiaLocal;
|
||||
}
|
||||
|
||||
inline btVector3 evalEulerEqn(const btVector3& w1, const btVector3& w0, const btVector3& T, const btScalar dt,
|
||||
const btMatrix3x3 &I)
|
||||
{
|
||||
const btVector3 w2 = I*w1 + w1.cross(I*w1)*dt - (T*dt + I*w0);
|
||||
return w2;
|
||||
}
|
||||
|
||||
inline btMatrix3x3 evalEulerEqnDeriv(const btVector3& w1, const btVector3& w0, const btScalar dt,
|
||||
const btMatrix3x3 &I)
|
||||
{
|
||||
|
||||
btMatrix3x3 w1x, Iw1x;
|
||||
const btVector3 Iwi = (I*w1);
|
||||
w1.getSkewSymmetricMatrix(&w1x[0], &w1x[1], &w1x[2]);
|
||||
Iwi.getSkewSymmetricMatrix(&Iw1x[0], &Iw1x[1], &Iw1x[2]);
|
||||
|
||||
const btMatrix3x3 dfw1 = I + (w1x*I - Iw1x)*dt;
|
||||
return dfw1;
|
||||
}
|
||||
|
||||
btVector3 btRigidBody::computeGyroscopicForce(btScalar maxGyroscopicForce) const
|
||||
{
|
||||
btVector3 inertiaLocal;
|
||||
inertiaLocal[0] = 1.f/getInvInertiaDiagLocal()[0];
|
||||
inertiaLocal[1] = 1.f/getInvInertiaDiagLocal()[1];
|
||||
inertiaLocal[2] = 1.f/getInvInertiaDiagLocal()[2];
|
||||
btVector3 inertiaLocal = getLocalInertia();
|
||||
btMatrix3x3 inertiaTensorWorld = getWorldTransform().getBasis().scaled(inertiaLocal) * getWorldTransform().getBasis().transpose();
|
||||
btVector3 tmp = inertiaTensorWorld*getAngularVelocity();
|
||||
btVector3 gf = getAngularVelocity().cross(tmp);
|
||||
@@ -274,6 +303,138 @@ btVector3 btRigidBody::computeGyroscopicForce(btScalar maxGyroscopicForce) const
|
||||
return gf;
|
||||
}
|
||||
|
||||
void btSetCrossMatrixMinus(btMatrix3x3& res, const btVector3& a)
|
||||
{
|
||||
const btScalar a_0 = a[0], a_1 = a[1], a_2 = a[2];
|
||||
res.setValue(0, +a_2, -a_1,
|
||||
-a_2, 0, +a_0,
|
||||
+a_1, -a_0, 0);
|
||||
}
|
||||
|
||||
btVector3 btRigidBody::computeGyroscopicImpulseImplicit_Cooper(btScalar step) const
|
||||
{
|
||||
#if 0
|
||||
dReal h = callContext->m_stepperCallContext->m_stepSize; // Step size
|
||||
dVector3 L; // Compute angular momentum
|
||||
dMultiply0_331(L, I, b->avel);
|
||||
#endif
|
||||
|
||||
btVector3 inertiaLocal = getLocalInertia();
|
||||
btMatrix3x3 inertiaTensorWorld = getWorldTransform().getBasis().scaled(inertiaLocal) * getWorldTransform().getBasis().transpose();
|
||||
btVector3 L = inertiaTensorWorld*getAngularVelocity();
|
||||
|
||||
btMatrix3x3 Itild(0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
|
||||
#if 0
|
||||
for (int ii = 0; ii<12; ++ii) {
|
||||
Itild[ii] = Itild[ii] * h + I[ii];
|
||||
}
|
||||
#endif
|
||||
|
||||
btSetCrossMatrixMinus(Itild, L*step);
|
||||
Itild += inertiaTensorWorld;
|
||||
|
||||
|
||||
#if 0
|
||||
// Compute a new effective 'inertia tensor'
|
||||
// for the implicit step: the cross-product
|
||||
// matrix of the angular momentum plus the
|
||||
// old tensor scaled by the timestep.
|
||||
// Itild may not be symmetric pos-definite,
|
||||
// but we can still use it to compute implicit
|
||||
// gyroscopic torques.
|
||||
dMatrix3 Itild = { 0 };
|
||||
dSetCrossMatrixMinus(Itild, L, 4);
|
||||
for (int ii = 0; ii<12; ++ii) {
|
||||
Itild[ii] = Itild[ii] * h + I[ii];
|
||||
}
|
||||
#endif
|
||||
|
||||
L *= step;
|
||||
//Itild may not be symmetric pos-definite
|
||||
btMatrix3x3 itInv = Itild.inverse();
|
||||
Itild = inertiaTensorWorld * itInv;
|
||||
btMatrix3x3 ident(1,0,0,0,1,0,0,0,1);
|
||||
Itild -= ident;
|
||||
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
// Scale momentum by inverse time to get
|
||||
// a sort of "torque"
|
||||
dScaleVector3(L, dRecip(h));
|
||||
// Invert the pseudo-tensor
|
||||
dMatrix3 itInv;
|
||||
// This is a closed-form inversion.
|
||||
// It's probably not numerically stable
|
||||
// when dealing with small masses with
|
||||
// a large asymmetry.
|
||||
// An LU decomposition might be better.
|
||||
if (dInvertMatrix3(itInv, Itild) != 0) {
|
||||
// "Divide" the original tensor
|
||||
// by the pseudo-tensor (on the right)
|
||||
dMultiply0_333(Itild, I, itInv);
|
||||
// Subtract an identity matrix
|
||||
Itild[0] -= 1; Itild[5] -= 1; Itild[10] -= 1;
|
||||
|
||||
// This new inertia matrix rotates the
|
||||
// momentum to get a new set of torques
|
||||
// that will work correctly when applied
|
||||
// to the old inertia matrix as explicit
|
||||
// torques with a semi-implicit update
|
||||
// step.
|
||||
dVector3 tau0;
|
||||
dMultiply0_331(tau0, Itild, L);
|
||||
|
||||
// Add the gyro torques to the torque
|
||||
// accumulator
|
||||
for (int ii = 0; ii<3; ++ii) {
|
||||
b->tacc[ii] += tau0[ii];
|
||||
}
|
||||
#endif
|
||||
btVector3 tau0 = Itild * L;
|
||||
return tau0;
|
||||
return btVector3(0, 0, 0);
|
||||
}
|
||||
|
||||
btVector3 btRigidBody::computeGyroscopicImpulseImplicit_Ewert(btScalar step) const
|
||||
{
|
||||
// use full newton-euler equations. common practice to drop the wxIw term. want it for better tumbling behavior.
|
||||
// calculate using implicit euler step so it's stable.
|
||||
|
||||
const btVector3 inertiaLocal = getLocalInertia();
|
||||
const btVector3 w0 = getAngularVelocity();
|
||||
|
||||
btMatrix3x3 I;
|
||||
|
||||
I = m_worldTransform.getBasis().scaled(inertiaLocal) *
|
||||
m_worldTransform.getBasis().transpose();
|
||||
|
||||
// use newtons method to find implicit solution for new angular velocity (w')
|
||||
// f(w') = -(T*step + Iw) + Iw' + w' + w'xIw'*step = 0
|
||||
// df/dw' = I + 1xIw'*step + w'xI*step
|
||||
|
||||
btVector3 w1 = w0;
|
||||
|
||||
// one step of newton's method
|
||||
{
|
||||
const btVector3 fw = evalEulerEqn(w1, w0, btVector3(0, 0, 0), step, I);
|
||||
const btMatrix3x3 dfw = evalEulerEqnDeriv(w1, w0, step, I);
|
||||
|
||||
const btMatrix3x3 dfw_inv = dfw.inverse();
|
||||
btVector3 dw;
|
||||
|
||||
dw = dfw_inv*fw;
|
||||
|
||||
w1 -= dw;
|
||||
}
|
||||
|
||||
btVector3 gf = (w1 - w0);
|
||||
return gf;
|
||||
}
|
||||
|
||||
|
||||
void btRigidBody::integrateVelocities(btScalar step)
|
||||
{
|
||||
if (isStaticOrKinematicObject())
|
||||
|
||||
Reference in New Issue
Block a user