如何在Qt3D中绘制一条简单的线?

9
我觉得这应该很简单,但是我无论如何都想不出如何使用Qt 3D绘制基本线条。我能找到的唯一指导是这个晦涩的视频, 其中通过文档稀少的类进行了大量原始字节缓冲区和内存操作,让人望而生畏。
有没有更好的方法使用闪亮的新API来完成这个任务?
3个回答

18
从你提供的视频中,我得到了下面的代码(也发布在Qt论坛上:https://forum.qt.io/topic/66808/qt3d-draw-grid-axis-lines/3)。
首先,您需要创建您的QGeometry。由于这是一个简单的线条,只需由2个顶点(起点和终点)和2个索引(链接顶点)组成。为此,您需要创建2个QByteArray并将它们存储到QBuffer中。在第一个QByteArray中,存储2个顶点(每个顶点的x、y和z坐标)。在第二个QByteArray中,您只需声明要将第一个顶点链接到第二个顶点即可。由于我们在渲染器上使用Qt3DRender::QGeometryRenderer::Lines,因此只需要2个索引。
完成后,您只需将您的QGeometry放入QGeometryRenderer中以获得网格,并将该网格放入QEntity中,以便它出现在树中并进行渲染。
#include <Qt3DCore/QEntity>
#include <Qt3DCore/QTransform>
#include <Qt3DExtras/QPhongMaterial>
#include <Qt3DRender/QAttribute>
#include <Qt3DRender/QBuffer>
#include <Qt3DRender/QGeometry>

void drawLine(const QVector3D& start, const QVector3D& end, const QColor& color, Qt3DCore::QEntity *_rootEntity)
{
    auto *geometry = new Qt3DRender::QGeometry(_rootEntity);

    // position vertices (start and end)
    QByteArray bufferBytes;
    bufferBytes.resize(3 * 2 * sizeof(float)); // start.x, start.y, start.end + end.x, end.y, end.z
    float *positions = reinterpret_cast<float*>(bufferBytes.data());
    *positions++ = start.x();
    *positions++ = start.y();
    *positions++ = start.z();
    *positions++ = end.x();
    *positions++ = end.y();
    *positions++ = end.z();

    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(2);
    geometry->addAttribute(positionAttribute); // We add the vertices in the geometry

    // connectivity between vertices
    QByteArray indexBytes;
    indexBytes.resize(2 * sizeof(unsigned int)); // start to end
    unsigned int *indices = reinterpret_cast<unsigned int*>(indexBytes.data());
    *indices++ = 0;
    *indices++ = 1;

    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(2);
    geometry->addAttribute(indexAttribute); // We add the indices linking the points in the geometry

    // mesh
    auto *line = new Qt3DRender::QGeometryRenderer(_rootEntity);
    line->setGeometry(geometry);
    line->setPrimitiveType(Qt3DRender::QGeometryRenderer::Lines);
    auto *material = new Qt3DExtras::QPhongMaterial(_rootEntity);
    material->setAmbient(color);

    // entity
    auto *lineEntity = new Qt3DCore::QEntity(_rootEntity);
    lineEntity->addComponent(line);
    lineEntity->addComponent(material);
}

尝试了你的代码,它能正常运行,干得好。只有一个小错误:在函数签名中,你写成了 Q3DCore::QEntity *_rootEntity,但是 Qt3D 中的 t 漏掉了 ;) - Florian Blume
Q3DCore::QEntity 应该改为 Qt3DCore::QEntity。 - sonichy
我尝试使用这段代码画一百万条线,但它崩溃了。我需要改变什么吗? - ElevenJune
这段代码在MacOS上不再使用Qt6来渲染线条(Qt5可以)。有人知道Metal是否不再支持光栅化线条吗?因为我知道从Qt5到Qt6,图形后端发生了变化。 - HarryP2023
我想添加一些在使用QT6.2时发生的更改。您需要更改以下命名空间: Qt3DRender/QAttribute -> Qt3DCore/QAttribute; Qt3DRender/QBuffer -> Qt3DCore/QBuffer; Qt3DRender/QGeometry -> Qt3DCore/QGeometry;此外,您还需要将下面的代码中的命名空间更改为正确的命名空间。并且您需要包含Qt3DRender。 - Steven

1
这是我对缓冲区类型所做的更正(我认为它现在已被弃用):
auto *buf = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::VertexBuffer, geometry);
auto *indexBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::IndexBuffer, geometry);

我的是在Windows 10上运行的Qt 5.9。


-4
我建议看一下https://doc-snapshots.qt.io/qt5-5.9/qt3d-basicshapes-cpp-example.html,因为不久前我自己也问过一个类似的问题,即如何画一个圆。嗯,在3D中,圆是一个具有特殊半径比例的环面。
// thin Torus = Circle in 3D
Qt3DCore::QEntity *torusEntity0 = new Qt3DCore::QEntity(rootEntity);
Qt3DExtras::QTorusMesh *torusMesh0 = new Qt3DExtras::QTorusMesh;
torusMesh0->setRadius(15);
torusMesh0->setMinorRadius(0.01f);
torusMesh0->setRings(100);
torusMesh0->setSlices(20);
torusEntity0->addComponent(torusMesh0);
torusEntity0->addComponent(material);

那么在三维空间中,什么是一条线?它将是一个具有非常小外半径的圆柱体。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接