Sure, this is possible, but you need to extract the vertex positions yourself. Here is a code snippet from a test project. It iterates of the meshes of a model, extracts the vertices and creates a convex shape for each bone:
private void CreateLimbs()
{
ModelBoneCollection bones = _model.Bones;
// A list of vertex lists. One vertex list for each bone of the model.
List<List<Vector3F>> boneVerticesArray;
boneVerticesArray = bones.Select(bone => new List<Vector3F>()).ToList();
// Loop through the meshes of the model. Extract the vertices and fill the
// boneVerticesArray.
foreach (var mesh in _model.Meshes)
{
Matrix transform = GetAbsoluteTransform(mesh.ParentBone);
foreach (var meshPart in mesh.MeshParts)
{
var vertexDeclaration = meshPart.VertexBuffer.VertexDeclaration;
var vertexElements = vertexDeclaration.GetVertexElements();
// Get the verex positions.
var positionElement = vertexElements.First(e => e.VertexElementUsage == VertexElementUsage.Position);
if (positionElement.VertexElementFormat != VertexElementFormat.Vector3)
throw new NotSupportedException();
var positions = new Vector3[meshPart.NumVertices];
meshPart.VertexBuffer.GetData(
meshPart.VertexOffset * vertexDeclaration.VertexStride + positionElement.Offset,
positions,
0,
meshPart.NumVertices,
vertexDeclaration.VertexStride);
for (int i = 0; i < positions.Length; i++)
positions[i] = Vector3.Transform(positions[i], transform);
// Get indices.
var indexElementSize = (meshPart.IndexBuffer.IndexElementSize == IndexElementSize.SixteenBits) ? 2 : 4;
if (indexElementSize != 2)
throw new NotSupportedException();
var indices = new short[meshPart.PrimitiveCount * 3];
meshPart.IndexBuffer.GetData(meshPart.StartIndex * 2, indices, 0, meshPart.PrimitiveCount * 3);
// Get the bone indices.
var boneIndexElement = vertexElements.First(e => e.VertexElementUsage == VertexElementUsage.BlendIndices);
if (boneIndexElement.VertexElementFormat != VertexElementFormat.Byte4)
throw new NotSupportedException();
var boneIndicesArray = new Byte4[meshPart.NumVertices];
meshPart.VertexBuffer.GetData(
meshPart.VertexOffset * vertexDeclaration.VertexStride + boneIndexElement.Offset,
boneIndicesArray,
0,
meshPart.NumVertices,
vertexDeclaration.VertexStride);
// Get the bone weights.
var boneWeightElement = vertexElements.First(e => e.VertexElementUsage == VertexElementUsage.BlendWeight);
if (boneWeightElement.VertexElementFormat != VertexElementFormat.Vector4)
throw new NotSupportedException();
var boneWeightsArray = new Vector4[meshPart.NumVertices];
meshPart.VertexBuffer.GetData(
meshPart.VertexOffset * vertexDeclaration.VertexStride + boneWeightElement.Offset,
boneWeightsArray,
0,
meshPart.NumVertices,
vertexDeclaration.VertexStride);
// Now, we have all the info and can sort the vertices into the boneVerticesArray.
for (int i = 0; i < meshPart.NumVertices; i++)
{
Vector3 position = positions[i];
Vector4 boneIndices = boneIndicesArray[i].ToVector4();
Vector4 boneWeights = boneWeightsArray[i];
// A vertex should be in the convex hull of a bone if the bone weight is
// above a threshold.
const float threshold = 0.45f;
if (boneIndices.X >= 0 && boneWeights.X >= threshold)
boneVerticesArray[(int)boneIndices.X].Add((Vector3F)position);
if (boneIndices.Y >= 0 && boneWeights.Y >= threshold)
boneVerticesArray[(int)boneIndices.Y].Add((Vector3F)position);
if (boneIndices.Z >= 0 && boneWeights.Z >= threshold)
boneVerticesArray[(int)boneIndices.Z].Add((Vector3F)position);
if (boneIndices.W >= 0 && boneWeights.W >= threshold)
boneVerticesArray[(int)boneIndices.W].Add((Vector3F)position);
}
}
}
// We have all the vertices for each bone. Compute a convex hull for each bone.
int numberOfLimbs = boneVerticesArray.Count;
_limbs = new LimbGeometricObject[numberOfLimbs];
for (int i = 0; i < numberOfLimbs; i++)
{
var boneVertices = boneVerticesArray[i];
if (boneVertices.Count > 0)
{
// Create a simplified convex hull for the vertices.
DcelMesh convexHullMesh = GeometryHelper.CreateConvexHull(boneVertices, 64, 0);
// We only need the positions of the vertices in the hull.
IEnumerable<Vector3F> points = convexHullMesh.Vertices.Select(v => v.Position);
if (!points.Any())
{
// Convex hull computation failed? Maybe the mesh is degenerated...
// --> Use all vertices of this bone.
points = boneVertices;
}
// The ConvexPolyhedron shape is the fastest for large convex hulls.
ConvexPolyhedron shape = new ConvexPolyhedron(points);
_limbs[i] = new LimbGeometricObject(shape, _modelPose);
var collisionObject = new CollisionObject(_limbs[i])
{
CollisionGroup = 2,
Type = CollisionObjectType.Trigger,
};
_collisionDomain.CollisionObjects.Add(collisionObject);
}
}
}
Instead of the custom "LimbGeometricObject" you will want to create a RigidBody instance for each bone.
The method handles the general case where each mesh includes several bones. It uses the bone weights to decide if a vertex belongs to a certain bone. If the model is already simplified and contains a separate mesh for each bone, this method can be greatly simplified.