Game Development Community

[T3DB1] Bug: setSkinName and material definitions... - LOGGED

by Ted Southard · in Torque 3D Professional · 07/12/2010 (10:10 pm) · 9 replies

So, I understand the naming conventions of setSkinName, yet I can't seem to get it to work. I'm thinking that my material definitions may be jacked up, because I haven't found any info on what they should be to get this feature to work. Anyone have any insight on this? Thanks in advance!

#1
07/13/2010 (12:34 am)
The first thing is to name the texture files properly like this:

base.head.jpg (or .png or .dds ....)
base.body.jpg

red.head.jpg
red.body.jpg

blue.head.jpg
blue.body.jpg

Now set up the materials in materials.cs (just out of my head which is a little fuzzy right now, but you get the point)
singleton Material(base_head)
{
   mapTo = "base_head";
   diffuse[0] = "base.head.jpg";
   .
   .
};

singleton Material(base_body)
{
   mapTo = "base_body";
   diffuse[0] = "base.body.jpg";
   .
   .
};

singleton Material(red_head)
{
   mapTo = "base_head"; // Not quite sure here, could be red_head
   diffuse[0] = "red.head.jpg";
   .
   .
};

singleton Material(red_body)
{
   mapTo = "red_body"; // Not quite sure here, could be red_body
   diffuse[0] = "red.body.jpg";
   .
   .
};

singleton Material(blue_head)
{
   mapTo = "base_head"; // Not quite sure here, could be blue_head
   diffuse[0] = "blue.head.jpg";
   .
   .
};

singleton Material(blue_body)
{
   mapTo = "base_body"; // Not quite sure here, could be blue_body
   diffuse[0] = "blue.body.jpg";
   .
   .
};
Now you can change the skin by using:
%player.setSkinName('red');
// or
%player.setSkinName('blue');
// or
%player.setSkinName('base');
I hope this will help you, good luck.
#2
07/13/2010 (7:38 am)
So far, it still doesn't work. It's possible I'm not calling it correctly, but calling it on the player ID in the World Editor sets the skin (when you call getSkinName(), it returns the skin name that was set), but there is no visible change...
#3
07/14/2010 (8:42 pm)
So, here's my (lack of) progress so far...

- The mapTo portion of the material only maps to existing materials, and in this case, my model has a single material named "diffuse". If any of the skin materials are assigned to the model in the Material Editor, then 'mapTo = "diffuse";' appears in the material, so labeling it otherwise shouldn't work (and trying it, in fact, did not work).

- Taking the mapTo lines out of all the involved materials means nothing is mapped to the material on the model.

- The following are set in materials.cs:
singleton Material(base_skin)
{
   mapTo = "diffuse";
   diffuseMap[0] = "art/shapes/players/Humanoid/base.skin.png";
};

singleton Material(Skin0_skin)
{
   diffuseMap[0] = "art/shapes/players/Humanoid/skin0.skin.png";
};

singleton Material(Skin1_skin)
{
   diffuseMap[0] = "art/shapes/players/Humanoid/skin1.skin.png";
};

- I can successfully call .setSkinName() on the object I select in the World Editor, but not on the object returned by .getClientObject().

- I can set anything I like as the skin name in .setSkinName():
==>9760.setSkinName('ungabunga');
Mapping string: ungabunga to index: 8
==>9760.getskinname();
ungabunga
There's obviously no checking going on there...

- So, setting the Skin0.skin material doesn't do anything, though calling .getSkinName() will return whatever skin you set it to.

- Setting the texture names to match the material name ("diffuse") such as "base.diffuse.png", etc does not work.

- Setting the material name to have a "_diffuse" as a sort of suffix does not work.

Sort of stumped right now. Will update when I have more confusion to post ;)
#4
07/14/2010 (9:09 pm)
Update:

- Using baseTex instead of diffuse[0] does nothing.

- Taking out the path does nothing.

- Ensuring that the name of the material matches the prefix of the texture does nothing.

At this point I think I'm just pronouncing this feature as busted. There's some resource out there that does texture combining that I think I will try instead. If it's limited to being done on the client-side it shouldn't incur any real hits to performance.
#5
07/15/2010 (1:02 am)
Taking a look at the code, it seems that this block in TSShapeInstance::reSkin() is where the whole thing bails out:

if( !oldBaseName.isEmpty() && pName.compare( oldBaseNamePlusDot, oldBaseNameLength + 1, String::NoCase ) == 0 )
         {
            String matName = pName;
            String newPath = resourcePath + "/" + matName.replace( 0, oldBaseNameLength, newBaseName );
            replacedRoot = pMatList->setMaterial( j, newPath );
         }

pName is the name of the material taken from the material list (in the case of my object, "diffuse"), whereas the oldBaseNamePlusDot is the skin name, or in the case of my tests "skin0". Are these actually supposed to be getting compared like this? Because it seems to me that if you compare the group name to the skin name, you'll never get the compare to work, and thus never get the new skin into the material (even though it seems to be getting into the skin name, even when not applied).
#6
07/15/2010 (1:35 am)
game4rest's absolutely great resource T3D Networked Dynamic Skins and Materials Change was a more-than-adequate workaround when I ran into this.
#7
07/15/2010 (8:20 am)
Hi Ted,

I had the same problem a few months ago. I located the source as being a confusion between "." char and DAE exported "_" char.

Here is a revised version of reskin that works for me, based on T3D 1.0.1 :
void TSShapeInstance::reSkin( String newBaseName, String oldBaseName )
{
   if( newBaseName.isEmpty() )
      newBaseName = "base";
   if( oldBaseName.isEmpty() )
      oldBaseName = "base";

   const U32 oldBaseNameLength = oldBaseName.length();
	String oldBaseNamePlusDot;
	if( !oldBaseName.isEmpty() )
		oldBaseNamePlusDot = oldBaseName + String( "." );
	
	// NB_FIX 20100308
	String oldBaseNamePlusUnderscore;
	if( !oldBaseName.isEmpty() )
		oldBaseNamePlusUnderscore = oldBaseName + String( "_" );
	// NB_FIX 20100308 END
		
	// Make our own copy of the materials list from the resource
   // if necessary.
   if (ownMaterialList() == false)
      cloneMaterialList();

   Torque::Path   shapePath = mShapeResource.getPath();
   const String   resourcePath = shapePath.getPath();

   // Cycle through the materials.
   TSMaterialList* pMatList = getMaterialList();
   const Vector<String> &materialNames = pMatList->getMaterialNameList();

   for (S32 j = 0; j < materialNames.size(); j++) 
   {
      // Get the name of this material.
      const String &pName = materialNames[j];
 
	   if( !pName.isEmpty() )
      {
         // Try changing base.

         bool replacedRoot = false;

		  /* ORIGINAL VERSION
		  if( !oldBaseName.isEmpty() && ( pName.compare( oldBaseNamePlusDot, oldBaseNameLength + 1, String::NoCase ) == 0 ) )
		   */
		//
		// NB_FIX 20100308
		//
		// because colladaMax exporter from 3DS Max names the material and nodes in the DAE XML file
		// by replacing "." with "_"
		// So for instance, material "base.adn" got an < id = "base.adn" name = "base_adn" >
		// and the material system in T3D seems to get the "name" attribut
		//
		  if( !oldBaseName.isEmpty() && (
											 pName.compare( oldBaseNamePlusDot, oldBaseNameLength + 1, String::NoCase ) == 0 ||
											 pName.compare( oldBaseNamePlusUnderscore, oldBaseNameLength + 1, String::NoCase ) == 0 ) )
		// NB_FIX 20100308 END
		  {
            String matName = pName;
			  
			  // NB_FIX 20100308
			  //		  String newPath = resourcePath + "/" + matName.replace( 0, oldBaseNameLength, newBaseName );
			  String newPath = resourcePath + "/" + matName.replace( 0, oldBaseNamePlusDot.length(), newBaseName + String( "." ) );
			  // NB_FIX 20100308 END
			  
            replacedRoot = pMatList->setMaterial( j, newPath );
         }

         // If we did not change base, set the old material.

         if( !replacedRoot )
            pMatList->setMaterial( j, resourcePath + "/" + pName );
      }
   }

   // Initialize the material instances.

   initMaterialList();
}

Nicolas Buquet
www.buquet-net.com/cv/
#8
07/16/2010 (2:28 pm)
@Nicolas: I think you're bringing up something I didn't realize was a problem, namely COLLADA exports having _ instead of . in their names. The material name in my model is a DTS exported from Blender with a material name being simply "diffuse" with no . or _, and though I do have it working, the problem was that comparing "diffuse" with "base" or "skin0" probably wasn't going to result in a match. Making the change to compare oldBaseName and newBaseName resulted in a fix for me.

But since we're on this subject and there are no docs on this issue other than the forums- what I'm beginning to gather is that a model needs to have a material for each base that will be applied to it. So for combining textures, I would not be able to use this if the model has only one material, but would need to use functionality to actually combine textures themselves and then apply that to the model.

I've read other resources trying to get around this using the layer system and such, but when it comes down to it, it all just generates more draw calls per model, and if you have 50 of them on the screen and you're using 10 materials per model, then you can easily run into a draw call problem. So, I think I have to abandon this feature, cool as it sounded at first, and go look at texture combining as a way to get what I need.

However, I think that posting the fix was great, since those using COLLADA exports and this feature will need that.
#9
08/20/2010 (10:23 pm)
Logged as TQA-844