Qt Quick 3D - Custom Geometry Example

// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

import QtQuick
import QtQuick3D.Helpers

ProceduralMesh {
    property int rings: 50
    property int segments: 50
    property real radius: 100.0
    property real tubeRadius: 10.0
    property var meshArrays: generateTorus(rings, segments, radius, tubeRadius)
    positions: meshArrays.verts
    normals: meshArrays.normals
    uv0s: meshArrays.uvs
    indexes: meshArrays.indices

    function generateTorus(rings: int, segments: int, radius: real, tubeRadius: real) : var {
        let verts = []
        let normals = []
        let uvs = []
        let indices = []

        for (let i = 0; i <= rings; ++i) {
            for (let j = 0; j <= segments; ++j) {
                const u = i / rings * Math.PI * 2;
                const v = j / segments * Math.PI * 2;

                const centerX = radius * Math.cos(u);
                const centerZ = radius * Math.sin(u);

                const posX = centerX + tubeRadius * Math.cos(v) * Math.cos(u);
                const posY = tubeRadius * Math.sin(v);
                const posZ = centerZ + tubeRadius * Math.cos(v) * Math.sin(u);

                verts.push(Qt.vector3d(posX, posY, posZ));

                const normal = Qt.vector3d(posX - centerX, posY, posZ - centerZ).normalized();
                normals.push(normal);

                uvs.push(Qt.vector2d(i / rings, j / segments));
            }
        }

        for (let i = 0; i < rings; ++i) {
            for (let j = 0; j < segments; ++j) {
                const a = (segments + 1) * i + j;
                const b = (segments + 1) * (i + 1) + j;
                const c = (segments + 1) * (i + 1) + j + 1;
                const d = (segments + 1) * i + j + 1;

                // Generate two triangles for each quad in the mesh
                // Adjust order to be counter-clockwise
                indices.push(a, d, b);
                indices.push(b, d, c);
            }
        }
        return { verts: verts, normals: normals, uvs: uvs, indices: indices }
    }
}