Models, meshes, parts, and bones

Models, meshes, parts, and bones

Rate This
  • Comments 5

If you look inside the XNA framework Model class, you will see that it contains a Meshes property holding a collection of ModelMesh instances. If you look inside the ModelMesh class, you will see that each one contains a MeshParts property holding a collection of ModelMeshPart instances. Not to mention the Model.Bones property, which holds a collection of ModelBone instances. What is this all about?

In XNA, a Model can represent any kind of logical entity. It could be a person, or a car, or a level. If you were crazy you could even combine all the meshes for your entire game into a single Model instance! (not that I would recommend that…)

Within a Model, each ModelMesh represents a single physical object. Each ModelMesh can be moved independently, and some can be drawn while others are skipped. For instance a Model of a car would probably contain one ModelMesh for the body of the vehicle, four for the wheels, and a couple for the doors (assuming we are building a sexy sports coupe…)

Within a ModelMesh, each ModelMeshPart represents a single graphics card draw call. It contains a set of triangles that share the same material (stored in the ModelMeshPart.Effect property) and vertex declaration. For instance the ModelMesh for the body of our car might contain one ModelMeshPart for the painted car surface, one using an environment mapping effect for the reflective windscreen, and another using a normalmap texture for the snakeskin leather seats (I hasten to assure concerned readers that no snakes were harmed during the production of this blog post…)

The ModelBone objects describe how the ModelMesh instances are positioned. Each mesh has a ParentBone property, in which you can find a transform matrix describing where that ModelMesh is located relative to the Parent of the ParentBone. This allows you to build up hierarchies of jointed objects (wheel bone and door bone to car body bone, spinning windmill blades to windmill tower, thigh bone to knee bone…)

Putting this all together, we can draw some hopefully useful conclusions:
  • The Draw method belongs to the ModelMesh, rather than to the root Model, because we might want to draw each ModelMesh at a different position (making the car wheels spin) , or we might want to only draw some subset of the ModelMesh entries.
  • If our Model contains multiple meshes with different positions, we will need to look up the bone data to know where to render them.
  • You don't normally need to worry about the ModelMeshPart class, since this is used to hold data that only matters to the graphics card and does not affect the logical view of your model.
  • The new Beck album is really cool.

At this point the astute reader may be wondering what the ModelMesh.Effects property is all about. You thought I'd forgotten to explain that, didn't you? Not in the least…

The actual effect instances used to render your model are stored in the Effect property of the ModelMeshPart class. This is inevitable, really, since each ModelMeshPart can potentially have a different effect. If you want to change the effect used to render your model, you will need loop over each ModelMeshPart and assign a new value to their Effect property.

The ModelMesh.Effects property is just a shortcut that gives you a combined list of all the effects used on all the parts of the mesh. This allows you to draw an entire mesh using this code:

    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];
            effect.View = viewMatrix;
            effect.Projection = projectionMatrix;
        }

        mesh.Draw();
    }

This is really just a shortcut for:

    Matrix[] transforms = new Matrix[model.Bones.Count];

    Model.CopyAbsoluteBoneTransformsTo(transforms);

    foreach (ModelMesh mesh in model.Meshes)
    {
        foreach (ModelMeshPart part in mesh.MeshParts)
        {
            if (part.Effect == null)
                throw new IneffectiveException("Huh?");

            BasicEffect effect = (BasicEffect)part.Effect;

            effect.World = transforms[mesh.ParentBone.Index];
            effect.View = viewMatrix;
            effect.Projection = projectionMatrix;
        }

        mesh.Draw();
    }

But the first version is better because:

  • It is slightly less code to type.
  • It is optimized to avoid redundant setup work if more than one ModelMeshPart shares the same effect.

  • PingBack from http://www.xnatutorial.com/?p=45

  • That's very good for beginners, like me. Thanks again.

  • This saved me many hours of hunting and head-scratching.  Microsoft should have this explanation someplace conspicuous in their documentation.  But, of course, they don't.

    Thanks a million!

  • I love you!

  • Hello Shawn

    How does XNA set the bone order when it imports a FBX model?

    I would love to draw a bone after another, since one of the bones uses alpha transparent textures and I would like to draw these last.

Page 1 of 1 (5 items)
Leave a Comment
  • Please add 7 and 4 and type the answer here:
  • Post