Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I know that a texture's name is not preserved when it's loaded in. I also know that you can give it a name. For example:

Texture2D texture = content.Load<Texture2D>("MyTexture");
texture.Name = "MyTexture"; //Or whatever else you want to call it

However, what about when you load a model? It automatically loads in the right texture for each ModelMeshPart, and drops the Name (no idea why though). This is fine, right up until the point where you actually want to identify which texture that ModelMeshPart is using. I found someone else having the same problem here. Shawn Hargreaves gave this solution:

If you need access to this data at runtime, you will need to extend the pipeline to store it somewhere else. For instance you could use a custom processor to store texture filenames in the ModelMeshPart.Tag property

I figured that was easy enough. Yeah...feel free to point and laugh. I got as far as creating a custom proccessor class and inheriting the standard ModelProcessor before I realised that I didn't know exactly where the ModelMeshPart's texture was stored and I've spent the past few days trying to find out.

I just want to preserve each part's texture name so that I can do something like

Model model = content.Load<Model>("MyModel");
BasicEffect effect = (BasicEffect)model.Meshes[0].MeshParts[0].Effect;
string texName = effect.Texture.Name;

Also Merry Christmas.

EDIT

For the record, I'm importing a .x model.

share|improve this question
add comment

1 Answer 1

up vote 3 down vote accepted

The best approach in my opinion is to store all texture references in the ModelMeshPart.Tag property like Shawn Hargreaves suggested. If you do it this way, you can decide which texture names you need in your game.

In order to achieve this, you need a custom model processor. The filename for each texture referenced in the MeshPart is stored in MeshPart.Material.Textures. So a simple approach to just save all texture filenames for later use would look like this:

using System.Collections.Generic;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline.Processors;

namespace ModelTextureNameExtension
{
    [ContentProcessor(DisplayName = "Model with texture names")]
    public class ModelTextureNameProcessor : ModelProcessor
    {
        public override ModelContent Process(NodeContent input, ContentProcessorContext context)
        {
            ModelContent modelContent = base.Process(input, context);

            StoreTextureFilenameInTag(modelContent);

            return modelContent;
        }

        private void StoreTextureFilenameInTag(ModelContent modelContent)
        {
            Dictionary<string, string> textureDictionary = new Dictionary<string, string>();

            foreach (var mesh in modelContent.Meshes)
            {
                foreach (var meshPart in mesh.MeshParts)
                {
                    foreach (var textureEntry in meshPart.Material.Textures)
                    {
                        textureDictionary.Add(textureEntry.Key, textureEntry.Value.Filename);
                    }

                    meshPart.Tag = textureDictionary;
                }
            }
        }
    }
}

When you import a model with this processor, you can access the extracted data in your game like this:

Model model = Content.Load<Model>("Models/MyModel");

foreach (var mesh in model.Meshes)
{
    foreach (var meshPart in mesh.MeshParts)
    {
        Dictionary<string, string> textureDictionary = meshPart.Tag as Dictionary<string, string>;

        // Use the filename of the texture you need
    }
}

Please note that the number of referenced textures strongly depends on the model you import. You can adjust the content processor to your needs if you know which texture you exactly need.

textureEntry.Value.Name is always (at least when I tried to use it) null, so you need to fetch the texture name from the file name. You could also use the name of the material in the mode file which is stored in MeshPart.Material.Name.

share|improve this answer
    
I used textureEntry.Value.Name in the processor, as I'm looking for the texture's name, not it's filename. However all of those values are null, meaning that when base.Process(input, context) is called, it must lop off the Names there. I think this means that the names will somehow need to be retrieved and stored before base.Process is called. I suppose the preserving of the filename means I can edit that string to get what I want, but I'd still like to know if I can get at texture names. –  MetaReference Dec 26 '12 at 5:02
    
@MetaReference: Seems like there is no easy way to retrieve the texture name directly from the content processor other than parsing the filename. I've edited my answer, so maybe the material name is enough for your purpose. –  mpistrich Dec 26 '12 at 11:29
    
Tried the material name and that's null as well. I'll tick this as answered if I don't get a better answer by New Years Day. –  MetaReference Dec 26 '12 at 14:06
    
Seems like the information of the texture and material name is not available in your model file because when I tried it, the material name was not null (I was using a simple .fbx model). Maybe you can try to somehow add the material name when exporting the model so XNA can access it when importing the content. –  mpistrich Dec 26 '12 at 14:55
    
I'm using a .x model but if you're using a .fbx model, then that makes me suspect that it might be the importer, not the processor (as Hargreaves suggested) that's leaving the name out. I edited my OP to clarify the file type. –  MetaReference Dec 26 '12 at 16:54
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.