Нарисовать закрашенный QPolygonF в Qt3D

149
09 октября 2019, 03:40

У меня есть функция, которая возвращает 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);
}
Answer 1

В общем, решил так: Поменял в своей функции 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

READ ALSO
fatal error: &#39;Python.h&#39; file not found

fatal error: 'Python.h' file not found

Хотел вызывать C++ функции через питон, но

157
Константная rvalue ссылка

Константная rvalue ссылка

Используется ли где-то константная rvalue ссылка?

140
Возможно ли из qtwebkit вырезать только момент интерпретации страницы?

Возможно ли из qtwebkit вырезать только момент интерпретации страницы?

Необходимо сделать многопоточный паук для сайтов, для анализа веб страниц

136