MaterialMap change (FIX?)
by Ross Pawley · in Torque 3D Professional · 09/15/2010 (12:26 am) · 21 replies
So a while ago Jon from BrokeAss Games came to me and asked to see if I could investigate a problem he has had for a while. The case is when you have a DTS with a particular mapTo (the same as the texture name, in this instance) but you want to be able to reuse it by loading a different material on it.
So for example, you have shape.dts with a mapTO of "shapeMat" and your texture is called shapeMat.png. If you copy shapeMat.png to a new folder and make a new material with a different name, but the same mapTo of "shapeMat", the engine will load it all up fine but when it goes to map the material it will basically just end up grabbing the first material texture out instead. The behavior is such that if you try this, and apply the two separate materials to two instances of your shape, they'll both show up with the first material.
You *could* just re-export with a different mapTo field but that seems like a lame solution, and then you've got a bunch of duplicate binary data laying around. Seems like it's just a very poor design going on here if you can't ever apply more than one material to a given shape.
Instead my solution was to change the way that it uses the MaterialMap in MaterialManager to map from a texture name (the mapTo) to a material name, to instead map from a material name to a texture name. That way, in my above example, both shapes would end up showing their separate materials properly.
From this:
to this
I tested the above change out with the example scenario above using the SwarmGun (just went and made a copy of the SwarmGun materials.cs and the texture it uses, stuck em in a different folder and altered the texture a bit) and it seems to work, and nothing else broke from the change. I guess I am just wondering if this is a good change, whether its as obviously weird as it is as it seems or not.
So for example, you have shape.dts with a mapTO of "shapeMat" and your texture is called shapeMat.png. If you copy shapeMat.png to a new folder and make a new material with a different name, but the same mapTo of "shapeMat", the engine will load it all up fine but when it goes to map the material it will basically just end up grabbing the first material texture out instead. The behavior is such that if you try this, and apply the two separate materials to two instances of your shape, they'll both show up with the first material.
You *could* just re-export with a different mapTo field but that seems like a lame solution, and then you've got a bunch of duplicate binary data laying around. Seems like it's just a very poor design going on here if you can't ever apply more than one material to a given shape.
Instead my solution was to change the way that it uses the MaterialMap in MaterialManager to map from a texture name (the mapTo) to a material name, to instead map from a material name to a texture name. That way, in my above example, both shapes would end up showing their separate materials properly.
From this:
void MaterialManager::mapMaterial(const String & textureName, const String & materialName)
{
if (getMapEntry(textureName).isNotEmpty())
{
if (!textureName.equal("unmapped_mat", String::NoCase))
Con::warnf(ConsoleLogEntry::General, "Warning, overwriting material for: %s", textureName.c_str());
}
mMaterialMap[String::ToLower(textureName)] = materialName;
}to this
void MaterialManager::mapMaterial(const String & textureName, const String & materialName)
{
if (getMapEntry(materialName).isNotEmpty())
{
if (!textureName.equal("unmapped_mat", String::NoCase))
Con::warnf(ConsoleLogEntry::General, "Warning, overwriting material for: %s", textureName.c_str());
}
mMaterialMap[String::ToLower(materialName)] = textureName;
}I tested the above change out with the example scenario above using the SwarmGun (just went and made a copy of the SwarmGun materials.cs and the texture it uses, stuck em in a different folder and altered the texture a bit) and it seems to work, and nothing else broke from the change. I guess I am just wondering if this is a good change, whether its as obviously weird as it is as it seems or not.
About the author
Recent Threads
#2
This hasn't been extensively tested or anything, though, so be aware of that. That said as far as I could see with a simple load of a couple of levels it didn't cause any problems, and had the behavior I expected.
09/27/2010 (8:45 pm)
Nope, I posted it shortly before beta 3 came out, and no one has replied with discussion about this change/possible fix. It's easy enough to change in your own build though. Just replace the mapMaterial function with the one I provided there and recompile.This hasn't been extensively tested or anything, though, so be aware of that. That said as far as I could see with a simple load of a couple of levels it didn't cause any problems, and had the behavior I expected.
#3
09/28/2010 (6:33 pm)
Hmm... this actually seems like a very good thing to have implemented. Not rigorously tested but such a feature could fulfill my expectations of dynamic materials.
#4
@Michael, can you elaborate on what you mean by dynamic materials? I'm just curious.
09/28/2010 (8:39 pm)
It makes a lot of sense when you think about it. Mapping from a material name to a texture name just seems logically the much more flexible way to go. Though there might be unforeseen consequences, which is why I decided to post my change for discussion rather than as a full on FIX post.@Michael, can you elaborate on what you mean by dynamic materials? I'm just curious.
#5
09/28/2010 (9:13 pm)
Ah, just simply changing materials on the fly depending on certain in-game circumstances... little small texture changes like team insignias and such -- I'm probably a little to liberal with my usage of the term dynamic though ;)
#6
09/29/2010 (8:14 pm)
Ah right, that's what I thought you meant. I suppose this change would help facilitate material swapping to some degree.
#7
09/30/2010 (8:54 pm)
Michael, have you tried out this change at all? I'm very curious to hear how it works out from other people trying it. I'd like to integrate it into my build but I want to make sure I'm not crazy thinking it doesn't break anything.
#8
The code is still in use and hasn't seemed to have affected anything else, so that's a good sign. I have been meaning to try it out a bit more rigorously though -- hoping to actually have some "free time" this weekend :)
09/30/2010 (9:54 pm)
I've only tried out a few cases much like the example you described. The code is still in use and hasn't seemed to have affected anything else, so that's a good sign. I have been meaning to try it out a bit more rigorously though -- hoping to actually have some "free time" this weekend :)
#9
09/30/2010 (9:56 pm)
Awesome. It's good to know that it doesn't obviously break anything in simple tests. Just out of curiosity, how complex were the level(s) you loaded with the change in? I only ever tested it on the blank level, so there were only 5-6 materials in use.
#10
09/30/2010 (10:05 pm)
My regular testing level is one with a groundplane, 5-6 objects (static shapes, items, rigidshapes) and some stupid AI. So around a dozen materials in total, and two test cases that I used: one of a weapon and another of a crate. I'm wanting to say that I tried this out in the updated Deathball desert also but honestly can't remember if I did or not.
#11
Thanks for helping with the testing!
09/30/2010 (10:10 pm)
Good to know! Let me know if there's any issues with it and/or if you gather any more useful data about it. I think I'll go ahead and use it in my main build for a while to test it out a bit better.Thanks for helping with the testing!
#12
So I'm not sure whether I see this as it is (4:26 am, very short on sleep) but I think that what this does is it creates new materials every time.
10/05/2010 (2:32 am)
I've looked into what it might affect. Due to this change and without changing getMapEntry (definition and/or calls to it) the change can actually cause new materials to be added by the material manager (since a given material will not be found when searched for by the texture name as a key in mMaterialMap).So I'm not sure whether I see this as it is (4:26 am, very short on sleep) but I think that what this does is it creates new materials every time.
#13
10/06/2010 (1:38 am)
Konrad, I took a look at the places that call getMapEntry either directly or through script, and it seems like they all use the material name (at least, from a quick glance). I'll have to do some debugging and double check.
#14
11/16/2010 (1:27 pm)
C:\Torque\AFX2 for T3D Pro 1.1 B3\Engine\source\materials\materialList.cpp(381): materialName = MATMGR->getMapEntry(matName.substr(1, matName.length()-1)); C:\Torque\AFX2 for T3D Pro 1.1 B3\Engine\source\materials\materialList.cpp(383): materialName = MATMGR->getMapEntry(matName); C:\Torque\AFX2 for T3D Pro 1.1 B3\Engine\source\materials\materialList.cpp(385): String materialName = MATMGR->getMapEntry(matName); C:\Torque\AFX2 for T3D Pro 1.1 B3\Engine\source\materials\materialList.cpp(392): materialName = MATMGR->getMapEntry(String::ToString( "polyMat_%s", matName.c_str()) ); C:\Torque\AFX2 for T3D Pro 1.1 B3\Engine\source\materials\materialManager.cpp(261): if (getMapEntry(textureName).isNotEmpty()) C:\Torque\AFX2 for T3D Pro 1.1 B3\Engine\source\materials\materialManager.cpp(271):String MaterialManager::getMapEntry(const String & textureName) const C:\Torque\AFX2 for T3D Pro 1.1 B3\Engine\source\materials\materialManager.cpp(468): return MATMGR->getMapEntry(argv[1]).c_str(); C:\Torque\AFX2 for T3D Pro 1.1 B3\Engine\source\materials\materialManager.cpp(483): return MATMGR->getMapEntry( String(argv[1]) ); C:\Torque\AFX2 for T3D Pro 1.1 B3\Engine\source\materials\materialManager.h(39): String getMapEntry(const String & textureName) const; C:\Torque\AFX2 for T3D Pro 1.1 B3\Engine\source\ts\collada\colladaShapeLoader.cpp(435): MATMGR->getMapEntry( mat->getName() ).isEmpty() ) )
#15
11/16/2010 (1:32 pm)
As far as I can tell it is grabbing by Material Name, not texture name.
#16
It works great for models in which I have a materials.cs but things without a material.cs I just see their armor, I don't see their body, any idea? SpaceOrc is the model I'm having trouble with.
Vince
11/17/2010 (12:00 am)
Ok,It works great for models in which I have a materials.cs but things without a material.cs I just see their armor, I don't see their body, any idea? SpaceOrc is the model I'm having trouble with.
Vince
#17
11/17/2010 (1:00 am)
The body isn't rendering at all?
#18
Atleast this is how I interpreted the debug info.
11/17/2010 (12:32 pm)
I figured it out, the orc warrior jpg doesn't have a skin in it, it uses the one defined by the orc caster, and shares the material. With this change, they no longer share the material so the orc warrior doesn't have it anymore. It's not a game breaker, since we aren't using that model in our game, it just means that all our skins need to have all the textures in them and models can't share textures.Atleast this is how I interpreted the debug info.
#19
11/17/2010 (3:29 pm)
Hmm, that's interesting. How often do you use models without a material.cs though?
#20
It's not the material.cs thats causing the problem. I think it's more that they are sharing textures which are mapped to the same material name. So pre patch, since the array was indexed by material name it would find the material since it was loaded for the other model, post patch, the array was being indexed via texture name and it wasn't able to find the texture.
All you have to do is apply this to the engine and grab a starter mission and put a warrior orc and casting orc in it. The casting orc looks fine, and the warrior orc is missing skin with this patch since the two I guess were designed to share the skin texture maybe to save memory.
dunno
11/17/2010 (4:25 pm)
With this fix in place we are now going back and adding material.cs to each object. Up until now we had to remove them since body parts between races and such were getting screwed up.It's not the material.cs thats causing the problem. I think it's more that they are sharing textures which are mapped to the same material name. So pre patch, since the array was indexed by material name it would find the material since it was loaded for the other model, post patch, the array was being indexed via texture name and it wasn't able to find the texture.
All you have to do is apply this to the engine and grab a starter mission and put a warrior orc and casting orc in it. The casting orc looks fine, and the warrior orc is missing skin with this patch since the two I guess were designed to share the skin texture maybe to save memory.
dunno
Torque Owner Giorgio Zanetti ( JoZ )
Corona Team