I am working on a project which has following goal:
- Load rigged 3D mesh (e.g. a human skeleton) with Assimp.NET
- Manipulate bones of mesh so it fits your own body (with Microsoft Kinect v2)
- Perform vertex skinning
Loading the rigged mesh and extracting bone information works (hopefully) without any problems (based on this tutorial: http://www.richardssoftware.net/2013/10/skinned-models-in-directx-11-with.html). Each bone (class "ModelBone") consists of following information:
Assimp.Matrix4x4 LocalTransform
Assimp.Matrix4x4 GlobalTransform
Assimp.Matrix4x4 Offset
LocalTransform
is directly extracted from assimp node (node.Transform
).
GlobalTransform
includes own LocalTransform
and all parent's LocalTransform
(see code snipped calculateGlobalTransformation()
).
Offset
is directly extracted from assimp bone (bone.OffsetMatrix
).
At the moment I don't have GPU vertex skinning implemented, but I iterate over each vertex and manipulate it's position and normal vector.
foreach (Vertex vertex in this.Vertices)
{
Vector3D newPosition = new Vector3D();
Vector3D newNormal = new Vector3D();
for (int i=0; i < vertex.boneIndices.Length; i++)
{
int boneIndex = vertex.boneIndices[i];
float boneWeight = vertex.boneWeights[i];
ModelBone bone = this.BoneHierarchy.Bones[boneIndex];
Matrix4x4 finalTransform = bone.GlobalTransform * bone.Offset;
// Calculate new vertex position and normal
newPosition += boneWeight * (finalTransform * vertex.originalPosition);
newNormal += boneWeight * (finalTransform * vertex.originalNormal);
}
// Apply new vertex position and normal
vertex.position = newPosition;
vertex.normal = newNormal;
}
Like I already said, I want to manipulate bones with a Kinect v2 sensor, so I won't have to use animations (e.g. interpolating keyframes, ...)! But for the beginning I want to be able to manipulate bones manually (e.g. rotate torso of mesh by 90 degrees). Therefore I create a 4x4 rotation matrix (90 degrees around x-axis) by calling Assimp.Matrix4x4.FromRotationX(1.5708f);
. Then I replace the bone's LocalTransform
with this rotation matrix:
Assimp.Matrix4x4 rotation = Assimp.Matrix4x4.FromRotationX(1.5708f);
bone.LocalTransform = rotation;
UpdateTransformations(bone);
After the bone manipulation I use following code to calculate the new GlobalTransform
of the bone and it's child bones:
public void UpdateTransformations(ModelBone bone)
{
this.calculateGlobalTransformation(bone);
foreach (var child in bone.Children)
{
UpdateTransformations(child);
}
}
private void calculateGlobalTransformation(ModelBone bone)
{
// Global transformation includes own local transformation ...
bone.GlobalTransform = bone.LocalTransform;
ModelBone parent = bone.Parent;
while (parent != null)
{
// ... and all local transformations of the parent bones (recursively)
bone.GlobalTransform = parent.LocalTransform * bone.GlobalTransform;
parent = parent.Parent;
}
}
This approach results in this image. The transformation seems to be applied correctly to all child bones, but the manipulated bone rotates around the world space origin and not around its own local space :( I already tried to include the GlobalTransform
translation (last row of GlobalTransform
) into the rotation matrix before set it as the LocalTransform
, but without success...
I hope somebody can help me with this problem!
Thanks in advance!