Creating Meshes
Meshes are representations of the static physical objects that make up the geometry
of your game world: buildings, ground, trees, lampposts, etc. Each mesh is like an
abstract definition or blueprint for its geometry that you place in your scenes by
creating instances with specific translations and rotations in the global space of
the scene.
Each mesh is created by the Beast Manager and maintained on its own in the cache. Therefore, each mesh can be instantiated
as many times as necessary in any scene that can access that cache, without increasing
the amount of memory needed.
All meshes in Beast use triangles as primitives. If you use a different primitive for the geometry in
your game, you are responsible for tesselating it into triangles before providing
the triangles to Beast.
About triangles and materials
Each triangle that you add to a mesh is created with a material, which you specify
only by name. When you create the mesh, you do not yet set up any properties for its
materials (like their color, reflectiveness, specularity, etc.). Later, when you instantiate
the mesh in a scene, you will need to create materials within that scene whose names
match the names of the materials you specified when adding your triangles to the mesh.
The materials themselves are stored within the scenes that use them.
This indirect approach to specifying materials has the benefit of allowing you to
re-use the same mesh in different scenes while changing the way light reacts to the
surface of the mesh in each scene. However, it has the disadvantage that Beast has no way to validate at the time the mesh is created that the named materials will
actually exist in the scene at the time the mesh is used. It is your responsibility
to ensure that you set up your scene with a set of materials whose names match the
names of all materials used in your meshes.
You can also override the material groups in your mesh for each instance that you
create. See also Creating Mesh Instances.
Setting up a mesh
To create a mesh:
- Create a new ILBMeshHandle.
- Initialize the handle by calling ILBBeginMesh(). In your call, you have to specify the Beast Manager that will be responsible for creating and managing the mesh.
- Add vertices and their normals to the mesh by calling ILBAddVertexData(). You can call this method multiple times to add vertices in batches; this can help
to reduce temporary memory consumption.
- Add triangles to your mesh. You add triangles in batches called material groups, each
of which collects together multiple triangles that share the same material. To add
a material group:
- Create the material group by calling ILBBeginMaterialGroup(). In your call, you need to specify the name of the material that you want to apply
to the triangles you add.
- Add triangles to the group by calling ILBAddTriangleData(). In your call, you need to provide the indices of the vertices that make up the triangles.
These indices refer back to the array of vertices you added to the mesh in your calls
to ILBAddVertexData(). You can call this method multiple times to add triangles in batches; this can help
to reduce temporary memory consumption.
- When you are finished adding triangles with the current material, call ILBEndMaterialGroup().
- While your mesh is open, you can also add other optional data described in the following
sections: UV layers, vertex colors, and tangents/bitangents. You can add these optional
groups in any order, but you must end each group before you create another.
Note that if you plan to bake the lighting for your mesh to a texture, you must create
at least one UV layer to tell Beast how to lay out the triangles of the mesh in 2D
space.
- Finalize the mesh handle by calling ILBEndMesh(). Once you have finalized the mesh, you can no longer modify it, but it will be ready
for instantiation in your scenes.
For example, the following code creates a simple mesh:
// Create the mesh
ILBBeastMesh mesh;
ILBBeginMesh(bm, _T("MyMesh"), &mesh);
// Add a batch of vertices and normals
ILBAddVertexData(mesh, points, normals, pointCount);
// Add a batch of triangles with the "Wood" material
ILBBeginMaterialGroup(mesh, "Wood");
ILBAddTriangleData(mesh, vertexIndices_wood, vertexCount_wood);
ILBEndMaterialGroup(mesh);
// Add a second batch of triangles with a different material
ILBBeginMaterialGroup(mesh, "Steel");
ILBAddTriangleData(mesh, vertexIndices_steel, vertexCount_steel);
ILBEndMaterialGroup(mesh);
... // Add optional data (see the following sections)
// Close the mesh
ILBEndMesh(mesh);
Adding UV layers
A UV layer, or UV set, is a customized mapping of each vertex in your mesh into two-dimensional
UV space. When you create a texture target or an atlased texture target for a mesh
instance, the UV layer is used to determine how the triangles in the 3D mesh get laid
out in the 2D texture.
If you plan to bake the lighting for your mesh to a texture, you must set up at least
one UV set. In some circumstances, you may want to set up additional UV layers for
special effects.
- By controlling the way your UV layer maps your mesh to 2D space, you can customize
the relative resolution of the lightmap for different areas of the mesh. You can create
your mapping such that the triangles that need more lighting detail occupy larger
areas of the UV space relative to the triangles that need less detail.
- If your runtime engine has any special requirements for the way it applies UV maps
to mesh instances, your UV layer will need to respect those requirements so that your
engine will be able to apply the textures created by Beast.
- UV layers also allow you to send information from selected material channels to different
output textures. For example, you could send the diffuse color of a mesh instance
to one UV layer, and its specular color to another UV layer. Those UV layers can then
be rendered to different textures with different resolutions or different layouts.
To create a UV layer:
- While your mesh is open, create the UV layer by calling ILBBeginUVLayer(). In your call, you need to specify a name for the layer.
- Call ILBAddUVData() to provide the 2D UV coordinates for each vertex that you added to your mesh in your
original calls to ILBAddVertexData(). You must specify the UV coordinates in the same order you added the vertices. You
can call ILBAddUVData() multiple times to add coordinates in batches; this can help to reduce temporary memory
consumption.
- When you have provided UV coordinates for each vertex in the mesh, you can close the
UV layer by calling ILBEndUVLayer(). This call will only succeed if you have provided coordinates for each vertex.
For example:
Adding vertex colors
You can specify an RGBA color for each vertex in your mesh.
- You can use these colors to provide the color for a particular channel in a material.
See ILBSetMaterialUseVertexColors().
- These colors will also be taken into account if you bake a vertex target for an instance
of this mesh.
To add a layer of vertex colors:
- While your mesh is open, create the color layer by calling ILBBeginColorLayer(). In your call, you need to specify a name for the layer.
- Call ILBAddColorData() to provide the color for each vertex that you added to your mesh in your original
calls to ILBAddVertexData(). You must specify the colors in the same order you added the vertices. You can call
ILBAddColorData() multiple times to add colors in batches; this can help to reduce temporary memory
consumption.
- When you have provided the color for each vertex in the mesh, you can close the color
layer by calling ILBEndColorLayer(). This call will only succeed if you have provided a color for each vertex.
For example:
Adding tangents and bitangents
Some types of render passes, notably the RNM pass, require your meshes to be set up
with tangents and bitangents.
To add tangent and bitangent information:
- While your mesh is open, open the tangent data layer by calling ILBBeginTangents().
- Call ILBAddTangentData() to provide the tangent and bitangent for each vertex that you added to your mesh
in your original calls to ILBAddVertexData(). You must specify the data in the same order you added the vertices. You can call
ILBAddTangentData() multiple times to add data in batches; this can help to reduce temporary memory consumption.
- When you have provided the tangent and bitangent for each vertex in the mesh, you
can close the tangent data layer by calling ILBEndTangents(). This call will only succeed if you have provided a tangent and a bitangent for each
vertex.
For example:
Thread safety
You can create multiple different meshes simultaneously in multiple threads. In addition,
multiple threads can find meshes in the cache and use them simultaneously. However,
only one thread should add data to any given mesh at any time; therefore, each mesh
should be created entirely within a single thread and not split across multiple threads.
Related API functions
API functions related to the creation and setup of meshes are declared in the beastmesh.h file.