У меня есть функция, которая возвращает QPolygonF, который мне нужно нарисовать и заполнить каким-нибудь цветом. Гугл выдал функцию отрисовки линии, основанную на OpenGL, которую я поменял на отрисовку LinesLoop.
Есть какой-то более изящный способ рисовки? Или нужно именно через OpenGL рисовать такие вот полигончики? Как можно закрасить этот LinesLoop или надо что-то другое использовать?
void MainWindow::drawPolygon(const QPolygonF polygon, QColor color, Qt3DCore::QEntity *_rootEntity)
{
int numOfVertices = polygon.size();
auto *geometry = new Qt3DRender::QGeometry(_rootEntity);
// position vertices
QByteArray bufferBytes;
bufferBytes.resize(3 * numOfVertices * static_cast<int>(sizeof(QPointF)));
float *positions = reinterpret_cast<float*>(bufferBytes.data());
for(auto point : polygon){
*positions++ = static_cast<float>(point.x());
*positions++ = 0.0f; //We need to drow only on the surface
*positions++ = static_cast<float>(point.y());
}
auto *buf = new Qt3DRender::QBuffer(geometry);
buf->setData(bufferBytes);
auto *positionAttribute = new Qt3DRender::QAttribute(geometry);
positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
positionAttribute->setVertexSize(3);
positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
positionAttribute->setBuffer(buf);
positionAttribute->setByteStride(3 * sizeof(float));
positionAttribute->setCount(static_cast<unsigned int>(numOfVertices));//(2);
geometry->addAttribute(positionAttribute); // We add the vertices in the geometry
// connectivity between vertices
QByteArray indexBytes;
indexBytes.resize(numOfVertices * static_cast<int>(sizeof(unsigned int))); // start to end
unsigned int *indices = reinterpret_cast<unsigned int*>(indexBytes.data());
for(unsigned int i = 0; i < static_cast<unsigned int>(numOfVertices); ++i) {
*indices++ = i;
}
auto *indexBuffer = new Qt3DRender::QBuffer(geometry);
indexBuffer->setData(indexBytes);
auto *indexAttribute = new Qt3DRender::QAttribute(geometry);
indexAttribute->setVertexBaseType(Qt3DRender::QAttribute::UnsignedInt);
indexAttribute->setAttributeType(Qt3DRender::QAttribute::IndexAttribute);
indexAttribute->setBuffer(indexBuffer);
indexAttribute->setCount(static_cast<unsigned int>(numOfVertices));
geometry->addAttribute(indexAttribute); // We add the indices linking the points in the geometry
// mesh
auto *poly = new Qt3DRender::QGeometryRenderer(_rootEntity);
poly->setGeometry(geometry);
poly->setPrimitiveType(Qt3DRender::QGeometryRenderer::LineLoop);
auto *material = new Qt3DExtras::QPhongMaterial(_rootEntity);
material->setAmbient(color);
// entity
auto *lineEntity = new Qt3DCore::QEntity(_rootEntity);
lineEntity->addComponent(poly);
lineEntity->addComponent(material);
}
В общем, решил так:
Поменял в своей функции drawPolygon ее имя на drawTriangles и строчку poly->setPrimitiveType(Qt3DRender::QGeometryRenderer::LineLoop); заменил на poly->setPrimitiveType(Qt3DRender::QGeometryRenderer::Triangles);, чтобы функция отрисовывала треугольники.
Далее, используя "header-only" библиотеку отсюда https://github.com/mapbox/earcut.hpp я написал простенькую функцию для триангуляции (деления полигона на много треугольников)
QPolygonF MainWindow::triangulateQPolygonF(QPolygonF polygon) {
using Coord = double;
using N = uint32_t;
// Create array
using Point = std::array<Coord, 2>;
std::vector<std::vector<Point>> vecVecPolygon;
std::vector<Point> vecPolygon;
for(auto point : polygon) {
vecPolygon.push_back({point.x(), point.y()});
}
vecVecPolygon.push_back(vecPolygon);
std::vector<N> indices = mapbox::earcut<N>(vecVecPolygon);
QPolygonF resPolygon;
for(unsigned int i = 0; i < indices.size(); ++i) {
resPolygon << QPointF((vecPolygon[indices[i]])[0], //x coordinate
(vecPolygon[indices[i]])[1]); //y coordinate
}
return resPolygon;
}
И все. Теперь просто пишу в программе что-то, наподобии drawTriangles(triangulateQPolygonF(polygon), QColor(Qt::black), entity);
Стоит иметь в виду, что отрисовываться будут только треугольники, у которых вершины указаны в polygon в порядке "по часовой стрелке". В ином случае они будут невидимы спереди. Чтобы изменить это поведение, можно воспользоваться https://doc.qt.io/qt-5.11/qt3drender-qcullface.html#details (Qt3DRender::QCullFace::NoCulling для отображения по часовой и против). Я так и не разобрался, как правильно использовать этот класс, но у себя криво реализовал, основываясь на коде в ответе отсюда https://stackoverflow.com/questions/51818584/2d-meshes-in-qt3d
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости