Lately i found some time to work on my game engine and i thought that skinning is a must have feature. So before grabbing the bulls by the horns and writhing shaders to multiply matrices the first question that pop up is “Where does 3DS Max keeps his skinning data? What does he offer us?”.


By consulting the SDK i found out about the existence of the classes ISkin and ISkin2. Everything looks easy till here, we have our object, we have our I_SKIN interface, what could be so hard in in calling our object for a interface?

1
obj->GetInterface(I_SKIN);

In reality things aren’t that simple, and after finding out that something that seemed logical at first glance returns a NULL pointer it’s back to the drawing board. Where is the skin if not inside the object?

Since the SDK didn’t offer any samples except for the IGame class Google remained my only alternative of discovering the mysteries of I_SKIN. So after a long search here we are with the answer:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//We need to get our reference object using one of the next 2 function from the current Node
Object* xobj = node->GetObjectRef();
Object* xobj = node->GetObjOrWSMRef();
//If the object has a super class of the type Derived Object then type cast it
IDerivedObject* derivedObj = NULL;
if (xobj->SuperClassID() == GEN_DERIVOB_CLASS_ID)
    derivedObj = static_cast<IDerivedObject*>(xobj);

//The IDerivedObject class actually holds the entire stack of modifiers from max so we need to search for a SKIN modifier
//Once we find the SKIN_CLASSID we can get use GetInterface on the modifier to obtain the ISkin interface
for(int i = 0; i < derivedObj->NumModifiers(); ++i)
{
  Modifier *pModifier = derivedObj->GetModifier(i);
  if (pModifier == NULL || pModifier->ClassID() != SKIN_CLASSID)
    continue;
  skin = (ISkin*)pModifier->GetInterface(I_SKIN);
  break;
}

//Using the ISkin we can get the ISkinContextData based on the modifier node
if (skin != NULL)
  skinContextData = (ISkinContextData*)skin->GetContextInterface(node);

Extracting all the necessary data from:

1
2
3
Mesh* mesh;
ISkin* skin;
ISkinContextData *skinContextData;

shouldn’t be that complicated once you know what you need (bones/weights/etc) but from my point of view 3DS Max should really invest a bit more time in their SDK samples since something like getting the ISkin interface can be really obscure as you can see from the code above.