Export (0) Print
Expand All

Extending a Standard Content Processor

Describes how XNA Game Studio lets you modify or extend the behavior of any standard Content Pipeline processor that ships with the product. See Standard Importers and Processors for a description of standard processors.

Because there are so many asset variants supported by different digital content creation (DCC) tools, it is often useful to be able to modify how one of the standard processors operates. The following examples illustrate some of the kinds of things you might want to do.

Bb447748.note(en-us,XNAGameStudio.41).gifNote
The following code samples are provided only for demonstration. Most of the functionality described is already available by using parameters on a standard processor.

Adding a Scaling Operation to a Processor

There are many reasons why you might want to modify the existing functionality of a standard processor. Here is one example. If your source assets and your game are at different scales, you may want the processor to scale each model automatically at build time. You can implement such automatic scaling by overriding the Process method of the ModelProcessor class, which generates a Model. In the override, you first scale the entire scene, and then invoke the base class functionality to process as usual.

The following code illustrates this technique:

[ContentProcessor]
class ScalingModelProcessor : ModelProcessor
{
    public override ModelContent Process(
        NodeContent input, ContentProcessorContext context )
    {
        MeshHelper.TransformScene( input, Matrix.CreateScale( 10.0f ) );
        return base.Process( input, context );
    }
}
    

Generating Additional Data

In some cases, you may want to add information to a game asset that a standard processor would not. For example, if a custom effect you want to apply requires tangent or binormal data, you can extend the standard model processor to build this additional data into the asset. To do this, you override the Process method of the ModelProcessor class. In the override, navigate the NodeContent hierarchy of the game asset, and call CalculateTangentFrames for each MeshContent object you find.

The following code shows how to do this:

[ContentProcessor]
class ModelProcessorWithTangents : ModelProcessor
{
    public override ModelContent Process( NodeContent input, ContentProcessorContext context )
    {
        GenerateTangentFramesRecursive( input );
        return base.Process( input, context );
    }

    private void GenerateTangentFramesRecursive( NodeContent node )
    {
        MeshContent mesh = node as MeshContent;
        if (mesh != null)
        {
            MeshHelper.CalculateTangentFrames( mesh, VertexChannelNames.TextureCoordinate( 0 ), 
                VertexChannelNames.Tangent( 0 ), VertexChannelNames.Binormal( 0 ) );
        }

        foreach (NodeContent child in node.Children)
        {
            GenerateTangentFramesRecursive( child );
        }
    }
}

Changing the Processors Called for Child Objects

Another useful technique is to override a standard processor, and to change how child objects are processed just by changing the processors they use.

Consider, for example, the hierarchy of calls through which textures in a model are processed:

One reason you may want to change how this works is that the ModelTextureProcessor.Process method applies DXT1 or DXT5 compression to all textures it processes. If textures in your game assets are compressed already, you may want to avoid a second compression.

To prevent compression of textures during processing

Here is how to prevent compression from being applied to model textures during processing.

  1. Create an override of the standard MaterialProcessor.BuildTexture method, and invoke the TextureProcessor.Process method, which does no compression, instead of ModelTextureProcessor.Process.
  2. Create an override of ModelProcessor.ConvertMaterial that invokes your override of MaterialProcessor.BuildTexture instead of the standard one.

The first of these overrides could be coded as:

[ContentProcessor]
class NoCompressionMaterialProcessor : MaterialProcessor
{
    protected override ExternalReference<TextureContent> BuildTexture( 
        string textureName, ExternalReference<TextureContent> texture, ContentProcessorContext context )
    {
        return context.BuildAsset<TextureContent, TextureContent>( texture, "TextureProcessor" );
    }
}

There are several things to note about this code.

  • An ExternalReference is an asset object that is shared between multiple classes, such as a diffuse texture used by more than one material. When such an asset is specified, the Content Manager loads only one copy of the ExternalReference at run time and builds it only once, no matter how many references there are to it.
  • The ContentProcessorContext BuildAsset method lets you invoke a processor by name to build the content in an object.
  • Although textureName, the first argument to BuildTexture, is ignored in the override above, you could use it if you wanted to process textures differently depending on normal maps or other criteria.

Given the processor created by your first override above, you could code the second override:

[ContentProcessor]
class NoCompressionModelProcessor : ModelProcessor
{
    protected override MaterialContent ConvertMaterial(
        MaterialContent material, ContentProcessorContext context )
    {
        return context.Convert<MaterialContent, MaterialContent>(
            material, "NoCompressionMaterialProcessor" );
    }
}

Because this override is processing MaterialContent objects in memory rather than ExternalReference objects, it uses the ContentProcessorContext.Convert function instead of BuildAsset to invoke the processor created by your first override.

After building and installing your new NoCompressionModelProcessor (see Adding a Custom Importer), you can assign it to any models whose textures are already compressed and no further compression is applied.

Community Additions

ADD
Show:
© 2014 Microsoft