Programming
Fundamentials
Setting Up Development Environment
UnigineScript
High-Level Systems
C++
C#
UUSL (Unified UNIGINE Shader Language)
File Formats
Rebuilding the Engine and Tools
GUI
Double Precision Coordinates
API
Bounds-Related Classes
Containers
Controls-Related Classes
Core Library
Engine-Related Classes
GUI-Related Classes
Node-Related Classes
Pathfinding-Related Classes
Physics-Related Classes
Plugins-Related Classes
Rendering-Related Classes
Utility Classes

Mesh Class

The Mesh class provides an interface for mesh loading, manipulating and saving.

By using this class, you can create a mesh, add geometry to it (e.g. box, plane, capsule or cylinder surface), add animations and bones (if you want to create a skinned mesh) and then use it to create the following objects:

Features of the mesh are listed below:

  • Each surface of the mesh supports several morph targets.
  • Each surface has a quaternion-based tangent basis for the better loading speed.
  • 8-bit vertex colors are supported.
  • Each vertex of a surface has 2 sets of indices: coordinate and triangle indices. It improves the loading speed and reduces data duplicating.
  • Each vertex of a surface has 2 UV sets.
  • A bind pose transformation is stored for each mesh (even if there are no animations and animation frames). See also the getBoneTransfroms() function.
    Notice
    The 1st animation frame should not contain the bind pose.

Vertex Indices

Each vertex stores information about its position, normal, binormal, tangent and texture coordinates. There are 2 separate vertex buffers:

  • CVertices coordinate buffer which stores only vertex coordinates.
  • TVertices triangle buffer which stores vertex attributes such as normal, binormal, tanget, color, UV coordinates.

On the picture below, arrows are used to show normals:

Surface that contains 2 adjacent triangles. Here C0...C4 are coordinate vertices, T0...T5 are triangle vertices

The coordinate buffer is an array of coordinate vertices. In order to reduce data duplication, vertices of surface which have the same coordinates are saved only once in the buffer. For example, the coordinate buffer for the surface presented on the picture above is the following:

Output
CB = [C0,C1,C2,C3]
Each polygon of the surface has 3 coordinates. We have 2 polygons, thus, we have 6 vertices, but we save in the CVertices buffer only 4, because 2 of them have the same coordinates. Each coordinate vertex contains coordinates (float[3]) of the vertex.
Notice
The number of vertices and coordinate vertices is equal.

The triangle buffer is an array of triangle vertices. For example, the triangle buffer for the surface presented on the picture above is the following:

Output
TB = [T0,T1,T2,T3,T4,T5]
Each triangle vertex can store:
  • Normal
  • Binormal
  • Tangent
  • 1st UV map texture coordinates
  • 2nd UV map texture coordinates
  • Color
Notice
The number of vertices and triangle vertices can be different.
The number of triangle vertices depends on the number of triangles, to which the vertex belongs. For example, if 2 triangles have 1 adjacent vertex with different normals for each triangle, 2 triangle vertices will be stored (the 1st and the 3rd vertices on the picture above). However, if the components are the same for all of the adjacent triangles, only 1 triangle vertex will be stored.

Both the coordinate and triangle vertices have indices. There are 2 index buffers to get proper cvertex and tvertex data for each triangle of the mesh:

  • CIndex buffer — coordinate indices which are links to cvertices.
  • TIndex buffer — triangle indices which are links to tvertices.
By using indices, you can get proper cvertex and tvertex data for each mesh triangle.

Coordinate Indices

Each coordinate vertex has a coordinate index. The number of coordinate indices is equal to 3*number of triangles. For the given surface the array of the coordinate indices is the following:

Output
CIndices = [Ci0,Ci1,Ci3,Ci1,Ci2,Ci3]
Here:
  • The first 3 elements are the coordinate indices of the first (bottom) triangle.
  • The second 3 elements are the coordinate indices of the second (top) triangle.

Triangle Indices

Each triangle vertex has a triangle index. The number of triangle indices is equal to 3*number of triangles. For the given surface the array of the triangle indices is the following:

Output
TIndices = [Ti0,Ti1,Ti5,Ti2,Ti3,Ti4]
Here:
  • The first 3 elements are the triangle indices of the first (bottom) triangle.
  • The second 3 elements are the triangle indices of the second (top) triangle.

Notice
The number of the coordinate and triangle indices is equal.

See Also

Copying a Mesh into Another

You can copy a mesh into another by using the Mesh class.

In the following example, we copy the ObjectMeshDynamic mesh to the new ObjectMeshDynamic class instance by using the Mesh class as a container. The executing sequence is the following:

  • It is supposed that you already have an ObjectMeshDynamic to copy. Create the Mesh class instance as a container for the ObjectMeshDynamic mesh.
  • Copy the ObjectMeshDynamic mesh to the Mesh by using the getMesh() function.
  • Create a new ObjecteMeshDynamic instance from the Mesh by using overloaded constructor of the ObjectMeshDynamic class.

Source code(UnigineScript)
/* ... */
// create ObjectMeshDynamic and Mesh instances
ObjectMeshDynamic dynamicMesh = new ObjectMeshDynamic();
Mesh firstMesh = new Mesh();

// get the ObjectMeshDynamic and copy it to the Mesh class instance
dynamicMesh.getMesh(firstMesh);

// create a new ObjectMeshDynamic instance from the firstMesh mesh
ObjectMeshDynamic dynamicMesh_2 = new ObjectMeshDynamic(firstMesh);
/* ... */

Also you can copy the mesh by using the setMesh() function. For example, in the code below we set the mesh instance to the already created ObjectMeshDynamic mesh. The executing sequence is the following:

  • It is supposed that you already have 2 ObjectMeshDynamic class instances. Create the Mesh class instance as a container.
  • Copy the ObjectMeshDynamic to the Mesh by using the getMesh() function.
  • Set the mesh to the second ObjectMeshDynamic instance by using setMesh() function.
Source code(UnigineScript)
/* ... */
// create ObjectMeshDynamic instances 
ObjectMeshDynamic dynamicMesh = new ObjectMeshDynamic();
ObjectMeshDynamic dynamicMesh_2 = new ObjectMeshDynamic();

// create Mesh instances
Mesh firstMesh = new Mesh();

// get the ObjectMeshDynamic and copy it to the Mesh class instance
dynamicMesh.getMesh(firstMesh);

// put the secondMesh mesh to the dynamicMesh_2 instance
dynamicMesh_2.setMesh(firstMesh);
/* ... */
Notice
You can return the transformed mesh from the Mesh class to the same ObjectMeshDynamic instance without creating a new one.

You can easily copy one mesh instance to a new one by using the constructor and pass the mesh instance as an argument:

Source code(UnigineScript)
Mesh firstMesh = new Mesh();
Mesh secondMesh = new Mesh(firstMesh);

Copying Surfaces of the Mesh

By using the Mesh class you can copy surfaces from one mesh to another.

In the following example we create two meshes with different surfaces. The first mesh has the capsule surface, the second has the box surface. We copy the box surface from the second mesh to the first. The executing sequence is:

  • Create 2 Mesh class instances and add surfaces to them.
  • Add the box surface from the mesh_2 mesh and add it to the mesh_1 mesh by using the addMeshSurface() function.
  • Create the new ObjectMeshDynamic mesh from the mesh_1 instance.
  • Add the dynamic mesh to the editor and set the material, property and name.
Source code(UnigineScript)
// create mesh instances
Mesh mesh_1 = new Mesh();
Mesh mesh_2 = new Mesh();

// add surfaces for the added meshes
mesh_1.addCapsuleSurface("capsule_surface", 1.0f, 2.0f, 200, 100);
mesh_2.addBoxSurface("box_surface", vec3(2.2));

// add the surface from the mesh_2 to the mesh_1 as a new surface
// with the name "new_box_surface"
mesh_1.addMeshSurface("new_box_surface", mesh_2, 0);

// create the ObjectMeshDynamic from the mesh_1 object
ObjectMeshDynamic dynamicMesh = new ObjectMeshDynamic(mesh_1);

// add dynamicMesh to the editor as a Node object
engine.editor.addNode(node_remove(dynamicMesh));

// set the position of the mesh
dynamicMesh.setWorldTransform(translate(Vec3(10.0f,10.0f,10.0f)));
// set the material to the mesh
dynamicMesh.setMaterial("mesh_base","*");
// set the property to the mesh
dynamicMesh.setProperty("surface_base","*");
// set the name of the mesh
dynamicMesh.setName("Dynamic Mesh");
Notice
You can copy a surface from the source mesh and add it to the existing surface of the current mesh without creating a new one.

The ObjectMeshDynamic mesh will appear in the editor:

Adding Vertices and Changing Their Attributes

You can change the attributes of the vertex by using the Mesh class.

In the following example, we create a plane by adding vertices to the mesh and change the attributes of some of these vertices. Let's clarify this:

  • Create the Mesh class instance and add 4 vertices to it.
  • Add 6 indices to create a plane.
  • After that tangents and normals are created by using the createTangents() and createNormals() functions.
  • Current values of normal of the 2 vertices are shown in console. After changing, new values and shown in console.
  • Tangent is shown in the console, and then it is changed and shown in the console again.
  • Create the new ObjectMeshDynamic mesh from the mesh instance.
  • Add the dynamic mesh to the editor and set the material, property and name.
Source code
// create a mesh instance
Mesh mesh = new Mesh();

// add a new surface
mesh.addSurface("surface_0");
 
// add vertices of the plane
mesh.addVertex(vec3(0.0f,0.0f,0.0f),0);
mesh.addVertex(vec3(0.0f,0.0f,1.0f),0);
mesh.addVertex(vec3(0.0f,1.0f,0.0f),0);
mesh.addVertex(vec3(0.0f,1.0f,1.0f),0);

// add indices 
mesh.addIndex(0,0);
mesh.addIndex(1,0);
mesh.addIndex(2,0);

mesh.addIndex(3,0);
mesh.addIndex(2,0);
mesh.addIndex(1,0);

// create tangents
mesh.createTangents();

// create normals
mesh.createNormals(0);

// show the message in console about the normals of the first
// and the second normal before changing
log.message("the first normal is: %s and the second is: %s\n", typeinfo(mesh.getNormal(0, 0, 0)), typeinfo(mesh.getNormal(1, 0, 0)));

// set the new value of the normals
mesh.setNormal(0, vec3(1,1,0), 0, 0);
mesh.setNormal(1, vec3(1,1,1), 0, 0);

// show the normals value in the console
log.message("the first normal is: %s and the second is: %s\n", typeinfo(mesh.getNormal(0, 0, 0)), typeinfo(mesh.getNormal(1, 0, 0)));

// show the tangent value in the console
log.message("tangent is: %s\n", typeinfo(mesh.getTangent(0,0,0)));

// set the new value of the tangent
mesh.setTangent(0, quat(0.0,-0.0,-0.0,1), 0,0);

// show the tangent value after the changing the value
log.message("tangent is: %s\n", typeinfo(mesh.getTangent(0,0,0)));

// create the ObjectMeshDynamic from the Mesh object
ObjectMeshDynamic dynamicMesh = new ObjectMeshDynamic(mesh);

// add dynamicMesh to the editor as a Node object
engine.editor.addNode(node_remove(dynamicMesh));

// set the position of the mesh
dynamicMesh.setWorldTransform(translate(Vec3(10.0f,10.0f,10.0f)));
// set the material to the mesh
dynamicMesh.setMaterial("mesh_base","*");
// set the property to the mesh
dynamicMesh.setProperty("surface_base","*");
// set the name of the mesh
dynamicMesh.setName("new_mesh");

When you launch the project, in the console you'll see the following:

Output
the first normal is: vec3: -1 0 0 and the second is: vec3: -1 0 0
the first normal is: vec3: 1 1 0 and the second is: vec3: 1 1 1
tangent is: quat: 0.5 -0.5 -0.5 0.5
tangent is: quat: 0 0 0 0.999962

After when setTangent() and setNormal() function were called, the normal and the tangent changed their values.

Let's comment this part of code:

Source code(UnigineScript)
// show the tangent value in the console
log.message("tangent is: %s\n", typeinfo(mesh.getTangent(0,0,0)));

// set the new value of the tangent
mesh.setTangent(0, quat(0.0,-0.0,-0.0,1), 0,0);

// show the tangent value after the changing the value
log.message("tangent is: %s\n", typeinfo(mesh.getTangent(0,0,0)));
The result will be different. You can see what influence the tangent has on the vertex: on the left is the plane with changed tangent, on the right is the plane with unchanged tangent.

Last update: 2017-07-03