Meshes are the visible representation of everything you see in a scene (with the exception of particle systems). Meshes are essentially made up of a set of vertex data, and then multiple submeshes which store index data into the vertex set.
The most common way to create a mesh is to load it from a supported file format. You can do this by calling load_mesh_from_file(...)
on an AssetManager
. You can optionally customise the loading of the file in a number of ways. Firstly you can provide a VertexSpecification
for the loaded mesh to use, which allows you to customise the format of the vertex attributes.
Secondly, you can pass a MeshLoadOptions
instance which provides a mechanism to specify additional options:
cull_mode
- this sets the default face culling mode for all materials created while loading the meshblending_enabled
- this defaults to true, but if set to false then all materials loaded will have blending forcibly disabledoverride_texture_extension
- This is useful if your mesh format specifies paths to textures, but you want to load a different format at runtime (e.g. a compressed texture)For various applications it's necessary to know which polygon edges are shared with other polygons, specifically this is used when calculating shadow volumes for stencil shadowing. By default all meshes maintain adjacency info unless disabled with Mesh::set_maintain_adjacency(false)
.
Meshes
are made up of Submeshes
. Conceptually, each Submesh
has its own material as well as the indices that make up the submesh (these are indices into the Mesh-level vertex data).
When creating a submesh you can optionally pass in an IndexDataPtr
or you can just pass the IndexType
and an IndexData
instance will be created for you. It's sometimes useful to share index data across submeshes
for memory reasons.
It's quite common to allow for the same mesh to be rendered with different materials, although duplicating the mesh is an option, doing so is not very memory efficient.
To solve this problem, each Submesh
has 8 material slots which can be selected by setting the active material slot on the Actor
. By default, everything uses MATERIAL_SLOT0
. Here's an example:
auto mesh = stage->assets->new_mesh_from_file("mymesh.obj"); // Assume this populates slot 0
// Change the material at slot 1 of the submesh
mesh->submesh("first")->set_material_at_slot(MATERIAL_SLOT1, other_material);
auto actor1 = stage->new_actor_with_mesh(mesh); // Uses the default material at slot 0
auto actor2 = stage->new_actor_with_mesh(mesh);
actor2->use_material_slot(MATERIAL_SLOT1); // actor2 now uses the other material
A mesh may optional have a skeleton assigned to it - this is normally created implicitly by loading a mesh file from a format that supports skeletal animation (e.g. .ms3d).
A skeleton contains a number of joints, and these joints are linked together to form bones. A joint has both a relative rotation + translation (to the parent) and an absolute rotation + translation.
You can find and manipulate a joint by it's name:
Joint* joint = mesh->skeleton->find_joint("neck");
neck->rotate_to(my_rotation);
neck->move_to(my_translation);
Finally, skeletons maintain a relationship from vertices to joints. You can link a vertex index to a joint by calling:
mesh->skeleton->attach_vertex_to_joint(joint, vertex_index, weight);
The vertex_index
should be an index into the mesh's vertex_data
array. weight
should be a value between 0.0 and 1.0. The total weights for a vertex should add up
to 1.0.
Simulant has built-in support for building heightmap terrain meshes from textures. You can create a heightmap terrain using the new_mesh_from_heightmap
method on the AssetManager
.
When a Mesh
has been created from a heightmap, the mesh gains a TerrainData
attribute in its data
:
auto data = mesh->data->get<TerrainData>("terrain_data");
This struct provides information about how the heightmap was generated, for example its grid spacing, min/max heights etc. TerrainData
also provides some utility functions:
TerrainData::height_at_xz(float x, float z)
- Returns the Y coordinate at the position specified. Returns an optional<float>
which will be "falsey" if the coordinate was outside the terrainTerrainData::triangle_at_xz(float x, float z)
- Returns the 3 indexes of the triangle at the given coordinate. Returns an optional