# 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.

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.

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

In this case:

- `m_uiFaceSize` is 6 and
- `m_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.

Conversation saved
HOOPSY BETA

### Hello! I'm HOOPSY

Your multilingual generative AI assistant for documentation. Ask me anything about HOOPS Exchange in your own language, or choose a sample question below to start a conversation:

What is HOOPS Exchange?
What are the latest release notes for HOOPS Exchange?
How do I start evaluating HOOPS Exchange?
How do I write my first sample application?
How can I get assistance?

HOOPSY may store conversations according to OpenAI's policy. Responses may not always be accurate.

HOOPSY is thinking...