I would like to implement a GCode Viewer in 3D for a C /Qt5.15.2 program that I wrote.
A GCode file contains the instructions for a 3D-Printer to print a 3D Model (where to move, how much material to extrude, which layer is being printed, etc.). After parsing the GCode file, I get a list of lines representing the displacement of the nozzle and want to display in 3D this basic list of lines. Like in this example from
I started playing with Qt3D and OpenGL examples from Qt to try to draw a lot of lines (in this case 10.000, but some GCode have more than a million lines) but after creating the scene and trying to display the window the program crashes. How do you draw a lot of objects in Qt3D or openGL without the program crashing please ?
I started from this example, removed the example elements from the scene, and used a drawLine function from this thread to draw my lines. What am I doing wrong please ? My code is :
#include <QGuiApplication>
#include <Qt3DCore/QEntity>
#include <Qt3DRender/QCamera>
#include <Qt3DRender/QCameraLens>
#include <Qt3DCore/QTransform>
#include <Qt3DCore/QAspectEngine>
#include <Qt3DInput/QInputAspect>
#include <Qt3DRender/QRenderAspect>
#include <Qt3DExtras/QForwardRenderer>
#include <Qt3DExtras/QPhongMaterial>
#include <Qt3DExtras/QCylinderMesh>
#include <Qt3DExtras/QSphereMesh>
#include <Qt3DExtras/QTorusMesh>
#include <QPropertyAnimation>
#include "qt3dwindow.h"
#include <Qt3DCore/QEntity>
#include <Qt3DCore/QTransform>
#include <Qt3DExtras/QPhongMaterial>
#include <Qt3DRender/QAttribute>
#include <Qt3DRender/QBuffer>
#include <Qt3DRender/QGeometry>
#include <QElapsedTimer>
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);
}
int main(int argc, char* argv[])
{
QGuiApplication app(argc, argv);
Qt3DExtras::Qt3DWindow view;
Qt3DCore::QEntity *scene = new Qt3DCore::QEntity;
// Camera
Qt3DRender::QCamera *camera = view.camera();
camera->lens()->setPerspectiveProjection(45.0f, 16.0f/9.0f, 0.1f, 1000.0f);
camera->setPosition(QVector3D(0, 0, 2.0f));
camera->setViewCenter(QVector3D(0, 0, 0));
QColor red(255,0,0);
QElapsedTimer elapsed;
elapsed.start();
double i=0;
while( i < 1000){
qDebug() << i << elapsed.elapsed();
drawLine(QVector3D(0,0,-i/10.0),QVector3D(1,0,-i/10.0),red,scene);
drawLine(QVector3D(1,0,-i/10.0),QVector3D(1,1,-i/10.0),red,scene);
drawLine(QVector3D(1,1,-i/10.0),QVector3D(0,1,-i/10.0),red,scene);
drawLine(QVector3D(0,1,-i/10.0),QVector3D(0,0,-i/10.0),red,scene);
i =0.1;
}
// For camera controls (commented to publish less code)
/*Qt3DExtras::QOrbitCameraController *camController = new Qt3DExtras::QOrbitCameraController(scene);
camController->setLinearSpeed( 50.0f );
camController->setLookSpeed( 180.0f );
camController->setCamera(camera);*/
view.setRootEntity(scene);
view.show();
return app.exec();
}
If usefull, here is the debug stack :
1 __memmove_avx_unaligned_erms memmove-vec-unaligned-erms.S 369 0x7ffff6276828
2 ?? 0x7fffdb31a2cb
3 ?? 0x7fffdb307d68
4 ?? 0x7fffdb317c46
5 ?? 0x7fffda6ac0ad
6 ?? 0x7fffda6acd23
7 ?? 0x7fffda6ae2ee
8 ?? 0x7fffda6ae91d
9 ?? 0x7fffda6ce86e
10 ?? 0x7fffda6f4167
11 ?? 0x7fffda953428
12 ?? 0x7fffda820a05
13 ?? 0x7fffda820df8
14 ?? 0x7fffda820f55
15 ?? 0x7fffda9486f8
16 Qt3DRender::Render::OpenGL::Renderer::submitRenderViews(QVector<Qt3DRender::Render::OpenGL::RenderView *> const&) 0x7fffe8045819
17 Qt3DRender::Render::OpenGL::Renderer::doRender(bool) 0x7fffe8046b83
18 Qt3DRender::Render::OpenGL::Renderer::render() 0x7fffe803ae79
19 Qt3DRender::Render::RenderThread::run() 0x7ffff7939c3e
20 QThreadPrivate::start(void *) 0x7ffff65adb35
... <More>
CodePudding user response:
I would propose using a drawLineStrip function to speed up the drawing.
Vertices and indices of the same material are placed in a single vertex/index buffer. It is important to set the setRestartIndexValue
and setPrimitiveRestartEnabled
properties of the GeometryRenderer. It would look as follows:
void drawLineStrip(const QVector<QVector3D>& vertices, const QVector<unsigned int>& indices, const QColor& color, Qt3DCore::QEntity* _rootEntity)
{
auto* geometry = new Qt3DRender::QGeometry(_rootEntity);
// position vertices (start and end)
QByteArray bufferBytes;
bufferBytes.resize(3 * vertices.size() * sizeof(float)); // start.x, start.y, start.end end.x, end.y, end.z
float* positions = reinterpret_cast<float*>(bufferBytes.data());
for (int n = vertices.size(), i = 0; i < n; i)
{
*positions = vertices[i].x();
*positions = vertices[i].y();
*positions = vertices[i].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(vertices.size());
geometry->addAttribute(positionAttribute); // We add the vertices in the geometry
// connectivity between vertices
QByteArray indexBytes;
indexBytes.resize(indices.size() * sizeof(unsigned int)); // start to end
memcpy(indexBytes.data(), indices.data(), indices.size() * sizeof(unsigned int));
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->setVertexSize(1);
indexAttribute->setBuffer(indexBuffer);
indexAttribute->setByteStride(1 * sizeof(unsigned int));
indexAttribute->setCount(indices.size());
geometry->addAttribute(indexAttribute); // We add the indices linking the points in the geometry
// mesh
auto* line = new Qt3DRender::QGeometryRenderer(_rootEntity);
line->setGeometry(geometry);
line->setRestartIndexValue(-1);
line->setPrimitiveRestartEnabled(true);
line->setPrimitiveType(Qt3DRender::QGeometryRenderer::LineStrip);
auto* material = new Qt3DExtras::QPhongMaterial(_rootEntity);
material->setAmbient(color);
// entity
auto* lineEntity = new Qt3DCore::QEntity(_rootEntity);
lineEntity->addComponent(line);
lineEntity->addComponent(material);
}
In your program you would use it this way:
QVector<QVector3D> vertices;
vertices.resize((ceil(1000. / 0.1) 1) * 5);
QVector<unsigned int> indices;
indices.resize((ceil(1000. / 0.1) 1) * 6);
double i = 0;
int k = 0;
while (i < 1000) {
k = 1;
int vIdx = 5 * k;
vertices[vIdx 0] = QVector3D(0, 0, -i / 10.0);
vertices[vIdx 1] = QVector3D(1, 0, -i / 10.0);
vertices[vIdx 2] = QVector3D(1, 1, -i / 10.0);
vertices[vIdx 3] = QVector3D(0, 1, -i / 10.0);
vertices[vIdx 4] = QVector3D(0, 0, -i / 10.0);
int idx = 6 * k;
indices[idx 0] = vIdx 0;
indices[idx 1] = vIdx 1;
indices[idx 2] = vIdx 2;
indices[idx 3] = vIdx 3;
indices[idx 4] = vIdx 4;
indices[idx 5] = -1;
i =0.1;
}
drawLineStrip(vertices, indices, red, scene);