Mesh's Matrix

posted in Lyost's Journal
Published October 22, 2011
Advertisement
[heading]Model Processing[/heading]
While working on a model processor to determine the bounds of a model, I noticed something odd. The min/max were not what I expected and the total width did not match the model. The code is simple and taken from one of my tester programs were it worked correctly, so I was wondering why this model was an issue.

private void GetAllVertices(NodeContent input,LinkedList verts,
ref BoundingBox box)
{
MeshContent mesh = input as MeshContent;
if (mesh != null)
{
// load the positions from the mesh node
foreach (Vector3 pos in mesh.Positions)
{
// store the vertex
verts.AddLast(pos);

// update the bounding box
if (pos.X < box.Min.X)
{
box.Min.X = pos.X;
}
if (pos.X > box.Max.X)
{
box.Max.X = pos.X;
}
if (pos.Y < box.Min.Y)
{
box.Min.Y = pos.Y;
}
if (pos.Y > box.Max.Y)
{
box.Max.Y = pos.Y;
}
if (pos.Z < box.Min.Z)
{
box.Min.Z = pos.Z;
}
if (pos.Z > box.Max.Z)
{
box.Max.Z = pos.Z;
}
}
}
else
{
// recurse on the children of a non-mesh node
foreach (NodeContent child in input.Children)
{
GetAllVertices(child,verts,ref box);
}
}
}

This function is called from the model processor's Process method with box initialized so that its min values are float.MaxValue and its max values are float.MinValue. The part of storing the vertices in a linked list was for other functionality in this particular model processor (building a heightmap from the mesh).

Since this code works elsewhere, I inspected the fbx file. The fbx files I use are generated from the fbx exporter that comes with Blender 2.56.5, which generates text based fbx files; Autodesk's site says fbx files can also be binary. I noticed that the matrix in the PoseNode for the model was not the identity matrix, whereas in the models that work it is. Later exploration of the fbx files also showed that the Model node for the mesh has a "Lcl Rotation" property whose rotation in degrees matches the matrix.

The model showing the issue is the result of manipulating a Blender grid object. These objects are in the xy plane when created. Since I was creating terrain for a game where terrain is in the xz plane and y is the height, I rotated the object by -90 degrees around the x-axis, where the minus sign is to get the normal facing the right direction of +y. This is what created the issue. Setting rotation or scale in object mode does not edit the vertices of the mesh, instead it manipulates the object's world matrix. Since the model I was dealing with was a single mesh, the solution was simple, set the object rotation to 0 and in edit mode rotate by -90 around the x-axis. By applying the rotation in edit mode, the vertices' coordinates were actually changed by the rotation. To help avoid this problem with future models, I've updated the "Modeling Requirements" section of my design doc to specify that objects must have a rotation of 0 around each axis and a scale of 1.

[heading]How This Matters to Drawing[/heading]
Going through the process in the previous section helped me understand the details of a different section of code. When drawing a simple model in XNA, the code is typically along the lines of:

Matrix[] transforms = new Matrix[model.Bones.Count];
model.CopyAbsoluteBoneTransformsTo(transforms);
foreach (ModelMesh mesh in model.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.World = transforms[mesh.ParentBone.Index] * World;
effect.View = cam.View;
effect.Projection = cam.Projection;
}

mesh.Draw();
}

With World being a Matrix defined by the game. Why do "transforms[mesh.ParentBone.Index] * World" instead of just World? Both MSDN and "Learning XNA 4.0" by Aaron Reed don't go into detail of why it is necessary. MSDN keeps referring to bones in its brief explanation, but doesn't mention that even models without a skeleton still have 1 bone in XNA (discussed in the next paragraph). "Learning XNA 4.0" by Aaron Reed says it's to handle models that are comprised of multiple meshes. However, this code matters for single mesh models that are not attached to a skeleton, such as my terrain model in the previous section.

All meshes in a model have a world space matrix attached to them. This matrix allows rotation and scaling of the mesh to be applied to the vertices that it is comprised of. XNA loads this matrix as if it were a bone and sets it as the parent bone of the mesh. If you skip applying this matrix, then your rendering of the model may not match what is shown in the software used to create the model.
0 likes 2 comments

Comments

JTippetts
In Blender you can hit the shortcut Ctrl-a then select Apply Rotation to apply the current object rotation to the vertices of the mesh. There are also entries to apply translation and scale as well. If you do this before exporting, you should get the expected result, without having to go into edit mode to perform the transformations.
October 22, 2011 10:05 PM
Lyost
[quote name='JTippetts' timestamp='1319321100']
In Blender you can hit the shortcut Ctrl-a then select Apply Rotation to apply the current object rotation to the vertices of the mesh. There are also entries to apply translation and scale as well. If you do this before exporting, you should get the expected result, without having to go into edit mode to perform the transformations.
[/quote]


Thanks! That wasn't on the cheat sheet of commands that I got from http://gryllus.net/Blender/3D.html I'll add it to my copy.
October 23, 2011 02:29 PM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement