Customizing how models build their textures

Customizing how models build their textures

  • Comments 1

When the content pipeline builds a model, by default it will use the ModelTextureProcessor to convert all the textures used on that model.

 

There are many reasons why you might want to override this behavior:

  • You might want to change the output texture format
  • You might want missing texture files to be silently ignored, rather than causing build errors
  • You might want to automatically fix invalid size textures, scaling them so the output will always be a power of two
  • You might want to disable or tweak the default magenta color keying behavior
  • You might want to apply special processing to specific textures, for instance converting grayscale height maps into normalmap format, or sphere maps into cubemap textures

All of these customizations are pretty easy once you understand the basic approach. I'll give an example of how to automatically correct non-power-of-two texture sizes.

 

First, we need to make a custom processor that will convert textures in the way we want. There is quite a lot of code here, but it should all be fairly self explanatory. Note how it logs a warning if the input texture size was invalid, so you can tell which textures are being automatically resized:

    [ContentProcessor]
class MyTextureProcessor : ContentProcessor<TextureContent, TextureContent>
{
public override TextureContent Process(TextureContent input,
ContentProcessorContext context)
{
// Convert the input to standard Color format, for ease of processing.
input.ConvertBitmapType(typeof(PixelBitmapContent<Color>));

foreach (MipmapChain imageFace in input.Faces)
{
for (int i = 0; i < imageFace.Count; i++)
{
PixelBitmapContent<Color> mip = (PixelBitmapContent<Color>)imageFace[i];

// Apply color keying.
mip.ReplaceColor(Color.Magenta, Color.TransparentBlack);

// Make sure the image is a power of two in size.
int width = MakePowerOfTwo(mip.Width);
int height = MakePowerOfTwo(mip.Height);

if ((width != mip.Width) || (height != mip.Height))
{
context.Logger.LogWarning(null, input.Identity,
"Bitmap was not a power of two. Scaled from {0}x{1} to {2}x{3}.",
mip.Width, mip.Height, width, height);

PixelBitmapContent<Color> scaledMip;
scaledMip = new PixelBitmapContent<Color>(width, height);

BitmapContent.Copy(mip, scaledMip);

imageFace[i] = scaledMip;
}
}
}

input.GenerateMipmaps(false);

// Compress the output texture.
input.ConvertBitmapType(typeof(Dxt1BitmapContent));

return input;
}


static int MakePowerOfTwo(int value)
{
int bit = 1;

while (bit < value)
bit *= 2;

return bit;
}
}

Second, we need to make a custom material processor that will call into our custom texture processor. This one is very simple, but for more complex scenarios you could examine the textureName parameter and use it to decide which texture processor should be invoked:

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

The final step is a custom model processor that will call into our custom material processor. Specify this processor for your model, and it will no longer be a problem if that model references textures of invalid sizes:

    [ContentProcessor]
class MyModelProcessor : ModelProcessor
{
protected override MaterialContent ConvertMaterial(MaterialContent material,
ContentProcessorContext context)
{
return context.Convert<MaterialContent,
MaterialContent>(material, "MyMaterialProcessor");
}
}
  • Thanks alot, but I don't know where to place your code. And how to use it in my project.

    Please help me, thanks

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