Skip to content

Model Factory

Detail
Interface IModelFactory
Availability Client and Server
Docs IModelFactory

Description

Models are in-game representation of meshes. Empeld supports a few different model formats, an internal format (the Mesh object), as well as a hybrid format (MML or model-markup-language, an XML document)

Supported Formats

Format Extension Description
Wavefront Object .obj Almost all features, with an extension called serb (Read More Below)
Milkshape 3D (MS3D) ms3d A common format for animated meshes that supports skeletal animation
Model Markup Language mml Combine multiple meshes into a hybrid mesh with attachment points
Text A "Text" or Billboard object to display in-game 3D text
Mesh A programatically generated mesh via code (Or you can write your own loader)
  • Wavefront Obj files
  • Milkshape 3D Objects (Including Skeletal Animations)
  • MML (Model Markup Language) -- More Below
  • Text / Billboards
  • Custom Mesh Object (Runtime generated meshes)

Formats

Wavefront Object

Supports standard Wavefront Object, including an extension called SERB (See below)

To add a SERB texture, in the mtl file, simply add:

map_Kd texture.png
map_serb texture.serb.png

Milkshape 3D

Supports MS3D models, including skeletal animations. Use XML to load animation frames into the model. For instance:

<?xml version="1.0" encoding="utf-8"?>
<model src="peasant_anim_01.ms3d"> <!-- Load a model -->
    <animation src="peasant.frames"> <!-- Load frame format -->
        <sequence name="test" start="0" end="100" fps="24" />
    </animation>
    <groups default="false">
        <group name="body_01" visible="true" />
        <group name="hand_01" visible="true" />
        <group name="head_01_01" visible="true" />
        <group name="pants_05" visible="true" />
        <group name="shoes_03" visible="true" />
        <group name="beard_01_02" visible="true" />
        <group name="hair_03" visible="true" />
    </groups>
    <transform>
        <rotate x="90" />
        <scale x="1.1" y="1.1" z="1.1" />
    </transform>
</model>

Model Markup Language (XML)

Model XML is a way of specifying special load attributes for a specific model without modifying the model directly in an editor. This can be particularly useful if you want to define custom animations or groups in the model format. It can also be used if you need to scale or rotate the model before using it in the game.

There are two flavors:

  • Model: Starts with <model> tag, and describes a single model
  • Assembly: Starts with <assembly> tag, and can combine one or more models into a "model assembly", where indepenty parts have visiblity and transforms.

Model XML

<?xml version="1.0" encoding="utf-8"?>
<model src="peasant_anim_01.ms3d">
    <animation src="peasant.frames">
        <sequence name="test" start="0" end="100" fps="24" />
    </animation>
    <groups default="false">
        <group name="body_01" visible="true" />
        <group name="hand_01" visible="true" />
    </groups>
    <transform>
        <rotate x="90" />
        <scale x="1.1" y="1.1" z="1.1" />
    </transform>
</model>

Assembly XML

In Assembly XML, each part is a "group", which can be manipulated (transformed) in-game via the model instance. This allows, for example, rotating an independent turret on a vehicle.

A note on attachments: There are two modes for attachments:

  • absolute="false" (default): This assumes that the sub-component is already at (0,0,0), and wants to be attached to a base component at a location
  • absolute="true": This assumes the mesh is already at the "right" location. Effectively, this does two things:
    • Add a translate transform to the front of the list that moves the mesh by (-x, -y, -z) to center it before any transforms are applied
    • Subtract all sub-components attachment locations from the (x,y,z) specified, moving the attachment to be relative to any sub-components
<?xml version="1.0" encoding="utf-8"?>
<assembly>
    <component name="base">
        <model src="Laser_1.obj"> <!-- Load a model -->
            <groups default="false"> <!-- All groups in the model are not visibly by default -->
                <group name="Laser_1_Base_Cylinder.163" visible="true" /> <!-- Except this one group, which is visible -->
            </groups>
        </model>
    </component>

    <!-- Middle -->
    <component name="tower">
        <attach to="base" x="0" y="0" z="0.16" absolute="true" /> <!-- Attaches this sub-group of the same model to the base. Inherits transforms -->
        <model src="Laser_1.obj">
            <groups default="false">
                <group name="Laser_1_Mid_Cylinder.248" visible="true" />
            </groups>
        </model>
    </component>

    <!-- Gun -->
    <component name="turret">
        <attach to="tower" x="0" y="0" z="1.51" inheritTransform="false" absolute="true" />
        <model src="Laser_1.obj">
            <groups default="false">
                <group name="Laser_1_Gun_Cylinder.250" visible="true" />
            </groups>
            <!-- Transform just this part -->
            <transform>
                <!-- NOTE: Because absolute=true in attach, the model will be transformed to 0,0,0 first, meaning it will rotate at 0,0,0 -->
                <rotate z="180" />
            </transform>
            <labels>
                <label name="bsrc" x="0" y="1.45" z="0" transform="false" />
                <label name="height" x="0" y="0" z="0" transform="false" />
            </labels>
        </model>
    </component>

    <!-- Global transform, applie to model as a whole -->
    <transform>
        <scale xyz="1.25" />
    </transform>
</assembly>

Mesh

Mesh objects are created programatically as a series of Triangles and attributes on those triangles.

See Mesh

Extensions

XML Frames Format

Animation frames can be given a name via either XML or a "frames file" format.

A frames file looks like this:

# A comment
# StartFrame EndFrame Name
123 590 walk

SERB

SERB is a way to add more detail to a texture by giving it different material values. In-order maps to RGBA: Specular (R), Emiitence (G), Reflective (B), Bump (A).

For RGB, each value is interpretted as greyscale, and maps to "power". 0 is "none", 255 is "full".

For Bump (A), it is interpreted as "height", and a normal is computed based on its neighbor's values.