如何在 Qt3D 中绘制一条简单的线?
How do I draw a simple line in Qt3D?
我觉得这应该很简单,但我一生都不知道如何使用 Qt 3D 绘制基本线条。我能找到的关于这个主题的唯一指南是 this obscure video, in which there's an off-putting amount of raw byte buffer and memory manipulation going on via scarcely documented classes.
有没有更好的方法使用我缺少的闪亮的新 API 来做到这一点?
我建议看看 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);
那么 3D 中的线是什么?它将是一个外半径非常小的圆柱体。
根据您 link 编辑的视频,我想出了下面的代码(也发布在 Qt 论坛中:https://forum.qt.io/topic/66808/qt3d-draw-grid-axis-lines/3)。
首先,您需要创建 QGeometry。由于它是一条简单的线,因此它仅由 2 个顶点(起点、终点)和 2 个索引(link 个顶点)组成。为此,您需要创建 2 个 QByteArray 并将它们存储到 QBuffer 中。在第一个中,您存储 2 个顶点(每个顶点的 x、y 和 z 坐标)。在第二个中,你只是说你想 link 你的第一个顶点到第二个。当我们在渲染器上使用 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);
}
这是我必须对缓冲区类型进行的更正(我假设它现在已弃用):
auto *buf = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::VertexBuffer, geometry);
auto *indexBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::IndexBuffer, geometry);
我的是 Win 10 上的 Qt 5.9。
我觉得这应该很简单,但我一生都不知道如何使用 Qt 3D 绘制基本线条。我能找到的关于这个主题的唯一指南是 this obscure video, in which there's an off-putting amount of raw byte buffer and memory manipulation going on via scarcely documented classes.
有没有更好的方法使用我缺少的闪亮的新 API 来做到这一点?
我建议看看 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);
那么 3D 中的线是什么?它将是一个外半径非常小的圆柱体。
根据您 link 编辑的视频,我想出了下面的代码(也发布在 Qt 论坛中:https://forum.qt.io/topic/66808/qt3d-draw-grid-axis-lines/3)。
首先,您需要创建 QGeometry。由于它是一条简单的线,因此它仅由 2 个顶点(起点、终点)和 2 个索引(link 个顶点)组成。为此,您需要创建 2 个 QByteArray 并将它们存储到 QBuffer 中。在第一个中,您存储 2 个顶点(每个顶点的 x、y 和 z 坐标)。在第二个中,你只是说你想 link 你的第一个顶点到第二个。当我们在渲染器上使用 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);
}
这是我必须对缓冲区类型进行的更正(我假设它现在已弃用):
auto *buf = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::VertexBuffer, geometry);
auto *indexBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::IndexBuffer, geometry);
我的是 Win 10 上的 Qt 5.9。