Loading Models in XNA with the Content Pipeline

The last time I played with XNA was when it was in in beta. There was no "Content Pipeline", and loading models was so tedious, I just decided to stop using XNA until it RTM'd. Since now is that time, I thought I'd best see how things have changed...

I bought the GarageGames Orcs RTS Buildings Pack, since it looked fitting for an MMO, was pretty cheap and had .x versions already included (which I know the Content Pipeline should handle).

I fired up GSE and added the .X files to my project and clicked Build....

I was greeted to some compile errors - and I hadn't even started coding!!

Thankfully, these errors were trivial. The content pack included .x and .jpg files with the same name (orcs1.jpg and orcs1.x). The content pipeline likes to strip the extensions off for the asset names, so there was a clash. I ran through and added ".jpg" to the asset name of each jpeg (though now I'm typing, I'm thinking I could've just Excluded them from the project, since the reference in the .x file would cause them to be added!).

With them all building, it was time to see if I could add them to my world. I was starting with the ChaseCamera sample from creators.xna.com, since I knew I'd be able to move the camera around easily to see the models.

At the top of Game.cs, I added a new variable to hold my models:

List<Model> buildingModels = new List<Model>();

And in the LoadGraphicsContent() method, I loaded each model. Since the filenames weren't sequential, I just hard-coded them for now:

buildingModels.Add(content.Load<Model>("Content/OrcPack/snow/orcs1"));
buildingModels.Add(content.Load<Model>("Content/OrcPack/snow/orcs11"));
buildingModels.Add(content.Load<Model>("Content/OrcPack/snow/orcs12"));
buildingModels.Add(content.Load<Model>("Content/OrcPack/snow/orcs13"));
buildingModels.Add(content.Load<Model>("Content/OrcPack/snow/orcs14"));
buildingModels.Add(content.Load<Model>("Content/OrcPack/snow/orcs15"));
buildingModels.Add(content.Load<Model>("Content/OrcPack/snow/orcs2"));
buildingModels.Add(content.Load<Model>("Content/OrcPack/snow/orcs3"));
buildingModels.Add(content.Load<Model>("Content/OrcPack/snow/orcs4"));
buildingModels.Add(content.Load<Model>("Content/OrcPack/snow/orcs5"));

And in my Draw() method, I called the existing DrawModel() method (which came from the ChaseCamera sample, to draw the ship/ground). Since the models are in a much smaller scale than the ship, I had to scale them up. Really this should be done per-asset at compile time - I'll see about creating a custom importer for this later (since all content packs will likely have different settings, and I want my units to be metres).

DrawModel(buildingModels[0], Matrix.Identity * Matrix.CreateTranslation(new Vector3(0, 0, 0)) * Matrix.CreateScale(100));
DrawModel(buildingModels[1], Matrix.Identity * Matrix.CreateTranslation(new Vector3(300, 0, 0)) * Matrix.CreateScale(100));
DrawModel(buildingModels[2], Matrix.Identity * Matrix.CreateTranslation(new Vector3(600, 0, 0)) * Matrix.CreateScale(100));
DrawModel(buildingModels[3], Matrix.Identity * Matrix.CreateTranslation(new Vector3(600, 0, -300)) * Matrix.CreateScale(100));
DrawModel(buildingModels[4], Matrix.Identity * Matrix.CreateTranslation(new Vector3(600, 0, -600)) * Matrix.CreateScale(100));
DrawModel(buildingModels[5], Matrix.Identity * Matrix.CreateTranslation(new Vector3(300, 0, -600)) * Matrix.CreateScale(100));
DrawModel(buildingModels[6], Matrix.Identity * Matrix.CreateTranslation(new Vector3(0, 0, -600)) * Matrix.CreateScale(100));
DrawModel(buildingModels[7], Matrix.Identity * Matrix.CreateTranslation(new Vector3(0, 0, -300)) * Matrix.CreateScale(100));
DrawModel(buildingModels[8], Matrix.Identity * Matrix.CreateTranslation(new Vector3(200, 0, -200)) * Matrix.CreateScale(100));
DrawModel(buildingModels[9], Matrix.Identity * Matrix.CreateTranslation(new Vector3(400, 0, -400)) * Matrix.CreateScale(100));

I also made a slight change to the ground.x model to reference the snowy ground.jpg from the content pack. I ran the project again, and there are the models!

So, in conclusion, the Content Pipeline makes loading models trivial. The next few things to look at are heightmaps, loading models in from some sort of "level file" rather than hard-coding, and animated models that react to user input (eg. breathing/running animations).

If you found this article interesting, why not Subscribe to my RSS feed or follow @DanTup on Twitter for more? :)