Player Models HowTo

Wolfenstein: Enemy Territory Documentation
© 2003 Splash Damage, Ltd. All Rights Reserved.


The player model system in Enemy Territory exists out of multiple parts. This document will elaborate on all the different files needed, how to create them and how to fit them together. There are quite a few files involved per player model, so good media management is a requirement.

The File Types

.mdm Skeletal meshes. These files contain all surfaces with vertex positions, their bone weighting and UV information. Tags are saved to this file as well.
.mdx Skeletal animation files. These files contain the bone positions for multiple frames. Frame bounding box data is present too.
.md3 MD3 files are old Q3 style meshes. They can be vertex-animated and are primarily used for head and attachment models.
.anim Animation groups. These files reference a set of mdx files and include their animation frame descriptors.
.aninc Animation inclusion files. They contain the names of animation sequences and their properties like starting frame, duration, frame rate, etc.
.skin Skin definition files. They are used in combination with a mesh to define the shader to be used with specific surfaces. They are also used to specify which models the game code has to attach to player models.
.script Animation script files. These define possible state combinations and are used by the game code to find out which animation sequences to play in those situations.
.char Character files. They combine all of the above files into a valid character that can be referenced from game code and map scripts to spawn a player or bot with a certain look.

A Quick Overview of the Exporting Process
It all starts with a mesh tied to a biped in MAX. Using the SkelOut plugin, this will be saved to a SKL file. Then, BuildMDS will use this file to create a MDM file and one or more MDX files. Tie these together with an animation group, an animation script and some skin files and you have yourself a new model.

From MAX to SKL
To install the SkelOut plugin, copy the skelout.dle file to the plugins directory in your MAX dir. (Re-)starting MAX will load the plugin.

The export process for an ET compatible version 2 SKL file requires you to have everything you don’t want in the game hidden in MAX. All surfaces and tags that remain and will have to be exported into the MDM files will have to be frozen; else they’ll get converted into bones. The only objects that remain unfrozen and unhidden should be the biped sections that the skeleton uses.

It’s very important to make sure the biped is set to rigid, both during development and exporting to ensure what you see in MAX is the same as what you will see in-game.

Now hit file->export, select Wolfenstein Skeleton Export (*.SKL) from the dropdown box and enter a filename. Click on save and you will get a dialog box where you can enter multiple values for exporting.

Specify the start frame, end frame and the frame rate at which you want to have the SKL exported. The default frame and sample rate of 15 should be fine in all cases. Make sure you select version 2 for MDM exports, else you won’t be able to create proper MDM or MDX files.

Hit OK and the plugin should start exporting. Minimize MAX for the process to go faster as it won’t have to render the frames as it goes.

Providing no error messages pop up you should have made yourself a SKL file.

BuildMDS
To convert the SKL file to MDM and/or MDX files a tool called BuildMDS is used. Before this tool is used some understanding about the ideas behind MDX and MDM is required.

The reason these model formats have their meshes and animation data separated is so that multiple meshes can share the same animation data which has the potential to greatly reduce the games’ memory footage. There is only one requirement to make this work, namely that all bones that a mesh references must be present in the animation data. So basically the bone structure in the MDX files always has to be the same, or a superset of, the bone structure in the MDM files. To ensure this, a parent MDX file will have to be specified when exporting related MDM or MDX files. How this file is generated and where it has to be referenced will be explained later on.

Before you will be able to convert a SKL file, you need two additional files. A .skd file and a .ski file. The skd file is used to define the spine bones and the way the torso bends. Besides that it contains information about the models’ LOD. Here is an example of a skd file:

//
// MDS definition file
//
// (read in by BUILDMDS when building the MDS file)
//
//—————————————————————————————–

VERSION 1

//—————————————————————————————–
//
// SPINE BONES
//
// This is used to scale torso rotations to create a smooth transition along the spine
//
// Always make sure NUMWEIGHTS specifies the correct number of bones listed
//
// NOTE: this is also used to determine where the torso starts. so if you decide to give the
// first spine element a torso weight of 0, it will be deemed as belonging to the legs, so it will
// show legs animations. so best set it to a very low number (eg. 0.0001) so that it remains
// connected to the torso.
//
// NOTE2: any descendant bones of those listed here will be deemed as belonging to the torso. So
// make sure any legs bone do not descend from any of these bones.

NUMSPINEBONES 3

// NOTE: cant use the “spine” since it is the parent of the thigh’s
//”Bip01 Spine” 0.1

“Bip01 Spine1” 0.30
“Bip01 Spine2” 0.55
“Bip01 Spine3” 0.85

//—————————————————————————————–
//
// MISC INFORMATION
//
//
// LODFRAME is the animation frame index to use when creating the collapse map for LOD.
// The best frame to use for this is a crouching position where all elbow and knee joints are bent,
// otherwise the LOD levels won’t take into account that these joints will often be bent, and will
// result in forced straight legs and arms in lower LOD levels.
//
// NOTE: a NEGATIVE lod frame translates to ( NUMFRAMES + LODFRAME ), so you can assign
// the second last frame and not have to update it each time the frame count changes

LODFRAME 4274

// LODSCALE can be used to vary the speed at which a model decreases it’s LOD with range. It would
// be wise to give a low detail model a lower LODSCALE than a model with much higher detail.

LODSCALE 1.0

// LODBIAS can be used to set a fixed amount by which to adjust all LOD calculations for this model.
// This will effect the in-game LOD calculations by this amount, applied before 0.0 – 1.0 capping is
// applied.
// Negative values will decrease LOD falloff, so a value here of -1.0 will mean a model will always
// show full detail, assuming r_lodbias is 0.

LODBIAS 0.0

The comments in this example should explain the syntax and the usage well enough for you to create your own skd files.

The ski file is the export information file that BuildMDS uses to know which base MDX to use and which MDX files to export from a certain SKL file. An example:

//
// MDX export information file
//
// (read in by BUILDMDS when building the MDM/MDX files)
//
//—————————————————————————————–

VERSION 1

//—————————————————————————————–

// COMPILEBONESFILE links to the .mdx skeletal file that this mdm uses during compile, to grab the
// bonenames from and translate these to boneindices (this path is relative to the compiler). It needs
// to be generated before the .mdm can be generated. MDX files use it as well to remap their bones.
// It’s a good idea to have a base (dummy) mdx file that is used to generate all the other mdx and mdm
// files of. For this file is required to be there (if it’s not and it’s listed in the mdxfiles
// list it will be generated automatically first), unless you are making the base mdx ofcourse. In that
// case give a COMPILEBONESFILE name of “BASEMDX”. When that’s the case then the mdx listed first in
// the mdxfiles list will be used as a base. Which naturally means that the skl used with this definition
// file has to be the skl that provides the base bonesetup.

COMPILEBONESFILE “BASEMDX”

// NUMMDXFILES is the number of mdx files we generate from this skl file using this definition file

NUMMDXFILES 2

// Here are the mdx file details listed. Syntax is <outputfilename> <startframe in .skl> <endframe in .skl>

“base.mdx” 0 4869
“self_inject.mdx” 4870 4886

This file should be self-explanatory as well, but to ensure nothing will go wrong some extra information regarding the COMPILEBONESFILE entry is needed. When exporting the first MDM and set of MDX files from a SKL that will provide the base MDX, the value of COMPILEBONESFILE needs to be set to “BASEMDX”. This is required to show BuildMDS that we are using this SKL as a base.

Whenever a MDM or MDX is exported from other SKL files belonging to the same set of shared animations and meshes as this base MDX, COMPILEBONESFILE should point at a MDX file generated from the base SKL. This allows BuildMDS to remap the bones in other SKL files to ensure compatible MDM and MDX files are generated.

Keep in mind that whenever a new bones structure is required; for example if more bones are being used than the base provides, a new base MDX will have to be generated and all MDM and MDX files in the same set of animations will have to be converted again.

Now let’s move on to the actual usage of BuildMDS. If you want to generate a MDM file and optionally a set of MDX files (you can set NUMMDXFILES to 0 in the ski file to choose not to generate any of these), you use the following command line:

buildmds <sklfile> -mdm [-verbose] [-force] [-dest name]

The SKL filename should be specified without extension. Verbose can be specified to generate extra information about the conversion process, force can be used to override the up-to-date checks done on MDM and MDX files relative to the source SKL file and force an export at all times. The MDM will be named after the SKL file, although this can be overwritten by using the dest parameter.

To only generate MDX files, the following command line is to be used:

buildmds <sklfile> -mdx [-verbose] [-force]

Both the command lines mentioned use the ski file to determine the filenames of the MDX files to generate.

There are more command line parameters available for BuildMDS, but most aren’t relevant to the MDM and MDX conversion process. Some of them aren’t used at all while some others might actually cause the process to malfunction. So unless you know what you’re doing it’s best to stay away from them.

Animation Groups
Now a set of compatible MDX files has been generated, an animation group needs to be made to tie them together. The syntax of this file is as follows:

animgroup
{
animfile <mdx file>
{
#include <aninc file>
}
}

There is no limit to the amount of mdx files that can be specified in one animation group.

The aninc file that is included through the #include statement specifies which animation sequences are present in the related MDX file and has the following syntax:

<animation name> <first frame> <length> <looping> <fps> <move speed> <transition> <reversed>

All of which should be on one line. Any number of animation sequences can be specified in one aninc file, the only limit is the total amount of individual animation sequences that can be handled by the game. A small example aninc file:

        // SELF INJECT
self_inject        0    16    0    15    0    0    0

This one specifies only one animation, but every MDX file can have one or multiple animation sequences.

You can create multiple animation groups for a set of compatible MDX files, to create subsets for certain characters. This is useful if there is, for example, a cigarette smoking animation that is compatible with the default human set but this sequence is only used on certain levels. A separate animation group can be created for humans that smoke and referenced from a character definition that gets used only in those levels that require the animation. This prevents the game from having to load the smoking animation on levels that don’t use it.

Another use is if you have two characters that use the same animation set and script, but each has its own death animations (which will be referenced from the animation script using the same animation names, such as death_knife), you then can create two animation groups for these characters and tie them up in two different character definitions. Useful if you have, for example, a scripted character you want to die in a certain way.

Skin Files
Skin files have two functions. They are used in combination with models where their primary function is to define which shaders are to be used on the surfaces of a model. Their secondary function, which only applies to skin files for the head and body models, is to attach accessory models to the body or head. The syntax is very basic, namely:

<key>,    “<value>”

If the key is the name of a surface, the value is an absolute path to a shader or texture to be used for this surface. For accessory attachment keys, the value is an absolute path to a model to attach.

The following keys are supported for the body skin file:

md3_beltr Attaches to tag tag_bright.
md3_beltl Attaches to tag tag_bleft.
md3_belt Attaches to tag tag_ubelt.
md3_back Attaches to tag tag_back.
md3_weapon Attaches to tag tag_weapon.
md3_weapon2 Attaches to tag tag_weapon2.

And for the head skin file:

md3_hat Attaches to tag_mouth, gets removed when a headshot is given.
md3_hat2 Attaches to tag tag_mouth.
md3_hat3 Attaches to tag tag_mouth.

Character Definitions
Character files are used to describe a full character and tie all the files that define the way a player or bot looks. They have the following syntax:

characterDef
{
<keys and values>
}

The following set of keys is supported:

mesh <mesh> The mesh file to use. (MDM or MDS)
animationgroup <animation group> The animation group. If a MDS is used, this should point to an old-style animation config.
animationscript <animation script> This points to an animation script file.
skin <skin file> The skin file used for the mesh. The actual filename gets derived from this string and the mesh filename. If you have “players/soldier/body.mdm” as mesh and “default” as skin, it will look for “players/soldier/body_default.skin”.
animatedHead If this keyword is present, the code assumes the head model used for this character supports facial animation.
undressedCorpseModel <mesh> Mesh used for when a Covert Ops steals the uniform of a corpse. (MDM or MDS)
undressedCorpseSkin <skin> The skin file used for the undressed corpse.
hudHead <head model> Mesh to use for the hud head. (MD3)
hudHeadSkin <skin> The skin file used for the hud head.
hudHeadAnims <animation inclusion file> Hud head animation descriptions.

Enemy Territory File Tree Structure
For Enemy Territory the following file structure is used:

[etmain]
|
|-[animations] – contains animation group files (*.anim)
|    |
|    |-[human]
|    | |
|    | |-[base] – contains human/base animation set files (*.mdx/*.aninc)
|    |-[scripts] – contains animation scripts
|
|-[characters]
|    |
|    |-[<theme>]
|        |
|        |-[allied] – contains Allied character definitions
|        |
|        |-[axis] – contains Axis character definitions
|
|-[models]
|
|-[players]
|
|-[<theme>]
|
|-[allied] – contains subdirectories with Allied character media
|-[axis] – contains subdirectories with Axis character media

A subdirectory with themed and teamed character media will use a structure similar to the following example:

[allied]
|
|-[soldier]
|
|-[acc] – accessory models and skin textures
|    |
|    |-backpack.md3 – backpack model
|    |-backpack.tga – backpack texture
|    |-helmet.md3 – helmet model
|    |-helmet.tga – helmet texture
|
|-body.mdm – the body mesh
|-body.tga – the body (torso) texture
|-legs.tga – the body (legs) texture
|-body_default.skin – the “default” body skin
|-head.md3 – the head model
|-head.tga – the head texture
|-head_default.skin – the “default” head skin

Note: only allied and axis as types of players were taken into consideration here. In case another party is added, like civilians, it can slot in next to the Allied and Axis directories.

Workflow
Through working with this model system, we’ve setup a set of procedures that makes getting the models into the game relatively fast and painless. First of all we created a MAX file that contains the base biped with a bunch of weighted dummy triangles around it to ensure every single bone that will ever be used in game is actually referenced. This MAX file has only 1 frame, frame 0, and this frame gets exported into a SKL file that is used to create the base MDX.

Next to that, there is a set of MAX files that contain our animations. These MAX files use the same dummy mesh as the base frame. Because MDX files in a set all must have exactly the same bone setup, this method ensures that that will be the case. These MAX files are then exported to SKL files ready for converting into MDX.

The last set of MAX files is the meshes. They are single frame and the biped setup is the animation frame used to create the collapse map for LOD.

To convert everything into MDM and MDX, a batch file and a file tree that mirrors the layout of the one used by the game are combined to make it all happen with one single run of the batch file.

The picture at the right shows the basic layout of the tree and a here is a little section from the batch file, that sits next to the BuildMDS executable in the ‘Player Models Exporting’ directory:

@echo off

echo Generating Base MDX
buildmds source/animations/human/base/base -mdx -destdir source/animations/human/base

echo Generating Human/Base animations
buildmds source/animations/human/base/body -mdx -destdir output/animations/human/base

echo Generating Temperate/Allied meshes
buildmds source/meshes/temperate/allied/cvops/body -mdm -destdir output/models/players/temperate/allied/cvops
buildmds source/meshes/temperate/allied/engineer/body -mdm -destdir output/models/players/temperate/allied/engineer
buildmds source/meshes/temperate/allied/fieldops/body -mdm -destdir output/models/players/temperate/allied/fieldops
buildmds source/meshes/temperate/allied/medic/body -mdm -destdir output/models/players/temperate/allied/medic
buildmds source/meshes/temperate/allied/soldier/body -mdm -destdir output/models/players/temperate/allied/soldier

Due to the width of this document the lines above might wrapped, but copying and pasting it into notepad will show the proper formatting. Just in case it doesn’t, every line starting with ‘buildmds’ takes two lines in this document but only one line in the batch file. It has the skl file listed on its line, the conversion type (-mdm or -mdx) and a destination directory.

The base MDX file sits in source/animations/human/base and all ski files should reference this file. By default, BuildMDS converts files only if there is a need for converting, which is the case if the source SKL is newer than the destination MDM or MDX. This check also applies to the base MDX. If it’s newer than the MDM or MDX that is dependant on it, then this will get re-converted.

Some Generic Hints and Tips
For efficiency and to ease maintenance it would be nice if every animation sequence got its own mdx file.

Multi Player and Single Player won’t have to duplicate their meshes and animation data anymore. They’ll use the same meshes and animation data will be referenced through characters and animation groups.

Because the animation logic behind human players will be the same, you should only ever need one single animation script for the whole human set. Custom animations can be played by combining the script with a different animation group.