DMX model: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
mNo edit summary
(details from Valve)
Line 89: Line 89:
bool flipVCoordinates; // left-handed to right-handed?
bool flipVCoordinates; // left-handed to right-handed?


// In the next three cases, the "Indicies" array contains one entry for each vertex.
// In the next three cases, the first array contains the location of each vertex on the model.
// the indice value defines which value from the 'real' array the vertex takes. In this
// The second "Indices" array contains one entry one entry per vertex /per face/.
// way, vertices can share data. This is a useful optimisation since each poly has its
// own three verts, even if they overlap other verts.
Vector positions[];
Vector positions[];
Line 103: Line 101:
int textureCoordinatesIndices[];
int textureCoordinatesIndices[];
// Weightmapping; optional. The size of BOTH arrays is equal to ( sizeof(positions) * jointCount )...
// Weightmapping; optional. The size of BOTH arrays is equal to ( sizeof(positions) * jointCount )
// it is not possible for two verts in the same place to be weighted differently.
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)
Line 139: Line 136:
{
{
DmeTimeFrame* timeFrame;
DmeTimeFrame* timeFrame;
Colour color;
Colour color; // SFM only
CUtlString text;
CUtlString text; // SFM only
bool mute; // no effect
bool mute; // SFM only
int frameRate; // typically 30
int frameRate; // typically 30


void trackGroups[]; // only seen empty
void trackGroups[]; // SFM only
DmeChannel channels[]; // two for each bone: position and rotation
DmeChannel channels[]; // two for each bone: position and rotation
};
};


Line 158: Line 155:
class DmeChannel
class DmeChannel
{
{
// this system is clearly designed to support the animation of arbitrary
// this system is shared with Source Filmmaker, so has support for animating generic properties.
// values, but is only used for bone location and rotation.
// Studiomdl only cares about bones though.
CDmxElement* fromElement;
CDmxElement* fromElement;
CUtlString fromAttribute;
CUtlString fromAttribute;
Line 173: Line 170:
DmeQuaternionLog log[];
DmeQuaternionLog log[];
DmeVector3Log log[];
DmeVector3Log log[];
// etc?
// etc
};
};


Line 215: Line 212:
DmeMesh* dominators[]; // unknown
DmeMesh* dominators[]; // unknown
DmeMesh* targets[]; // mesh with the shapes on
DmeMesh* targets[]; // mesh with the shapes on
DmeFlexRules* targets[] //
};
};


Line 220: Line 218:
{
{
CUtlString rawControlNames[]; // which controls are being wrapped
CUtlString rawControlNames[]; // which controls are being wrapped
bool stereo; // equivalent to QC 'split'?
bool stereo; // equivalent to QC 'split'
bool eyelid; // flags as an eyelid used by AI for blinking
bool eyelid; // flags as an eyelid used by AI for blinking
float wrinkleScales[]; // wrinklemap stuff; one value for each named control.
float wrinkleScales[]; // wrinklemap stuff; one value for each named control.
float flexMin;
float flexMax;
};
class DmeVertexDeltaData // a shape
{
CUtlString vertexFormat[]; // positions, normals, [wrinkle]
bool flipVCoordinates;
bool corrected;
Vector3 positions[]; // offset: (shape position) - (mesh position)
int positionsIndices[]; // index in the main VertexData positions array (*not* positionsIndices)
Vector3 normals[]; // absolute
int normalsIndices[]; // index in the main VertexData normals array (*not* normalsIndices)
float wrinkle[]; // unknown
int wrinkleIndices[]; // unknown
};
class DmeFlexRules
{
DmeFlexRule* deltaStates[];
Vector2 deltaStateWeights[];
DmeMesh* target; // mesh with the shapes on
};
class DmeFlexRule
{
// Name should match the name of a DmeVertexDeltaData element
float result;
CUtlString expression; // +-*/() with min, max & sqrt.
};
};
</source>
</source>

Revision as of 13:08, 7 August 2012

The DMX model format replaces Studiomdl Data. Below is the structure of version 18, which can be compiled by Alien Swarm studiomdl. Source 2009 studiomdl requires version 1.

Note.pngNote:All names are case sensitive.

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;
};

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	
	DmeVertexData		deltaStates[];	// flex shapes	
	DmeFaceSet			faceSets[];

	Vector2D			deltaStateWeights[];		// unknown
	Vector2D			deltaStateWeightsLagged[];	// unknown
};

class DmeVertexData // mesh data
{
	CUtlString	vertexFormat[];		// { positions, normals, textureCoordinates, [jointWeights, jointIndices] }
	int			jointCount;			// most bones any one vert is weighted to (should be quite low)
	bool		flipVCoordinates;	// left-handed to right-handed?

	// In the next three cases, 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)
};

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
};

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 system 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[];
};

Flex shapes

class DmeModelRoot
{
	// model and skeleton should point to the same object
	DmeModel*	model;
	DmeModel*	skeleton;
	
	DmeCombinationOperator*	combinationOperator;
};

class DmeCombinationOperator // flex controller global settings
{
	DmeCombinationInputControl	controls[];
	Vector		controlValues[];		// rest position...but why a 3D vector?
	Vector		controlValuesLagged[];	// unknown
	bool		usesLaggedValues;
	DmeMesh*	dominators[];			// unknown
	DmeMesh*	targets[];				// mesh with the shapes on
	DmeFlexRules*	targets[]			// 
};

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 stuff; one value for each named control.
	float		flexMin;
	float		flexMax;
};

class DmeVertexDeltaData // a shape
{
	CUtlString	vertexFormat[]; // positions, normals, [wrinkle]
	bool		flipVCoordinates;
	bool		corrected;

	Vector3	positions[]; // offset: (shape position) - (mesh position)
	int		positionsIndices[]; // index in the main VertexData positions array (*not* positionsIndices)

	Vector3	normals[]; // absolute
	int		normalsIndices[]; // index in the main VertexData normals array (*not* normalsIndices)

	float	wrinkle[]; // unknown
	int		wrinkleIndices[]; // unknown
};

class DmeFlexRules
{
	DmeFlexRule*	deltaStates[];
	Vector2			deltaStateWeights[];
	DmeMesh*		target; // mesh with the shapes on
};

class DmeFlexRule
{
	// Name should match the name of a DmeVertexDeltaData element

	float		result;
	CUtlString	expression; // +-*/() with min, max & sqrt.
};