DMX model: Difference between revisions
Jump to navigation
Jump to search
Note:All names are case sensitive.
No edit summary |
No edit summary |
||
Line 1: | Line 1: | ||
The '''[[DMX]] model format''' replaces [[Studiomdl Data]]. | {{toc-right}} | ||
The '''[[DMX]] model format''' replaces [[Studiomdl Data]]. This article describes '''version 18'''. | |||
{{note|All names are case sensitive.}} | {{note|All names are case sensitive.}} | ||
== Versions == | |||
;1 | |||
: Source 2007 | |||
: Source 2009 | |||
; 15 | |||
: Left 4 Dead | |||
: Left 4 Dead 2 | |||
; 18 (documented below) | |||
: Alien Swarm | |||
: Source MP | |||
: Portal 2 | |||
: Source Filmmaker | |||
: CS:GO | |||
== Common == | == Common == | ||
Line 10: | Line 27: | ||
class DmeDag | class DmeDag | ||
{ | { | ||
DmeTransform | DmeTransform transform; | ||
bool visible; | bool visible; | ||
void children[]; // never seen used (Compatibility with DmeModel?) | void children[]; // never seen used (Compatibility with DmeModel?) | ||
// One of the following: | // One of the following: | ||
CUtlString name // of a DmeJoint | CUtlString name; // of a DmeJoint | ||
DmeMesh | DmeMesh shape; | ||
DmeAttachment | DmeAttachment shape; | ||
}; | }; | ||
class DmeJoint // a bone | class DmeJoint // a bone | ||
{ | { | ||
DmeTransform | DmeTransform transform; | ||
void | void shape; // only seen empty | ||
bool visible; | bool visible; | ||
DmeJoint children[]; | DmeJoint children[]; | ||
Line 47: | Line 64: | ||
{ | { | ||
// model and skeleton should point to the same object | // model and skeleton should point to the same object | ||
DmeModel | DmeModel model; | ||
DmeModel | DmeModel skeleton; | ||
DmeCombinationOperator combinationOperator; // flex controllers; optional | |||
}; | }; | ||
class DmeModel // one per file | class DmeModel // one per file | ||
{ | { | ||
DmeTransform | DmeTransform transform; // global model transform...DmeDag not supported here? | ||
void shape; // only seen empty (Compatibility with DmeDag?) | void shape; // only seen empty (Compatibility with DmeDag?) | ||
bool visible; | bool visible; | ||
DmeDag | DmeDag|DmeJoint children[]; // mixed type | ||
DmeJoint jointList[]; | DmeJoint jointList[]; | ||
DmeTransformList baseStates[]; // bone positions; only ever seen with one value | DmeTransformList baseStates[]; // bone positions; only ever seen with one value | ||
Line 73: | Line 92: | ||
bool visible; | bool visible; | ||
void | void bindState; // only seen empty | ||
DmeVertexData | DmeVertexData currentState; // pointer to default baseState | ||
DmeVertexData baseStates[]; // only ever seen with one value | DmeVertexData baseStates[]; // only ever seen with one value | ||
DmeVertexDeltaData deltaStates[]; // flex shapes | |||
DmeFaceSet faceSets[]; | DmeFaceSet faceSets[]; | ||
Line 85: | Line 104: | ||
class DmeVertexData // mesh data | class DmeVertexData // mesh data | ||
{ | { | ||
CUtlString vertexFormat[]; // { positions, normals, textureCoordinates, [jointWeights, jointIndices] } | CUtlString vertexFormat[]; // { positions, normals, textureCoordinates, [jointWeights, jointIndices, balance] } | ||
int jointCount; // most bones any one vert is weighted to; max 3 | int jointCount; // most bones any one vert is weighted to; max 3 | ||
bool flipVCoordinates; // left-handed to right-handed? | bool flipVCoordinates; // left-handed to right-handed? | ||
// | // The first array contains the location of each vertex on the model. | ||
// The second "Indices" array contains one entry one entry per vertex /per face/. | // The second "Indices" array contains one entry one entry per vertex /per face/. | ||
Line 101: | Line 120: | ||
int textureCoordinatesIndices[]; | int textureCoordinatesIndices[]; | ||
// Weightmapping; optional. The size of BOTH arrays is equal to ( sizeof(positions) | // Weightmapping; optional. The size of BOTH arrays is equal to ( sizeof(positions) jointCount ) | ||
float jointWeights[]; // weight | float jointWeights[]; // weight | ||
int jointIndices[]; // index in DmeModel::jointList (v18) or DmeModel::baseStates[0]::transforms (v1) | int jointIndices[]; // index in DmeModel::jointList (v18) or DmeModel::baseStates[0]::transforms (v1) | ||
float balance[]; // Defines flex controller stereo split. 0 means right, 1 means left. | |||
int balanceIndices[]; | |||
}; | }; | ||
class DmeFaceSet // defines faces, including their material | class DmeFaceSet // defines faces, including their material | ||
{ | { | ||
DmeMaterial | DmeMaterial material; // the material these faces are drawn with | ||
int | int faces[]; // the vertices that make up each face, delimited by -1. Quads and n-gons allowed. | ||
}; | }; | ||
Line 115: | Line 137: | ||
{ | { | ||
CUtlString mtlName; // with path relative to \game\materials\, no extension | CUtlString mtlName; // with path relative to \game\materials\, no extension | ||
}; | |||
class DmeVertexDeltaData // a shape key | |||
{ | |||
CUtlString vertexFormat[]; // positions, normals, [wrinkle] | |||
bool flipVCoordinates; // unknown | |||
bool corrected; // unknown | |||
// these arrays use the same system as those in DmeVertexData | |||
Vector3 positions[]; // offset: (shape position) - (mesh position) | |||
int positionsIndices[]; // index in VertexData::positions | |||
Vector3 normals[]; // absolute | |||
int normalsIndices[]; // index in VertexData::normals | |||
float wrinkle[]; // Multiplier for controller-defined wrinkle weight | |||
int wrinkleIndices[]; // index in VertexData::positions | |||
}; | |||
</source> | |||
=== Flex controllers === | |||
<source lang=cpp> | |||
class DmeCombinationOperator // flex controller global settings | |||
{ | |||
DmeCombinationInputControl controls[]; | |||
Vector controlValues[]; // rest position...but why a 3D vector? | |||
Vector controlValuesLagged[]; // unknown | |||
bool usesLaggedValues; | |||
DmeCombinationDominationRule dominators[]; | |||
DmeMesh|DmeFlexRules targets[]; // mixed type | |||
}; | |||
class DmeCombinationInputControl // a flex controller | |||
{ | |||
CUtlString rawControlNames[]; // which controls are being wrapped | |||
bool stereo; // equivalent to QC 'split' | |||
bool eyelid; // flags as an eyelid used by AI for blinking | |||
float wrinkleScales[]; // wrinklemap strength for each named control. Positive means compress, negative means stretch. | |||
float flexMin; | |||
float flexMax; | |||
}; | |||
class DmeCombinationDominationRule // Disables certain shapes (NOT controllers) when others are active | |||
{ | |||
CUtlString dominators[]; | |||
CUtlString supressed[]; | |||
}; | |||
class DmeFlexRules // shape key pre-processing | |||
{ | |||
DmeFlexRule|DmeFlexRulePassThrough deltaStates[]; // mixed type | |||
Vector2 deltaStateWeights[]; | |||
DmeMesh target; // mesh with the shapes on | |||
}; | |||
// In the next two cases, the element name must match | |||
// the name of a DmeVertexDeltaData element on the target DmeMesh | |||
class DmeFlexRule | |||
{ | |||
float result; | |||
CUtlString expression; // +-/() with min, max & sqrt. | |||
}; | |||
class DmeFlexRulePassThrough // no expression required | |||
{ | |||
float result; | |||
}; | }; | ||
</source> | </source> | ||
Line 123: | Line 212: | ||
class DmeModelRoot | class DmeModelRoot | ||
{ | { | ||
DmeModel | DmeModel skeleton; | ||
DmeAnimationList | DmeAnimationList animationList; | ||
}; | }; | ||
Line 135: | Line 224: | ||
class DmeChannelsClip | class DmeChannelsClip | ||
{ | { | ||
DmeTimeFrame | DmeTimeFrame timeFrame; | ||
Colour color; // SFM only | Colour color; // SFM only | ||
CUtlString text; // SFM only | CUtlString text; // SFM only | ||
Line 155: | Line 244: | ||
class DmeChannel | class DmeChannel | ||
{ | { | ||
// this | // this format is shared with Source Filmmaker, so has support for animating generic properties. | ||
// Studiomdl only cares about bones though. | // Studiomdl only cares about bones though. | ||
CDmxElement | CDmxElement fromElement; | ||
CUtlString fromAttribute; | CUtlString fromAttribute; | ||
int fromIndex; | int fromIndex; | ||
CDmxElement | CDmxElement toElement; // ordinarily a DmeTransform used by the target bone | ||
CUtlString toAttribute; | CUtlString toAttribute; | ||
int toIndex; | int toIndex; | ||
Line 177: | Line 266: | ||
DmeQuaternionLogLayer layers[]; | DmeQuaternionLogLayer layers[]; | ||
CDmxElement | CDmxElement curveinfo; | ||
bool usedefaultvalue; | bool usedefaultvalue; | ||
Quaternion defaultvalue; | Quaternion defaultvalue; | ||
Line 189: | Line 278: | ||
int curvetypes[]; // only seen empty...keyframe interp? | int curvetypes[]; // only seen empty...keyframe interp? | ||
Quaternion values[]; | Quaternion values[]; | ||
}; | }; | ||
</source> | </source> |
Revision as of 02:22, 2 September 2012
The DMX model format replaces Studiomdl Data. This article describes version 18.

Versions
- 1
- Source 2007
- Source 2009
- 15
- Left 4 Dead
- Left 4 Dead 2
- 18 (documented below)
- Alien Swarm
- Source MP
- Portal 2
- Source Filmmaker
- CS:GO
Common
// A "DAG" is a generic Maya container, appearing here in order to transform objects.
// It can take the place of a DmeMesh, DmeJoint or DmeAttachment at any time.
class DmeDag
{
DmeTransform transform;
bool visible;
void children[]; // never seen used (Compatibility with DmeModel?)
// One of the following:
CUtlString name; // of a DmeJoint
DmeMesh shape;
DmeAttachment shape;
};
class DmeJoint // a bone
{
DmeTransform transform;
void shape; // only seen empty
bool visible;
DmeJoint children[];
bool lockInfluenceWeights;
};
class DmeTransformList
{
DmeTransform transforms[];
};
class DmeTransform // name is of a defined model if there are children, otherwise blank
{
Vector position;
Quaternion orientation;
};
Mesh
class DmeModelRoot
{
// model and skeleton should point to the same object
DmeModel model;
DmeModel skeleton;
DmeCombinationOperator combinationOperator; // flex controllers; optional
};
class DmeModel // one per file
{
DmeTransform transform; // global model transform...DmeDag not supported here?
void shape; // only seen empty (Compatibility with DmeDag?)
bool visible;
DmeDag|DmeJoint children[]; // mixed type
DmeJoint jointList[];
DmeTransformList baseStates[]; // bone positions; only ever seen with one value
CUtlString upAxis; // uppercase character
};
class DmeAttachment // an attachment
{
bool visible;
bool isRigid; // apparently obsolete?
bool isWorldAligned; // does not move with parent bone, but is still positioned relative to it
};
class DmeMesh
{
bool visible;
void bindState; // only seen empty
DmeVertexData currentState; // pointer to default baseState
DmeVertexData baseStates[]; // only ever seen with one value
DmeVertexDeltaData deltaStates[]; // flex shapes
DmeFaceSet faceSets[];
Vector2D deltaStateWeights[]; // unknown
Vector2D deltaStateWeightsLagged[]; // unknown
};
class DmeVertexData // mesh data
{
CUtlString vertexFormat[]; // { positions, normals, textureCoordinates, [jointWeights, jointIndices, balance] }
int jointCount; // most bones any one vert is weighted to; max 3
bool flipVCoordinates; // left-handed to right-handed?
// The first array contains the location of each vertex on the model.
// The second "Indices" array contains one entry one entry per vertex /per face/.
Vector positions[];
int positionsIndices[];
Vector normals[];
int normalsIndices[];
Vector2D textureCoordinates[];
int textureCoordinatesIndices[];
// Weightmapping; optional. The size of BOTH arrays is equal to ( sizeof(positions) jointCount )
float jointWeights[]; // weight
int jointIndices[]; // index in DmeModel::jointList (v18) or DmeModel::baseStates[0]::transforms (v1)
float balance[]; // Defines flex controller stereo split. 0 means right, 1 means left.
int balanceIndices[];
};
class DmeFaceSet // defines faces, including their material
{
DmeMaterial material; // the material these faces are drawn with
int faces[]; // the vertices that make up each face, delimited by -1. Quads and n-gons allowed.
};
class DmeMaterial // a material
{
CUtlString mtlName; // with path relative to \game\materials\, no extension
};
class DmeVertexDeltaData // a shape key
{
CUtlString vertexFormat[]; // positions, normals, [wrinkle]
bool flipVCoordinates; // unknown
bool corrected; // unknown
// these arrays use the same system as those in DmeVertexData
Vector3 positions[]; // offset: (shape position) - (mesh position)
int positionsIndices[]; // index in VertexData::positions
Vector3 normals[]; // absolute
int normalsIndices[]; // index in VertexData::normals
float wrinkle[]; // Multiplier for controller-defined wrinkle weight
int wrinkleIndices[]; // index in VertexData::positions
};
Flex controllers
class DmeCombinationOperator // flex controller global settings
{
DmeCombinationInputControl controls[];
Vector controlValues[]; // rest position...but why a 3D vector?
Vector controlValuesLagged[]; // unknown
bool usesLaggedValues;
DmeCombinationDominationRule dominators[];
DmeMesh|DmeFlexRules targets[]; // mixed type
};
class DmeCombinationInputControl // a flex controller
{
CUtlString rawControlNames[]; // which controls are being wrapped
bool stereo; // equivalent to QC 'split'
bool eyelid; // flags as an eyelid used by AI for blinking
float wrinkleScales[]; // wrinklemap strength for each named control. Positive means compress, negative means stretch.
float flexMin;
float flexMax;
};
class DmeCombinationDominationRule // Disables certain shapes (NOT controllers) when others are active
{
CUtlString dominators[];
CUtlString supressed[];
};
class DmeFlexRules // shape key pre-processing
{
DmeFlexRule|DmeFlexRulePassThrough deltaStates[]; // mixed type
Vector2 deltaStateWeights[];
DmeMesh target; // mesh with the shapes on
};
// In the next two cases, the element name must match
// the name of a DmeVertexDeltaData element on the target DmeMesh
class DmeFlexRule
{
float result;
CUtlString expression; // +-/() with min, max & sqrt.
};
class DmeFlexRulePassThrough // no expression required
{
float result;
};
Animation
class DmeModelRoot
{
DmeModel skeleton;
DmeAnimationList animationList;
};
class DmeAnimationList
{
DmeChannelsClip animations[];
};
class DmeChannelsClip
{
DmeTimeFrame timeFrame;
Colour color; // SFM only
CUtlString text; // SFM only
bool mute; // SFM only
int frameRate; // typically 30
void trackGroups[]; // SFM only
DmeChannel channels[]; // two for each bone: position and rotation
};
class DmeTimeFrame
{
DmeTime_t start; // no apparent effect, use offset
DmeTime_t duration; // length in seconds...framerate is NOT adjusted
DmeTime_t offset; // remove this many seconds from the start (can be negative)
float scale; // frameRate multiplier
};
class DmeChannel
{
// this format is shared with Source Filmmaker, so has support for animating generic properties.
// Studiomdl only cares about bones though.
CDmxElement fromElement;
CUtlString fromAttribute;
int fromIndex;
CDmxElement toElement; // ordinarily a DmeTransform used by the target bone
CUtlString toAttribute;
int toIndex;
int mode; // unknown
// One of:
DmeQuaternionLog log[];
DmeVector3Log log[];
// etc
};
class DmeQuaternionLog // also DmeVector3Log etc.
{
DmeQuaternionLogLayer layers[];
CDmxElement curveinfo;
bool usedefaultvalue;
Quaternion defaultvalue;
};
class DmeQuaternionLogLayer // also DmeVector3LogLayer etc.
{
// only frames where the bone moves need to be given
// unlike SMD, sparse keyframes are supported
DmeTime_t times[];
int curvetypes[]; // only seen empty...keyframe interp?
Quaternion values[];
};