move capsule inertia to the body frame
With this bugfix capsule motions are realistic.
This commit is contained in:
parent
efae0fc202
commit
6d76caad1d
@ -44,91 +44,87 @@ void b3CapsuleShape::ComputeMass(b3MassData* massData, float32 density) const
|
|||||||
b3Vec3 B = m_centers[1];
|
b3Vec3 B = m_centers[1];
|
||||||
|
|
||||||
b3Vec3 d = B - A;
|
b3Vec3 d = B - A;
|
||||||
|
|
||||||
float32 h = b3Length(d);
|
float32 h = b3Length(d);
|
||||||
|
B3_ASSERT(h > B3_LINEAR_SLOP);
|
||||||
float32 h2 = h * h;
|
float32 h2 = h * h;
|
||||||
|
|
||||||
float32 r = m_radius;
|
float32 r = m_radius;
|
||||||
float32 r2 = r * r;
|
float32 r2 = r * r;
|
||||||
float32 r3 = r2 * r;
|
float32 r3 = r2 * r;
|
||||||
|
|
||||||
// Cylinder inertia about the capsule center of mass
|
//
|
||||||
b3MassData Ic_Cylinder;
|
b3Vec3 center = 0.5f * (A + B);
|
||||||
|
float32 mass = 0.0f;
|
||||||
|
b3Mat33 I; I.SetZero();
|
||||||
|
|
||||||
|
b3Mat33 rotation;
|
||||||
|
rotation.y = (1.0f / h) * d;
|
||||||
|
rotation.x = b3Perp(rotation.y);
|
||||||
|
rotation.z = b3Cross(rotation.y, rotation.x);
|
||||||
|
|
||||||
|
// Cylinder
|
||||||
{
|
{
|
||||||
// Cylinder mass
|
// Mass
|
||||||
float32 volume = B3_PI * r2 * h;
|
float32 cylinderVolume = B3_PI * r2 * h;
|
||||||
float32 mass = density * volume;
|
float32 cylinderMass = density * cylinderVolume;
|
||||||
|
|
||||||
// Cylinder inertia about the center of mass (same as capsule center of mass)
|
// Inertia about the center of mass
|
||||||
float32 x = (1.0f / 12.0f) * mass * (3.0f * r2 + h2);
|
float32 Ixx = (1.0f / 12.0f) * cylinderMass * (3.0f * r2 + h2);
|
||||||
float32 y = 0.5f * mass * r2;
|
float32 Iyy = 0.5f * cylinderMass * r2;
|
||||||
float32 z = x;
|
// Izz = Ixx
|
||||||
|
b3Mat33 cylinderI = b3Diagonal(Ixx, Iyy, Ixx);
|
||||||
|
|
||||||
Ic_Cylinder.center = 0.5f * (A + B);
|
// Align the inertia with the body frame
|
||||||
Ic_Cylinder.mass = mass;
|
cylinderI = b3RotateToFrame(cylinderI, rotation);
|
||||||
Ic_Cylinder.I = b3Diagonal(x, y, z);
|
|
||||||
|
// Shift the inertia to the body origin
|
||||||
|
cylinderI += cylinderMass * b3Steiner(center);
|
||||||
|
|
||||||
|
// Contribute
|
||||||
|
mass += cylinderMass;
|
||||||
|
I += cylinderI;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hemisphere inertia about the capsule center of mass
|
// Hemispheres
|
||||||
b3MassData Ic_Hemisphere;
|
|
||||||
{
|
{
|
||||||
// Hemisphere volume and mass
|
// Mass
|
||||||
float32 volume = (2.0f / 3.0f) * B3_PI * r3;
|
float32 hemiVolume = (2.0f / 3.0f) * B3_PI * r3;
|
||||||
float32 mass = density * volume;
|
float32 hemiMass = density * hemiVolume;
|
||||||
|
|
||||||
// I = Ic + m * d^2
|
|
||||||
// Ic = I - m * d^2
|
|
||||||
|
|
||||||
// Hemisphere inertia about the origin
|
// Hemisphere inertia about the origin
|
||||||
float32 Io = (2.0f / 5.0f) * mass * r2;
|
float32 Io = (2.0f / 5.0f) * hemiMass * r2;
|
||||||
|
|
||||||
|
// Hemisphere center of mass relative to the origin
|
||||||
|
float32 coy = (3.0f / 8.0f) * r;
|
||||||
|
|
||||||
// Hemisphere center of mass relative to origin
|
// Hemisphere inertia about the hemisphere/capsule center of mass
|
||||||
float32 d1 = (3.0f / 8.0f) * r;
|
float32 Iyy = Io - hemiMass * coy * coy;
|
||||||
|
|
||||||
// Hemisphere inertia about the hemisphere center of mass
|
|
||||||
float32 Ic = Io - (mass * d1 * d1);
|
|
||||||
|
|
||||||
// Hemisphere center of mass relative to the capsule center of mass
|
// Hemisphere center of mass relative to the capsule center of mass
|
||||||
float32 d2 = d1 + 0.5f * h;
|
float32 ccy = coy + 0.5f * h;
|
||||||
|
|
||||||
// Hemisphere inertia about the capsule center of mass
|
// Hemisphere inertia about the capsule the center of mass
|
||||||
float32 x = Ic + (mass * d2 * d2);
|
float32 Ixx = Io + hemiMass * ccy * ccy;
|
||||||
float32 y = Io;
|
|
||||||
float32 z = x;
|
|
||||||
|
|
||||||
Ic_Hemisphere.center.Set(0.0f, d2, 0.0f);
|
// Izz = Ixx
|
||||||
Ic_Hemisphere.mass = mass;
|
b3Mat33 hemiI = b3Diagonal(Ixx, Iyy, Ixx);
|
||||||
Ic_Hemisphere.I = b3Diagonal(x, y, z);
|
|
||||||
|
// Align the inertia with the body frame
|
||||||
|
hemiI = b3RotateToFrame(hemiI, rotation);
|
||||||
|
|
||||||
|
// Shift the inertia to the body origin
|
||||||
|
hemiI += hemiMass * b3Steiner(center);
|
||||||
|
|
||||||
|
// Contribute twice
|
||||||
|
mass += 2.0f * hemiMass;
|
||||||
|
I += 2.0f * hemiI;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Capsule inertia about the capsule center of mass
|
// Centroid, total mass, inertia at the origin
|
||||||
b3MassData Ic_Capsule;
|
massData->center = center;
|
||||||
{
|
massData->mass = mass;
|
||||||
// Capsule center of mass
|
massData->I = I;
|
||||||
Ic_Capsule.center = 0.5f * (A + B);
|
|
||||||
// Inertia about the capsule center of mass
|
|
||||||
// taking two hemispheres into account
|
|
||||||
Ic_Capsule.mass = Ic_Cylinder.mass + 2.0f * Ic_Hemisphere.mass;
|
|
||||||
Ic_Capsule.I = Ic_Cylinder.I + 2.0f * Ic_Hemisphere.I;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Capsule inertia about the reference frame of the cylinder
|
|
||||||
// Center of mass doesn't change
|
|
||||||
B3_ASSERT(h > B3_LINEAR_SLOP);
|
|
||||||
b3Mat33 R;
|
|
||||||
R.SetIdentity();
|
|
||||||
if (h > B3_LINEAR_SLOP)
|
|
||||||
{
|
|
||||||
R.y = (1.0f / h) * d;
|
|
||||||
R.x = b3Perp(R.y);
|
|
||||||
R.z = b3Cross(R.y, R.x);
|
|
||||||
}
|
|
||||||
|
|
||||||
b3Mat33 Ic = b3RotateToFrame(Ic_Capsule.I, R);
|
|
||||||
|
|
||||||
// Inertia about the center of mass
|
|
||||||
massData->center = Ic_Capsule.center;
|
|
||||||
massData->mass = Ic_Capsule.mass;
|
|
||||||
massData->I = Ic;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void b3CapsuleShape::ComputeAABB(b3AABB3* aabb, const b3Transform& xf) const
|
void b3CapsuleShape::ComputeAABB(b3AABB3* aabb, const b3Transform& xf) const
|
||||||
|
Loading…
x
Reference in New Issue
Block a user