Getting Tessellation using A3DMeshData
This document presents the layout and usage of the A3DMeshData
.
This structure abstracts the tessellation mechanism presented in Reading Tessellation and is used in conjunction with the A3DRiComputeMesh()
function.
Topology
In the context of A3DMeshData
, a mesh is a set of x / y / z vertices.
Vertex Coordinates
Each vertex is located in 3D space using a triplet of values.
They are stored in m_pdCoords
as a flat list in which each sequential group of 3 values forms the coordinates of the same vertex.
The following table describes the content of m_pdCoords
for a unit-size cube containing 8 vertices.
The value in the Index column can be used in m_pdCoords
to get the X coordinate of each corresponding vertex.
Y and Z coordinates can be retrieved using respectively Index + 1 and Index + 2.
Vertex |
Index |
X |
Y |
Z |
---|---|---|---|---|
#0 |
0 |
0.0 |
0.0 |
0.0 |
#1 |
3 |
1.0 |
0.0 |
0.0 |
#2 |
6 |
1.0 |
1.0 |
0.0 |
#3 |
9 |
0.0 |
1.0 |
0.0 |
#4 |
12 |
0.0 |
0.0 |
1.0 |
#5 |
15 |
1.0 |
0.0 |
1.0 |
#6 |
18 |
1.0 |
1.0 |
1.0 |
#7 |
21 |
0.0 |
1.0 |
1.0 |
In this case, m_uiCoordSize
is 24 (3 x 8).
The following code example shows how to iterate through the vertices of an A3DMeshData
:
for (A3DUns32 v_index = 0 ; v_index < s_data.m_uiCoordSize ; v_index += 3) {
A3DDouble x = s_data.m_pdCoords[v_index];
A3DDouble y = s_data.m_pdCoords[v_index + 1];
A3DDouble z = s_data.m_pdCoords[v_index + 2];
}
Vertex Normals
Normal coordinates follow exactly the same layout organization as vertex coordinates.
m_pdNormals
is used to store the normal coordinates, and the size of the array is set in m_uiNormalSize
.
Faces and Triangles
A mesh is composed of m_uiFaceSize
faces.
Each face f is composed of m_puiTriangleCountPerFace[f]
triangles.
A single triangle is defined using 3 vertices stored in m_ppuiPointIndicesPerFace
.
m_ppuiPointIndicesPerFace[f]
is an array of vertex indices for the face f, where f is in the range [0 ; m_uiFaceSize
].
The first three indices make the first triangle of face f, second group of 3 makes the second triangle and so on.
The length of m_ppuiPointIndicesPerFace[f]
is then 3 * m_puiTriangleCountPerFace[f]
.
Each value of m_ppuiPointIndicesPerFace[f]
is an index used to retrieve the actual coordinates in m_pdCoords
.
Going back to the unit cube mentioned above. In our case, the cube has 8 faces, each made up of 2 triangles.
In this case:
m_uiFaceSize
is 6 andm_puiTriangleCountPerFace
is{2, 2, 2, 2, 2, 2}
.
m_ppuiPointIndicesPerFace
can then be represented like this:
Face |
Triangle |
Index [f][t] |
Vertex 0 |
Vertex 1 |
Vertex 2 |
---|---|---|---|---|---|
#0 |
#0 |
[0][0] |
0 |
1 |
2 |
#1 |
[0][3] |
0 |
2 |
3 |
|
#1 |
#0 |
[1][0] |
5 |
4 |
7 |
#1 |
[1][3] |
5 |
7 |
6 |
|
#2 |
#0 |
[2][0] |
4 |
0 |
3 |
#1 |
[2][3] |
4 |
3 |
7 |
|
#3 |
#0 |
[3][0] |
1 |
5 |
6 |
#1 |
[3][3] |
1 |
6 |
2 |
|
#4 |
#0 |
[4][0] |
3 |
2 |
6 |
#1 |
[4][3] |
3 |
6 |
7 |
|
#5 |
#0 |
[5][0] |
4 |
5 |
1 |
#1 |
[5][3] |
4 |
1 |
0 |
In this case, m_ppuiPointIndicesPerFace
is an array of 36 indices: 6 faces x 2 triangles x 3 indices.
Please note that, in our case, the computation of the size is simplified given that all faces have the same number of triangles.
The following code example iterates through each vertices, per triangle and per face:
// Iterate though each face
for (A3DUns32 face_i = 0; face_i < s_data.m_uiFaceSize; ++face_i) {
A3DUns32 n_triangles = s_data.m_puiTriangleCountPerFace[face_i];
printf("Face #%d (%d triangles):\n", face_i, n_triangles);
// Iterate through each triangle
for (A3DUns32 triangle_i = 0; triangle_i < n_triangles; ++triangle_i) {
printf("\t- Triangle #%d:\n", triangle_i);
// Iterate through each vertex
for (A3DUns32 vertex_i = 0; vertex_i < 3; ++vertex_i) {
A3DUns32 vertex_index = s_data.m_ppuiPointIndicesPerFace[face_i][triangle_i * 3 + vertex_i];
A3DDouble x = s_data.m_pdCoords[vertex_index];
A3DDouble y = s_data.m_pdCoords[vertex_index + 1];
A3DDouble z = s_data.m_pdCoords[vertex_index + 2];
printf("\t\t- Vertex #%d: {%f, %f, %f}\n", vertex_i, x, y, z);
}
}
}
Which, in the case our our unit-cube, would result the following output:
Face #0 (2 triangles):
- Triangle #0:
- Vertex #0: {0.0, 0.0, 0.0}
- Vertex #1: {1.0, 0.0, 0.0}
- Vertex #2: {1.0, 1.0, 0.0}
- Triangle #1:
- Vertex #0: {0.0, 0.0, 0.0}
- Vertex #1: {1.0, 1.0, 0.0}
- Vertex #2: {0.0, 1.0, 0.0}
... other faces ...
Normal Indices
Similarly, triangle normals are stored in m_ppuiNormalIndicesPerFace[f], which contains indices to use with m_pdNormals
.
The layout is exactly the same.
Texturing
Each face can be individually configured to hold any number of textures.
UV-coordinates
Each texture coordinate (also named uv-coord) is located in 2D space using a pair of values.
They are stored in m_pdTextureUV
as a flat list in which each sequential
group of 2 values form the coordinates of the same texture point:
The following table provides an example of 4 texture coordinates. Index corresponds to the index of the first coordinate (U) of each uv-coord. The V coordinate can be retrieved by offsetting from Index.
UV-Coord |
Index |
U |
V |
---|---|---|---|
#0 |
0 |
0.24 |
0.17 |
#1 |
2 |
0.73 |
0.54 |
#2 |
4 |
0.11 |
0.79 |
#3 |
6 |
0.95 |
0.67 |
In this case, m_uiTextureSize
is 8 (2 x 4).
The following code example shows how to iterate through the texture coordinates of an
A3DMeshData
:
for (A3DUns32 v_index = 0 ; v_index < s_data.m_uiTextureSize ; v_index += 2) {
A3DDouble u = s_data.m_pdTextureUV[v_index];
A3DDouble v = s_data.m_pdTextureUV[v_index + 1];
}
Faces and Textures
The number of textures on face F is stored in m_puiTextureCountPerFace[F]
.
This array can be set to 0 if the mesh data is not textured.
m_ppuiTextureUVIndicesPerFace[f] is an array of uv-coordinate indices for the face f, where f is in the range [0 ; m_uiFaceSize
].
The array provides sequential triplets of texture indices grouped by triangle, then by vertex, then by texture number.
This means that the length of m_ppuiTextureUVIndicesPerFace[f] is m_puiTextureCountPerFace[f] * 3 * m_puiTriangleCountPerFace[f]
.
The indices provided in m_ppuiTextureUVIndicesPerFace
are used to retrieve the actual uv-coordinates in m_pdTextureUV
.
Using the unit cube described above (6 faces, 2 triangles per face), the table below shows the content of m_ppuiTextureUVIndicesPerFace
if each face has exactly 2 texture.
The value in the Index column can be used in m_ppuiTextureUVIndicesPerFace
to get the uv-cooord index of the first texture (UV-Coord 0) of each corresponding vertex.
Index is then offset to get the uv-coordinates of other textures.
Face # |
Triangle # |
Vertex # |
Index |
UV-Coord 0 |
UV-Coord 1 |
---|---|---|---|---|---|
#0 |
#0 |
#0 |
[0][0] |
2 |
1 |
#1 |
[0][2] |
2 |
1 |
||
#2 |
[0][4] |
0 |
1 |
||
#1 |
#0 |
[0][6] |
0 |
2 |
|
#1 |
[0][8] |
0 |
2 |
||
#2 |
[0][10] |
0 |
2 |
||
#1 |
#0 |
#0 |
[1][0] |
1 |
0 |
#1 |
[1][2] |
1 |
0 |
||
#2 |
[1][4] |
1 |
0 |
||
#1 |
#0 |
[1][6] |
2 |
3 |
|
#1 |
[1][8] |
2 |
3 |
||
#2 |
[1][10] |
3 |
2 |
||
#2 |
#0 |
#0 |
[2][0] |
0 |
2 |
#1 |
[2][2] |
0 |
2 |
||
#2 |
[2][4] |
1 |
3 |
||
#1 |
#0 |
[2][6] |
2 |
1 |
|
#1 |
[2][8] |
2 |
1 |
||
#2 |
[2][10] |
1 |
0 |
||
#3 |
#0 |
#0 |
[3][0] |
3 |
0 |
#1 |
[3][2] |
3 |
0 |
||
#2 |
[3][4] |
2 |
1 |
||
#1 |
#0 |
[3][6] |
1 |
2 |
|
#1 |
[3][8] |
1 |
2 |
||
#2 |
[3][10] |
0 |
3 |
||
#4 |
#0 |
#0 |
[4][0] |
2 |
1 |
#1 |
[4][2] |
2 |
1 |
||
#2 |
[4][4] |
0 |
3 |
||
#1 |
#0 |
[4][6] |
1 |
2 |
|
#1 |
[4][8] |
1 |
2 |
||
#2 |
[4][10] |
3 |
0 |
||
#5 |
#0 |
#0 |
[5][0] |
0 |
3 |
#1 |
[5][2] |
0 |
3 |
||
#2 |
[5][4] |
2 |
1 |
||
#1 |
#0 |
[5][6] |
3 |
0 |
|
#1 |
[5][8] |
3 |
0 |
||
#2 |
[5][10] |
2 |
1 |
Since each face has two triangles (and 3 vertices per triangle), the total number of uv-coordinates per face is 12: 2 triangles x 3 vertices x 2 textures. The total number of uv-coordinates for the entire cube is then 72: 12 per face x 6 faces. Please note that, in our case, the computation of the size is simplified given that all faces have the same number of triangles and textures.
The following code example iterates through each uv-coord, per texture, per triangle and per face:
assert(s_data.m_puiTextureCountPerFace != 0); // Ensure the mesh has textures
// Iterate through each face
for (A3DUns32 face_i = 0; face_i < s_data.m_uiFaceSize; ++face_i) {
A3DUns32 n_triangles = s_data.m_puiTriangleCountPerFace[face_i];
printf("Face #%d (%d triangles):\n", face_i, n_triangles);
// Iterate through each triangle
for (A3DUns32 triangle_i = 0; triangle_i < n_triangles; ++triangle_i) {
printf("\t- Triangle #%d:\n", triangle_i);
// Iterate through each vertex
for (A3DUns32 vertex_i = 0; vertex_i < 3; ++vertex_i) {
printf("\t\t- Vertex #%d:\n", vertex_i);
// Iterate through each texture
for (A3DUns32 texture_i = 0; texture_i < s_data.m_puiTextureCountPerFace[face_i]; texture_i++) {
A3DUns32 uv_index = s_data.m_ppuiTextureUVIndicesPerFace[face_i][
(3 * s_data.m_puiTextureCountPerFace[face_i] * triangle_i) +
(s_data.m_puiTextureCountPerFace[face_i] * vertex_i) +
texture_i
];
A3DDouble u = s_data.m_pdTextureUV[uv_index];
A3DDouble v = s_data.m_pdTextureUV[uv_index + 1];
printf("\t\t\t- Texture #%d: {%f, %f}\n", texture_i, u, v);
}
}
}
}
Which, in the case our our unit-cube, would result the following output:
Face #0 (2 triangles):
- Triangle #0:
- Vertex #0:
- Texture #0: {0.11, 0.79}
- Texture #1: {0.73, 0.54}
- Vertex #1:
- Texture #0: {0.11, 0.79}
- Texture #1: {0.73, 0.54}
- Vertex #2:
- Texture #0: {0.24, 0.17}
- Texture #1: {0.73, 0.54}
- Triangle #1:
- Vertex #0:
- Texture #0: {0.24, 0.17}
- Texture #1: {0.11, 0.79}
- Vertex #1:
- Texture #0: {0.24, 0.17}
- Texture #1: {0.11, 0.79}
- Vertex #2:
- Texture #0: {0.24, 0.17}
- Texture #1: {0.11, 0.79}
... other faces ...
Styling
A3DMeshData
contains styling information for the entire mesh as well as per face.
Mesh and face style information are stored, respectively in m_uiStyleIndex
and m_puiStyleIndexPerFace
.
See Getting Global Style Information for more information about how to retrieve style information from style indexes.