Shawn Hargreaves Blog
One of the more confusing things for newcomers to the XNA Framework Content Pipeline is figuring out how (and why) to split your code across multiple assemblies.
First off, let's examine the flow of data through the pipeline:
My choice of colors is not random. In fact, knowing why I colored some boxes blue but others red is probably the most important part of understanding the Content Pipeline!
This core difference implies other important distinctions:
You don't always have to implement all the boxes. For instance it is common to write a custom content processor, but use one of the built-in importers. It is also common for all three objects A, B, and C to be of the same type. Let's look at some examples...
The simplest scenario is writing a custom content processor to modify an existing data type. A good example is the NormalMapProcessor from the Sprite Effects sample:
Note how the sample includes two projects: SpriteEffectsWindows contains the main game code, while SpriteEffectsPipeline contains the custom processor code.
If you open the Xbox version of the solution, you will see that even though the SpriteEffectsXbox game project targets the Xbox 360 platform, SpriteEffectsPipeline still targets Windows (x86).
A more interesting scenario occurs if we want to add a new data type. The Custom Model Class sample is a good example of this:
Again the solution contains two projects, and again the pipeline extension project is always built for Windows, even when the game is targeting Xbox. The important thing is which types are defined in which projects:
It often turns out that Object B and Object C from my diagram are actually the same type.
Where should we define such a shared type?
We can't put it in the pipeline extension project, because we don't ship that project along with the final game. We also can't put it in the game project, because that would create a circular dependency: we need to use Object B to build content for the game, but if Object B is defined as part of that game, it wouldn't exist before the game was built. We can't use the game to build itself!
Types that are used both during the content build and inside the game itself are no longer purely blue or red. They introduce a third category: let's call it purple. We need a new assembly to contain such things.
You can find an example of this in the Skinned Model sample:
The interesting thing here is which assemblies define each type:
Note how both SkinningModelPipeline and SkinningSampleWindows have references to the shared SkinnedModelWindows project. This allows them both to access the same SkinningData type, so it can be used for both Object B and Object C as data flows through the pipeline.
But what about Xbox? If our game is for Xbox, we can no longer share a single project between the pipeline extension project (which runs on Windows) and the game (which runs on Xbox).
The answer can be found in SkinningSampleXbox.sln. This contains not three, but four separate projects. But two of these are actually the same thing, building the same source code for different platforms. Thus we have both SkinnedModelWindows, which defines the shared type for the Windows platform so it can be referenced by the SkinnedModelPipeline, and also SkinnedModelXbox, which includes the same .cs files and defines the same shared type, but this time for the Xbox platform so it can be referenced by the SkinningSampleXbox game project.
In other words:
Just out of curiosity why did you (read XNA team,i realize I am just asking for an unofficial answer) choose fbx and not collada format?Is it because of commercial reasons or partnership?Or maybe because collada isn't really mature yet?
We didn't exactly "not" choose Collada format: we understood that there are many interesting formats out there (imagine how cool it would be if you could import directly from .max or .mb files, for instance!) so it was important to design a system that could support many different formats. This is the main reason for the separate importer stage, as this lets people develop importers for many different file formats, but have them all use the same standard object model and processors.
When it came to which importers we wrote ourselves to ship built in to the product, time was very limited, so we just had to pick whichever we thought would give us the biggest bang for our limited buck.
Shawn, is there any other solution to the shared data type problem other than creating duplicate projects? What conflict prevents one from creating a single Xbox project that is also imported into the Windows pipeline extension project?
> What conflict prevents one from creating a single Xbox project that is also imported into the Windows pipeline extension project?
You cannot load and use an Xbox project on Windows (or vice versa). Projects are specific to a platform, and can only be used on the platform they were built for.
Fortunately, creating duplicate projects is trivially easy once you realize that you have to do this, thanks to the cross platform project management features in Game Studio.
Just wanted to say that this diagram and your bullet points have made this entire framework make sense INSTANTLY. You should convince the team to include that image in every new XNA project that Visual Studio builds so everyone can see it right away.
A little more than a year later, and this is still very useful. Thanks for the info Shawn.
I've downloaded the sample 3.1 http://creators.xna.com/en-US/sample/custommodelclass and have added it into my Windows Game Solution.
The default tank.fbx file shows the custom content processor, but if I import other .fbx files into this project, go to Properties, and look at the options in the dropdown for "Content Processor", I don't see "CustomModelProcessor".
Is there some other reason why I cannot see that custom content processor in this solution? I'm completely confused as to why "tank.fbx" shows it, but other imported model files only show the default content processors.
This means your content project is not correctly referencing the content pipeline extension DLL.
Most likely you either forgot to add a reference from your Content\References folder (not the main game references!) to the pipeline extension project.
Or perhaps the pipeline extension project is using a different version of Game Studio to your game?
Just wanted to tell you what a fantastic resource this page is! I've been struggling to understand the Content Pipeline but this page has helped a lot.
Thank you for this great article! It opened my eyes for the solution for my problem!
I thought Object B and C have to be the same...
I'd like to build an XNA app that will allow a user to create a sprite using themselves, but this seems to say I can't do it! Especially with Natal, I would think that personalization would be a high priority!
Does this still work with XNA 4 especially as there is now a separate 'Content Reference'. I for one cannot get it to work, I have a shared game library with 'object C' in and it's ContentReader, and this is referenced by my Content Pipeline project and the Game project, compilation of the Game project fails with "There was an error while deserializing intermediate XML. Cannot find type "GameShared.Level", I tried adding the reference for GameShared to the Content project but things just got a whole lot worse and gave me this error instead.. "Error loading pipeline assembly "BioLabShared, Version=188.8.131.52, Culture=neutral, PublicKeyToken=null"
Marveh: none of this stuff changed in Game Studio 4. I would recommend the creators.xna.com forums to get help with your problem - blog comments aren't really the best place for doing tech support!
Thanks, incase anyone else has this issue, i did find this VERY useful snippet on the creators.xna.com forums
"When adding references to a content project, you must always reference a Windows project. If you need to reference a custom class that you defined in a Windows Phone Game Library project, then right-click that project and select "Create Copy of Project for Windows". This will create a clone of the first project (that shares the same source files), but which builds the assembly for Windows. Add the reference from the content project to the Windows Copy of your game library. The content pipeline needs this because the content pipeline always executes on your local Windows machine. When you mix-and-match, you can run into a variety of problems."