Methods to compute more accurate inertia tensor for btCompoundShape and btConvexTriangleMeshShape.
Thanks to Ole K. for the fixes, see http://www.bulletphysics.com/Bullet/phpBB3/viewtopic.php?f=9&t=2562
This commit is contained in:
@@ -147,5 +147,62 @@ void btCompoundShape::calculateLocalInertia(btScalar mass,btVector3& inertia) co
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void btCompoundShape::calculatePrincipalAxisTransform(btScalar* masses, btTransform& principal, btVector3& inertia) const
|
||||
{
|
||||
int n = m_children.size();
|
||||
|
||||
btScalar totalMass = 0;
|
||||
btVector3 center(0, 0, 0);
|
||||
for (int k = 0; k < n; k++)
|
||||
{
|
||||
center += m_children[k].m_transform.getOrigin() * masses[k];
|
||||
totalMass += masses[k];
|
||||
}
|
||||
center /= totalMass;
|
||||
principal.setOrigin(center);
|
||||
|
||||
btMatrix3x3 tensor(0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
for (int k = 0; k < n; k++)
|
||||
{
|
||||
btVector3 i;
|
||||
m_children[k].m_childShape->calculateLocalInertia(masses[k], i);
|
||||
|
||||
const btTransform& t = m_children[k].m_transform;
|
||||
btVector3 o = t.getOrigin() - center;
|
||||
|
||||
//compute inertia tensor in coordinate system of compound shape
|
||||
btMatrix3x3 j = t.getBasis().transpose();
|
||||
j[0] *= i[0];
|
||||
j[1] *= i[1];
|
||||
j[2] *= i[2];
|
||||
j = t.getBasis() * j;
|
||||
|
||||
//add inertia tensor
|
||||
tensor[0] += j[0];
|
||||
tensor[1] += j[1];
|
||||
tensor[2] += j[2];
|
||||
|
||||
//compute inertia tensor of pointmass at o
|
||||
btScalar o2 = o.length2();
|
||||
j[0].setValue(o2, 0, 0);
|
||||
j[1].setValue(0, o2, 0);
|
||||
j[2].setValue(0, 0, o2);
|
||||
j[0] += o * -o.x();
|
||||
j[1] += o * -o.y();
|
||||
j[2] += o * -o.z();
|
||||
|
||||
//add inertia tensor of pointmass
|
||||
tensor[0] += masses[k] * j[0];
|
||||
tensor[1] += masses[k] * j[1];
|
||||
tensor[2] += masses[k] * j[2];
|
||||
}
|
||||
|
||||
tensor.diagonalize(principal.getBasis(), btScalar(0.00001), 20);
|
||||
inertia.setValue(tensor[0][0], tensor[1][1], tensor[2][2]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -142,6 +142,14 @@ public:
|
||||
return m_aabbTree;
|
||||
}
|
||||
|
||||
///computes the exact moment of inertia and the transform from the coordinate system defined by the principal axes of the moment of inertia
|
||||
///and the center of mass to the current coordinate system. "masses" points to an array of masses of the children. The resulting transform
|
||||
///"principal" has to be applied inversely to all children transforms in order for the local coordinate system of the compound
|
||||
///shape to be centered at the center of mass and to coincide with the principal axes. This also necessitates a correction of the world transform
|
||||
///of the collision object by the principal transform.
|
||||
void calculatePrincipalAxisTransform(btScalar* masses, btTransform& principal, btVector3& inertia) const;
|
||||
|
||||
|
||||
private:
|
||||
btScalar m_collisionMargin;
|
||||
protected:
|
||||
|
||||
@@ -204,3 +204,113 @@ const btVector3& btConvexTriangleMeshShape::getLocalScaling() const
|
||||
{
|
||||
return m_stridingMesh->getScaling();
|
||||
}
|
||||
|
||||
void btConvexTriangleMeshShape::calculatePrincipalAxisTransform(btTransform& principal, btVector3& inertia, btScalar& volume) const
|
||||
{
|
||||
class CenterCallback: public btInternalTriangleIndexCallback
|
||||
{
|
||||
bool first;
|
||||
btVector3 ref;
|
||||
btVector3 sum;
|
||||
btScalar volume;
|
||||
|
||||
public:
|
||||
|
||||
CenterCallback() : first(true), ref(0, 0, 0), sum(0, 0, 0), volume(0)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void internalProcessTriangleIndex(btVector3* triangle, int partId, int triangleIndex)
|
||||
{
|
||||
(void) triangleIndex;
|
||||
(void) partId;
|
||||
if (first)
|
||||
{
|
||||
ref = triangle[0];
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
btScalar vol = btFabs((triangle[0] - ref).triple(triangle[1] - ref, triangle[2] - ref));
|
||||
sum += (btScalar(0.25) * vol) * ((triangle[0] + triangle[1] + triangle[2] + ref));
|
||||
volume += vol;
|
||||
}
|
||||
}
|
||||
|
||||
btVector3 getCenter()
|
||||
{
|
||||
return (volume > 0) ? sum / volume : ref;
|
||||
}
|
||||
|
||||
btScalar getVolume()
|
||||
{
|
||||
return volume * btScalar(1. / 6);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class InertiaCallback: public btInternalTriangleIndexCallback
|
||||
{
|
||||
btMatrix3x3 sum;
|
||||
btVector3 center;
|
||||
|
||||
public:
|
||||
|
||||
InertiaCallback(btVector3& center) : sum(0, 0, 0, 0, 0, 0, 0, 0, 0), center(center)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void internalProcessTriangleIndex(btVector3* triangle, int partId, int triangleIndex)
|
||||
{
|
||||
(void) triangleIndex;
|
||||
(void) partId;
|
||||
btMatrix3x3 i;
|
||||
btVector3 a = triangle[0] - center;
|
||||
btVector3 b = triangle[1] - center;
|
||||
btVector3 c = triangle[2] - center;
|
||||
btVector3 abc = a + b + c;
|
||||
btScalar volNeg = -btFabs(a.triple(b, c)) * btScalar(1. / 6);
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
for (int k = 0; k <= j; k++)
|
||||
{
|
||||
i[j][k] = i[k][j] = volNeg * (center[j] * center[k]
|
||||
+ btScalar(0.25) * (center[j] * abc[k] + center[k] * abc[j])
|
||||
+ btScalar(0.1) * (a[j] * a[k] + b[j] * b[k] + c[j] * c[k])
|
||||
+ btScalar(0.05) * (a[j] * b[k] + a[k] * b[j] + a[j] * c[k] + a[k] * c[j] + b[j] * c[k] + b[k] * c[j]));
|
||||
}
|
||||
}
|
||||
btScalar i00 = -i[0][0];
|
||||
btScalar i11 = -i[1][1];
|
||||
btScalar i22 = -i[2][2];
|
||||
i[0][0] = i11 + i22;
|
||||
i[1][1] = i22 + i00;
|
||||
i[2][2] = i00 + i11;
|
||||
sum[0] += i[0];
|
||||
sum[1] += i[1];
|
||||
sum[2] += i[2];
|
||||
}
|
||||
|
||||
btMatrix3x3& getInertia()
|
||||
{
|
||||
return sum;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
CenterCallback centerCallback;
|
||||
btVector3 aabbMax(btScalar(1e30),btScalar(1e30),btScalar(1e30));
|
||||
m_stridingMesh->InternalProcessAllTriangles(¢erCallback, -aabbMax, aabbMax);
|
||||
btVector3 center = centerCallback.getCenter();
|
||||
principal.setOrigin(center);
|
||||
volume = centerCallback.getVolume();
|
||||
|
||||
InertiaCallback inertiaCallback(center);
|
||||
m_stridingMesh->InternalProcessAllTriangles(&inertiaCallback, -aabbMax, aabbMax);
|
||||
|
||||
btMatrix3x3& i = inertiaCallback.getInertia();
|
||||
i.diagonalize(principal.getBasis(), btScalar(0.00001), 20);
|
||||
inertia.setValue(i[0][0], i[1][1], i[2][2]);
|
||||
inertia /= volume;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,13 @@ public:
|
||||
virtual void setLocalScaling(const btVector3& scaling);
|
||||
virtual const btVector3& getLocalScaling() const;
|
||||
|
||||
///computes the exact moment of inertia and the transform from the coordinate system defined by the principal axes of the moment of inertia
|
||||
///and the center of mass to the current coordinate system. A mass of 1 is assumed, for other masses just multiply the computed "inertia"
|
||||
///by the mass. The resulting transform "principal" has to be applied inversely to the mesh in order for the local coordinate system of the
|
||||
///shape to be centered at the center of mass and to coincide with the principal axes. This also necessitates a correction of the world transform
|
||||
///of the collision object by the principal transform. This method also computes the volume of the convex mesh.
|
||||
void btConvexTriangleMeshShape::calculatePrincipalAxisTransform(btTransform& principal, btVector3& inertia, btScalar& volume) const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user