Как можно улучшить код генерации подразделенного прямоугольника в OpenGL?

Мой код


class Face
{
public:
    std::vector<unsigned int> FaceIndices;
    std::vector<unsigned int> EdgeIndices;
};

template<typename Vector3D>
class Mesh
{

public:
    Mesh() = default;

    std::vector<Vector3D> vertices;
    std::vector<Face> faces;

};
using Vector3D = QVector3D
Mesh<Vector3D> MyGLWidget::generateSubdivCube(unsigned int subdivisions_w, unsigned int subdivisions_h, unsigned int subdivisions_d)
{
    Mesh<Vector3D> cube;
    Vector3D pos(0.0f, 0.0f, 0.0f);
    Vector3D size(1.0f * subdivisions_w, 1.0f * subdivisions_h, 1.0f * subdivisions_d);
    Vector3D startPoint((pos.x() - size.x())/2, (pos.y() - size.y())/2, (pos.z() - size.z())/2);

    Vector3D delta_z(0.0f, 0.0f, size.z() / subdivisions_d);
    Vector3D delta_x(size.x() / subdivisions_w, 0.0f, 0.0f);
    Vector3D delta_y(0.0f, size.y() / subdivisions_h, 0.0f);

    std::array<unsigned int, 4> borderBottom;
    /*Front Face*/
    for(size_t iteration = 0; iteration <= subdivisions_w; ++iteration)
    {
        cube.vertices.push_back(startPoint + (delta_x * iteration));
        for(size_t iteration = 0; iteration < subdivisions_h; ++iteration)
            cube.vertices.push_back(cube.vertices.back() + delta_y);
    }
    unsigned int columnStep = subdivisions_h + 1;
    auto pointStartIndex = 0;
    borderBottom[0] = 0;
    for(size_t column = 0; column < subdivisions_w; ++column)
    {
        for(size_t row = 0; row < subdivisions_h; ++row)
        {
            Face face;
            face.FaceIndices.push_back(column * columnStep + row + 0);
            face.FaceIndices.push_back(column * columnStep + row + 1);
            face.FaceIndices.push_back(column * columnStep + row + columnStep);

            face.FaceIndices.push_back(column * columnStep + row + columnStep);
            face.FaceIndices.push_back(column * columnStep + row + 1);
            face.FaceIndices.push_back(column * columnStep + row + columnStep + 1);

            face.EdgeIndices.push_back(column * columnStep + row + 0);
            face.EdgeIndices.push_back(column * columnStep + row + 1);

            face.EdgeIndices.push_back(column * columnStep + row + 1);
            face.EdgeIndices.push_back(column * columnStep + row + columnStep + 1);

            face.EdgeIndices.push_back(column * columnStep + row + columnStep + 1);
            face.EdgeIndices.push_back(column * columnStep + row + columnStep);

            face.EdgeIndices.push_back(column * columnStep + row + columnStep);
            face.EdgeIndices.push_back(column * columnStep + row + 0);

            cube.faces.push_back(face);
        }
    }


    ///*Right*/
    pointStartIndex = std::distance(cube.vertices.begin(), cube.vertices.end() - columnStep);
    borderBottom[1] = pointStartIndex;
    for(size_t iteration = 1; iteration <= subdivisions_d; ++iteration)
    {
        auto pointEnd = cube.vertices.size();
        pointStartIndex = std::distance(cube.vertices.begin(), cube.vertices.end() - columnStep);
        for(auto pointStart = pointStartIndex; pointStart < pointEnd; ++pointStart)
            cube.vertices.push_back(cube.vertices[pointStart] + delta_z);
    }

    for(size_t column = 0; column < subdivisions_d; ++column)
    {
        for(size_t row = 0; row < subdivisions_h; ++row)
        {
            Face face;
            face.FaceIndices.push_back(column * columnStep + row + borderBottom[1] + 0);
            face.FaceIndices.push_back(column * columnStep + row + borderBottom[1] + 1);
            face.FaceIndices.push_back(column * columnStep + row + borderBottom[1] + columnStep);

            face.FaceIndices.push_back(column * columnStep + row + borderBottom[1] + columnStep);
            face.FaceIndices.push_back(column * columnStep + row + borderBottom[1] + 1);
            face.FaceIndices.push_back(column * columnStep + row + borderBottom[1] + columnStep + 1);


            face.EdgeIndices.push_back(column * columnStep + row + borderBottom[1] + 0);
            face.EdgeIndices.push_back(column * columnStep + row + borderBottom[1] + 1);

            face.EdgeIndices.push_back(column * columnStep + row + borderBottom[1] + 1);
            face.EdgeIndices.push_back(column * columnStep + row + borderBottom[1] + columnStep + 1);

            face.EdgeIndices.push_back(column * columnStep + row + borderBottom[1] + columnStep + 1);
            face.EdgeIndices.push_back(column * columnStep + row + borderBottom[1] + 1);

            face.EdgeIndices.push_back(column * columnStep + row + borderBottom[1] + 1);
            face.EdgeIndices.push_back(column * columnStep + row + borderBottom[1] + 0);

            cube.faces.push_back(face);
        }
    }
    ///*Back*/
    pointStartIndex = std::distance(cube.vertices.begin(), cube.vertices.end() - columnStep);
    borderBottom[2] = pointStartIndex;
    for(size_t iteration = 1; iteration <= subdivisions_w; ++iteration)
    {
        auto pointEnd = cube.vertices.size();
        pointStartIndex = std::distance(cube.vertices.begin(), cube.vertices.end() - columnStep);
        for(auto pointStart = pointStartIndex; pointStart < pointEnd; ++pointStart)
            cube.vertices.push_back(cube.vertices[pointStart] - delta_x);
    }

    for(size_t column = 0; column < subdivisions_w; ++column)
    {
        for(size_t row = 0; row < subdivisions_h; ++row)
        {
            Face face;
            face.FaceIndices.push_back(column * columnStep + row + borderBottom[2] + 0);
            face.FaceIndices.push_back(column * columnStep + row + borderBottom[2] + 1);
            face.FaceIndices.push_back(column * columnStep + row + borderBottom[2] + columnStep);

            face.FaceIndices.push_back(column * columnStep + row + borderBottom[2] + columnStep);
            face.FaceIndices.push_back(column * columnStep + row + borderBottom[2] + 1);
            face.FaceIndices.push_back(column * columnStep + row + borderBottom[2] + columnStep + 1);


            face.EdgeIndices.push_back(column * columnStep + row + borderBottom[2] + 0);
            face.EdgeIndices.push_back(column * columnStep + row + borderBottom[2] + 1);

            face.EdgeIndices.push_back(column * columnStep + row + borderBottom[2] + 1);
            face.EdgeIndices.push_back(column * columnStep + row + borderBottom[2] + columnStep + 1);

            face.EdgeIndices.push_back(column * columnStep + row + borderBottom[2] + columnStep + 1);
            face.EdgeIndices.push_back(column * columnStep + row + borderBottom[2] + 1);

            face.EdgeIndices.push_back(column * columnStep + row + borderBottom[2] + 1);
            face.EdgeIndices.push_back(column * columnStep + row + borderBottom[2] + 0);
            cube.faces.push_back(face);
        }
    }
    //
    ///*Left*/
    pointStartIndex = std::distance(cube.vertices.begin(), cube.vertices.end() - columnStep);
    borderBottom[3] = pointStartIndex;
    for(size_t iteration = 1; iteration < subdivisions_d; ++iteration)
    {
        auto pointEnd = cube.vertices.size();
        pointStartIndex = std::distance(cube.vertices.begin(), cube.vertices.end() - columnStep);
        for(auto pointStart = pointStartIndex; pointStart < pointEnd; ++pointStart)
            cube.vertices.push_back(cube.vertices[pointStart] - delta_z);
    }

    for(size_t column = 0; column < subdivisions_d; ++column)
    {
        for(size_t row = 0; row < subdivisions_h; ++row)
        {
            Face face;
            if(column == subdivisions_d - 1)
            {
                face.FaceIndices.push_back(column * columnStep + row + borderBottom[3] + 0);
                face.FaceIndices.push_back(column * columnStep + row + borderBottom[3] + 1);
                face.FaceIndices.push_back(row);

                face.FaceIndices.push_back(row);
                face.FaceIndices.push_back(column * columnStep + row + borderBottom[3] + 1);
                face.FaceIndices.push_back(row + 1);

                face.EdgeIndices.push_back(column * columnStep + row + borderBottom[3] + 0);
                face.EdgeIndices.push_back(column * columnStep + row + borderBottom[3] + 1);

                face.EdgeIndices.push_back(column * columnStep + row + borderBottom[3] + 1);
                face.EdgeIndices.push_back(row + 1);

                face.EdgeIndices.push_back(row + 1);
                face.EdgeIndices.push_back(column * columnStep + row + borderBottom[3] + 1);

                face.EdgeIndices.push_back(column * columnStep + row + borderBottom[3] + 1);
                face.EdgeIndices.push_back(column * columnStep + row + borderBottom[3] + 0);
            }
            else
            {
                face.FaceIndices.push_back(column * columnStep + row + borderBottom[3] + 0);
                face.FaceIndices.push_back(column * columnStep + row + borderBottom[3] + 1);
                face.FaceIndices.push_back(column * columnStep + row + borderBottom[3] + columnStep);

                face.FaceIndices.push_back(column * columnStep + row + borderBottom[3] + columnStep);
                face.FaceIndices.push_back(column * columnStep + row + borderBottom[3] + 1);
                face.FaceIndices.push_back(column * columnStep + row + borderBottom[3] + columnStep + 1);


                face.EdgeIndices.push_back(column * columnStep + row + borderBottom[3] + 0);
                face.EdgeIndices.push_back(column * columnStep + row + borderBottom[3] + 1);

                face.EdgeIndices.push_back(column * columnStep + row + borderBottom[3] + 1);
                face.EdgeIndices.push_back(column * columnStep + row + borderBottom[3] + columnStep + 1);

                face.EdgeIndices.push_back(column * columnStep + row + borderBottom[3] + columnStep + 1);
                face.EdgeIndices.push_back(column * columnStep + row + borderBottom[3] + 1);

                face.EdgeIndices.push_back(column * columnStep + row + borderBottom[3] + 1);
                face.EdgeIndices.push_back(column * columnStep + row + borderBottom[3] + 0);
            }
            cube.faces.push_back(face);
        }
    }


    ///*Bottom*/
    pointStartIndex = 0; /*back*/
    unsigned int pointEndIndex = pointStartIndex + subdivisions_w * columnStep; /*back*/
    std::vector<unsigned int> bottomIndices;
    for(size_t idxBottom = 0; idxBottom < cube.vertices.size(); idxBottom += columnStep)
        bottomIndices.push_back(idxBottom);


    std::vector<unsigned int> topIndices;
    unsigned int pointStartIndexTop = 0 + columnStep - 1; /*back*/
    unsigned int pointEndIndexTop = pointStartIndexTop + subdivisions_w * columnStep; /*back*/
    for(size_t idxTop = pointStartIndexTop; idxTop < cube.vertices.size(); idxTop += columnStep)
        topIndices.push_back(idxTop);

    for(size_t iteration = 1; iteration < subdivisions_d; ++iteration)
    {
        for(auto pointStart = 0 + columnStep; pointStart < pointEndIndex; pointStart += columnStep)
        {
            cube.vertices.push_back(cube.vertices[pointStart] + iteration * delta_z);
            bottomIndices.push_back(cube.vertices.size() - 1);
        }
    }

    std::sort(bottomIndices.begin(), bottomIndices.end(), [&](auto a, auto b) { return cube.vertices[a] < cube.vertices[b]; });

    for(size_t column = 0; column < subdivisions_w; ++column)
    {

        for(size_t row = 0; row < subdivisions_d; ++row)
        {
            Face face;
            unsigned int columnStepZ = subdivisions_d + 1;
            face.FaceIndices.push_back(bottomIndices[column * columnStepZ + row + 0]);
            face.FaceIndices.push_back(bottomIndices[column * columnStepZ + row + 1]);
            face.FaceIndices.push_back(bottomIndices[column * columnStepZ + row + columnStepZ]);

            face.FaceIndices.push_back(bottomIndices[column * columnStepZ + row + columnStepZ]);
            face.FaceIndices.push_back(bottomIndices[column * columnStepZ + row + 1]);
            face.FaceIndices.push_back(bottomIndices[column * columnStepZ + row + columnStepZ + 1]);


            face.EdgeIndices.push_back(bottomIndices[column * columnStepZ + row + 0]);
            face.EdgeIndices.push_back(bottomIndices[column * columnStepZ + row + 1]);

            face.EdgeIndices.push_back(bottomIndices[column * columnStepZ + row + 1]);
            face.EdgeIndices.push_back(bottomIndices[column * columnStepZ + row + columnStepZ + 1]);

            face.EdgeIndices.push_back(bottomIndices[column * columnStepZ + row + columnStepZ + 1]);
            face.EdgeIndices.push_back(bottomIndices[column * columnStepZ + row + columnStepZ]);

            face.EdgeIndices.push_back(bottomIndices[column * columnStepZ + row + columnStepZ]);
            face.EdgeIndices.push_back(bottomIndices[column * columnStepZ + row + 0]);
            cube.faces.push_back(face);
        }
    }

    ///*Top*/

    for(size_t iteration = 1; iteration < subdivisions_d; ++iteration)
    {
        for(auto pointStart = pointStartIndexTop + columnStep; pointStart < pointEndIndexTop; pointStart += columnStep)
        {
            cube.vertices.push_back(cube.vertices[pointStart] + iteration * delta_z);
            topIndices.push_back(cube.vertices.size() - 1);
        }
    }

    std::sort(topIndices.begin(), topIndices.end(), [&](auto a, auto b) { return cube.vertices[a] < cube.vertices[b]; });

    for(size_t column = 0; column < subdivisions_w; ++column)
    {

        for(size_t row = 0; row < subdivisions_d; ++row)
        {
            Face face;
            unsigned int columnStepZ = subdivisions_d + 1;
            face.FaceIndices.push_back(topIndices[column * columnStepZ + row + 0]);
            face.FaceIndices.push_back(topIndices[column * columnStepZ + row + 1]);
            face.FaceIndices.push_back(topIndices[column * columnStepZ + row + columnStepZ]);

            face.FaceIndices.push_back(topIndices[column * columnStepZ + row + columnStepZ]);
            face.FaceIndices.push_back(topIndices[column * columnStepZ + row + 1]);
            face.FaceIndices.push_back(topIndices[column * columnStepZ + row + columnStepZ + 1]);


            face.EdgeIndices.push_back(topIndices[column * columnStepZ + row + 0]);
            face.EdgeIndices.push_back(topIndices[column * columnStepZ + row + 1]);

            face.EdgeIndices.push_back(topIndices[column * columnStepZ + row + 1]);
            face.EdgeIndices.push_back(topIndices[column * columnStepZ + row + columnStepZ + 1]);

            face.EdgeIndices.push_back(topIndices[column * columnStepZ + row + columnStepZ + 1]);
            face.EdgeIndices.push_back(topIndices[column * columnStepZ + row + columnStepZ]);

            face.EdgeIndices.push_back(topIndices[column * columnStepZ + row + columnStepZ]);
            face.EdgeIndices.push_back(topIndices[column * columnStepZ + row + 0]);
            cube.faces.push_back(face);
        }
    }

    size_t face_idx = 0;

    return cube;
}

Уточню вопрос, мне кажется, что генерация этого меша очень громоздкая и отвратительна, есть какие-нибудь идеи, как это сделать лучше? Единственный выход, который я вижу, это просто сделать функцию генерации одного полигона подразделенного и рисовать их 6 штук, таким образом формировать куб, но в этом подходе есть одна проблема -> дублирование соседних вершин, есть еще какие-нибудь идеи ?

Вот так выглядит генерируемый мною меш. Как такое генерируют нормальные люди? введите сюда описание изображения


Ответы (0 шт):