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.

../../_images/a3dmeshdata_vertices.svg

A unit-length cube. The numbers corresponds to the indices in the below table.

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.

../../_images/a3dmeshdata_triangles.svg

In this model, all faces have exactly 2 triangles. Both triangles of the front face (#0) are highlighted.

In this case:

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.