Как можно улучшить код генерации подразделенного прямоугольника в 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 штук, таким образом формировать куб, но в этом подходе есть одна проблема -> дублирование соседних вершин, есть еще какие-нибудь идеи ?
Вот так выглядит генерируемый мною меш. Как такое генерируют нормальные люди?
