The EZ-Mesh File Format
by
John W. Ratcliff
EZ-Mesh is a simple to use XML file format to define skeletal deformed meshes. It was designed by John W. Ratcliff and Stan Melax back in 2001. It is currently maintained by John W. Ratcliff. The design goals of EZ-Mesh were as follows:
- The file format should be self-documenting and extremely human readable. Simply take a look at EXPORT.EZM which is only 34 lines long yet specifies a skeleton, animation data, and mesh data in a single file. The same thing with COLLADA would be mind blowing in complexity.
- The source code necessary to read the file format should be small. All of the source necessary to import an EZmesh file is less than 1,000 lines of code; and that includes the entire XML parser! In contrast COLLADA uses libraries that are composed of literally hundreds of thousands of lines of source to do just the same thing.
- The file format should allow a user to easily simply 'fprintf' or 'stream out' the contents of arbitrary mesh data to a file on disk. Ez-mesh lets you do this.
- The file format should be able to very simply express skeletons, bones, animations, and a wide variety of vertex formats. Again, EZ-mesh does this and other formats do not.
- The source library should require no external dependencies, not on the STL, and not on any vector, matrix, or quaternion libraries. The header file 'MeshImport.h' provides a few simple helper math functions if necessary. All data is describes as simple arrays of floats.
If such a file format already existed, I would have used it. However, all current file formats capable of representing a deformed skeletal and animated mesh have substantial weaknesses.
A MeshImport library is available to developers to allow them to easily serialize and deserialize graphics files into and out of their projects. It is available in both source code form as well as a set of pre-built binary DLLs.
The project page for the MeshImport test framework, which provides simply the pre-compiled DLLs can be found on Google Code here.
The project page for the MeshImport libraries, including full source code, can be found on Google Code here.
And overview of existing file formats are as follows:
- COLLADA: As previously discussed, the COLLADA file format is outrageously complex. It requires massive source code libraries to load or save the content and, even then, the data object model is as complex as the file format itself. While the design goals of COLLADA are quite commendable, the resulting file format produced appears dramatically over engineered and difficult to use. Currently there is no MeshImport library for this format; though it would be nice to if someone would write one.
- Unreal PSK: This is the file format for the Unreal Engine from Epic. It is a binary file format so, therefore, is not human readable. It also places animation data in a separate binary file, with the extension of .PSA. This is a popular file format for which importers and exporters exists for both 3D Studio Max and Maya from Autodesk. The MeshImport library can handle this file format as well. The biggest drawback of this file format, other than the fact that it is binary and not human readable, is that it only supports one set of texture co-ordinates and no other vertex streams like for tangents and binormals. It is a viable format however.
- Ogre 3D : This file format is similar to Ez-mesh. It is a simple XML file format that provides all of the basic information necessary to manage a deformed skeletal mesh. Since it is in XML is it reasonably human readable. The animation data is stored in a separate file than the mesh data. The biggest problem with this file format is that it produces files which are massive in size. Ez-Mesh, by comparison, is much more compact. It also lacks all of the vertex interpolates that a person might want to include in their vertex data. This file format is supported by the MeshImport library.
- FBX: This file format is available from Autodesk and requires the use of a massive SDK. It produces files in both binary as well as ASCII format. The ASCII format produces massive files. The only way to access these files is via their large SDK library. The SDK library is extremely complex and difficult to use. A MeshImport library, however, is available for this format.
- DirectX .X files : This file format might be a viable format. However, the only way to load and save .X files is via the DirectX SDK and the DirectX D3DX utilities library. The format is available in both ASCII and binary, but due to the highly proprietary nature of the format probably not worth using. Microsoft provides no formal documentation for this format, nor do they provide a source code library to import and export the data. Currently there is no MeshImport library for this format; though it would be nice to if someone would write one.
- Granny .GR2 : Rad GameTools provides the most robust import and export path for 3D Studio Max and Maya for deformed skeletal animated meshes. However, these are part of a proprietary library called 'Granny' which is only used by professional game developers.
These are the main graphics file formats capable of representing a full skeletal deformed mesh with animation data. There are others, but none of them meet the basic design goals for Ez-Mesh.
Currently the biggest limitation with Ez-Mesh is that there are no importer or exporter plugins available in 3D Studio Max and Maya. While it is possible to export from Max and Maya in FBX, Ogre 3D, or Unreal PSK; all of which can be processed by the MeshImport plugins; there is no easy way to get the data back in again. I would be very pleased to find anyone who might be interested in writing an import/export path for the MeshImport libraries.
Originally I planned to create a formal XML schema file for EzMesh but I simply didn't have the time to learn how to use an XML Schema editing tool; or build one by hand. Since the Ez-Mesh format is, in fact, 'so easy' I decided to simply document it in a straightforward fashion in text.
Here is a complete list of the elements and attributes to be found in an EZ-Mesh file and an explanation of their purpose and meaning. (Elements are in bold; attributes are underlined.
- <MeshSystem asset_name="name" asset_info="info" mesh_system_version="1" mesh_system_asset_version="0"> : This is the root node element and declares as single 'MeshSystem' which is a collection of meshes, materials, skeletons, and animations.
- MeshSystem attributes:
- asset_name: The name associated with this overall asset.
- asset_info : An arbitrary additional 'information' as an ASCII string the developer wants to associate with this asset.
- mesh_system_version : The major version number of the MeshSystem; currently there is only one value which is '1'
- mesh_system_asset_version : The minor version number of the MeshSystem; currently there is only one value which '0'
- MeshSystem child elements: MeshAABB
- <MeshAABB min="-1,-1,-1" max="1,1,1">: This element defines an axis aligned bounding box (AABB). It is a child element of MeshSystem, Mesh, and MeshSection.
- MeshAABB attributes:
- min : Defines a vector which represents the minimum position of the AABB bounding volume.
- max : Defines a vector which represents the maximum position of the AABB bounding volume.
- <Skeletons count="1"> : This element defines the root node for the collection of skeletons in the overall MeshSystem
- Skeletons attribute
- count : This defines the number of skeletons contained in the overall MeshSystem.
- <Skeleton name="test" count="1"> : This element forms the root of a skeleton; which is a collection of related bones.
- Skeleton attributes
- name : This attribute declares the 'name' of this Skeleton.
- count : This attribute defines the number of bones to expect in this Skeleton.
- <Bone name="Bip01" parent="root_bone" orientation="0 0 0 1" position="0 0 0" scale="1 1 1"/> : The Bone element describes the name, parent, position, orientation, and scale of a single bone in a skeletal.
- Bone attributes
- name : Describes the name for this Bone.
- parent : Describes the name of the parent for this Bone. If the parent attribute does not exist, then it is assumed that this Bone has no parent.
- orientation : Describes the orientation of the Bone as a quaternion in the form of XYZW. This must be a unit quaternion. If this attribute is missing, the orientation is assumed to be identity.
- position : Describes the position of the Bone. If this attribute it missing, the position is assumed to be the origin at 0,0,0
- scale : Describes the optional scale of the Bone. If this attribute is missing, the scale is assumed to be 1,1,1
- <Animations count="1"> : This element acts as the root node for a collection of animation data.
- Animations attributes
- count : This attribute defines how many Animations are contained within the overall MeshSystem
- <Animation name="run" trackcount="4" framecount="60" duration="2" dtime="0.02"> : This element is the root node for a collection of animation tracks.
- Animation attributes:
- name : Describes the name of the Animation
- trackcount : The number of 'tracks' of Animation data. These correspond to individual bones in the original Skeleton. Not all bones necessarily have a track of Animation data.
- framecount : The number of frames of Animation. The Animation data is stored as 'key frames'; samples at specific time intervals over the duration of the overall Animation.
- duration : The overall duration of the Animation in seconds.
- dtime : The amount of time, in seconds, between one frame and the next. For example a dtime of 0.02 corresponds to 50 frames per second.
- <AnimTrack name="Bip01" count="60" has_scale="true"> : This element contains all of the data for a single track of animation.
- AnimTrack attributes:
- name : Describes the name of this track. Typically corresponds with a particular bone name in the source skeleton.
- count : Defines the number of frames of track data. This is almost always the same value as the 'trackcount' field in the element 'Animation'
- has_scale : This attribute has a value of either true or false, and defines whether or not the element data contains scale data or not.
- AnimTrack element DATA : The element data for AnimTrack contains is in one of two formats. If the 'has_scale' attribute is missing, or false, then it contains position and orientation. If the 'has_scale' attribute it true, then it contains position, orientation, and scale.
- Element Data without scale: Seven floating point numbers in the format of Position.x, Position.y, Position.z, Quaternion.x, Quaternion.y, Quaternion.z, and Quaternion.w repeated for the total number of tracks (count).
- Example: 0 0 0 0 0 0 1, ...
- Element Data with scale: Ten floating point numbers in the format of Position.x, Position.y, Position.z, Quaternion.x, Quaternion.y, Quaternion.z, Quaternion.w, Scale.x, Scale.y, and Scale.z repeated for the total number of tracks (count).
- Example: 0 0 0 0 0 0 1 1 1 1,
- See export.ezm or clothsim.ezm for examples.
- <Materials count="1"> : This element is the root node for the collection of materials contained within the overall MeshSystem
- Materials attributes:
- count : The number of materials contained within this element.
- <Material name="shiny" meta_data="diffuse=shiny.tga"> : This element describes a material. It is composed of a specific name and an arbitrary string of ASCII meta data that the application wants to preserve.
- Material attributes:
- name : The name of the material
- meta_data : An arbitrary string of data associated with this material that the application would like to preserve. There are no specific rules or restrictions about what this string contains; though it must be a valid string that can fit inside an attribute.
- <Meshes count="1"> : This element acts as the root node for the overall collection of meshes that may be contained in the overall MeshSystem
- Meshes attributes:
- count : The number of Meshes contained within the overall MeshSystem
- <Mesh name="dude" skeleton="test" submesh_count="1"> : This element defines the start of a single Mesh. A single mesh is composed of a collection of 'sub-meshes' as well as vertex data.
- Mesh attributes:
- name : The name of the Mesh
- skeleton : The name of the Skeleton which this mesh references
- submesh_count : The number of sub-meshes associated with this Mesh. (Each sub-mesh correlates to a unique material assignment.)
- <vertexbuffer count="2" ctype="fff fff x4 ff ff ff ff fff fff ffff hhhh f" semantic="position normal color texcoord1 texcoord2 texcoord3 texcoord4 tangent binormal blendweights blendindices radius">
- vertexbuffer attributes:
- count : The number of vertices contained in the vertex buffer.
- ctype : This attribute describes the format of the binary data which the source element data should be converted into for each vertex.
- f : 4 byte float
d : 4 byte integer
c : 1 byte character
b : 1 byte integer
h : 2 byte integer
p : const char * (converts string in the source data to a 'const char *'.
x1 : 1 byte hex
x2 : 2 byte hex
x4 : 4 byte hex
- semantic : The semantics associated with the vertex data elements. Valid semantics are as follows:
- position : Represents the 3d position of the vertex
- normal : Represents the vertex normal
- color : Represents a color component represented as 8 bit ARGB values; typically specified in hex.
- texcoord1 through texcoord4 : Up to 4 two component texture co-ordinates.
- tangent : Represents a tangent vector (3 float components)
- binormal : Representa binormal vector (3 float components)
- blendweights : Represents four weighting values for the vertex
- blendindices: Represents indices to four skeletal bones
- interp1 through interp8 : Represents up to 8 arbitrary interpolated vertex components with up to four components each.
- radius : Represents a single floating point value; typically used as a distance value for this vertex.
- vertexbuffer element data: The data for this element is an ASCII stream which describes all of the data contained in each vertex.
- <MeshSection material="TestMaterial"> : The MeshSection element marks the beginning of an portion of the triangle mesh which is rendered with a specific material.
- MeshSection attributes:
- material : This contains the name of a previously declared material. This is the material used to render the following collection of triangles represented by the indexbuffer.
- <indexbuffer triangle_count="1"> : This element declares an index buffer (as an indexed triangle list referenced against the previously defined vertex buffer)
- indexbuffer attributes:
- trianglecount : The number of triangles in the index buffer.
- indexbuffer element data : The element data is a set of integers representing the triangle indices.