Framebuffer access in Qt3D

My task: to calculate the pixel coordinates (for example, to take a picture) of a three-dimensional grid in order to find the 2D shape of this grid from a specific camera angle.

I am currently using Qt3D with a QGeometryRenderer to render a scene containing a grid into a QWidget that works fine. I tried to display the contents of QWidget in Pixmap with QWidget :: render () suggested by this post How to create a screenshot of QWidget? . Saving pixmap in .jpg results in a blank image with the default background color, which makes sense because QWidget does not hold the mesh object itself.

This is how the scene is set in my mainwindow.cpp

// sets the scene objects, camera, lights,... void MainWindow::setScene() { scene = custommesh->createScene(mesh->getVertices(), mesh->getVerticesNormals(), mesh->getFaceNormals(), mesh->getVerticesIndex(), mesh->getFacesIndex()); // QEntity* custommesh->setMaterial(scene); // CustomMeshRenderer object camera = custommesh->setCamera(view); custommesh->setLight(scene, camera); custommesh->setCamController(scene, camera); view->setRootEntity(scene); // Qt3DExtras::Qt3DWindow object // Setting up a QWiget working as a container for the view QWidget *container = QWidget::createWindowContainer(view); container->setMinimumSize(QSize(500, 500)); QSizePolicy policy = QSizePolicy(QSizePolicy::Policy(5), QSizePolicy::Policy(5)); policy.setHorizontalStretch(1); policy.setVerticalStretch(1); container->setSizePolicy(policy); container->setObjectName("meshWidget"); this->ui->meshLayout->insertWidget(0, container); } 

As for the rendering here, this is the custommeshrenderer class, where the QGeometryRenderer is defined, and when the grid is initialized, QEntity * is returned.

 #include "custommeshrenderer.h" #include <Qt3DRender/QAttribute> #include <Qt3DExtras> #include <Qt3DRender/QGeometryRenderer> CustommeshRenderer::CustommeshRenderer() { rootEntity = new Qt3DCore::QEntity; customMeshEntity = new Qt3DCore::QEntity(rootEntity); transform = new Qt3DCore::QTransform; customMeshRenderer = new Qt3DRender::QGeometryRenderer; customGeometry = new Qt3DRender::QGeometry(customMeshRenderer); m_pVertexDataBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::VertexBuffer, customGeometry); m_pNormalDataBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::VertexBuffer, customGeometry); m_pColorDataBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::VertexBuffer, customGeometry); m_pIndexDataBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::IndexBuffer, customGeometry); } /** Set vertices and their normals for the scene @param vertices List with all vertices of the mesh @param vertices_normals List with all vertice normals @param face_normals List with all face normals @param vertice_idx List with the indices for the vertices @param face_idx List with all indices for the faces @return Entity where some components were added */ Qt3DCore::QEntity *CustommeshRenderer::createScene(QList<QVector3D> vertices, QList<QVector3D> vertices_normals, QList<QVector3D> face_normals, QList<int> vertices_idx, QList<QVector3D> faces_idx) { // Setting scale to 8.0 transform->setScale(8.0f); // Setting all the colors to (200, 0, 0) QList<QVector3D> color_list; for(int i = 0; i < vertices.length(); i++) { color_list.append(QVector3D(200.0f, 0.0f, 0.0f)); } // Fill vertexBuffer with data which hold the vertices, normals and colors // Build structure: Size of Verticles List * 3 (x,y,z) * 4 (since x,y,z are floats, which needs 4 bytes each) vertexBufferData.resize(vertices.length() * 3 * (int)sizeof(float)); float *rawVertexArray = reinterpret_cast<float *>(vertexBufferData.data()); normalBufferData.resize(vertices_normals.length() * 3 * (int)sizeof(float)); float *rawNormalArray = reinterpret_cast<float *>(normalBufferData.data()); colorBufferData.resize(color_list.length() * 3 * (int)sizeof(float)); float *rawColorArray = reinterpret_cast<float *>(colorBufferData.data()); setRawVertexArray(rawVertexArray, vertices); setRawNormalArray(rawNormalArray, vertices_normals); setRawColorArray(rawColorArray, color_list); //Fill indexBufferData with data which holds the triangulation information (patches/tris/lines) indexBufferData.resize(faces_idx.length() * 3 * (int)sizeof(uint)); uint *rawIndexArray = reinterpret_cast<uint *>(indexBufferData.data()); setRawIndexArray(rawIndexArray, faces_idx); //Set data to buffers m_pVertexDataBuffer->setData(vertexBufferData); m_pNormalDataBuffer->setData(normalBufferData); m_pColorDataBuffer->setData(colorBufferData); m_pIndexDataBuffer->setData(indexBufferData); // Attributes Qt3DRender::QAttribute *positionAttribute = new Qt3DRender::QAttribute(); positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute); positionAttribute->setBuffer(m_pVertexDataBuffer); // positionAttribute->setBuffer(m_pVertexDataBuffer.data()); positionAttribute->setDataType(Qt3DRender::QAttribute::Float); positionAttribute->setDataSize(3); positionAttribute->setByteOffset(0); positionAttribute->setByteStride(3 * sizeof(float)); positionAttribute->setCount(vertices.length()); positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName()); Qt3DRender::QAttribute *normalAttribute = new Qt3DRender::QAttribute(); normalAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute); normalAttribute->setBuffer(m_pNormalDataBuffer); //normalAttribute->setBuffer(m_pNormalDataBuffer.data()); normalAttribute->setDataType(Qt3DRender::QAttribute::Float); normalAttribute->setDataSize(3); normalAttribute->setByteOffset(0); normalAttribute->setByteStride(3 * sizeof(float)); normalAttribute->setCount(vertices.length()); normalAttribute->setName(Qt3DRender::QAttribute::defaultNormalAttributeName()); Qt3DRender::QAttribute* colorAttribute = new Qt3DRender::QAttribute(); colorAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute); colorAttribute->setBuffer(m_pColorDataBuffer); //colorAttribute->setBuffer(m_pColorDataBuffer.data()); colorAttribute->setDataType(Qt3DRender::QAttribute::Float); colorAttribute->setDataSize(3); colorAttribute->setByteOffset(0); colorAttribute->setByteStride(3 * sizeof(float)); colorAttribute->setCount(vertices.length()); colorAttribute->setName(Qt3DRender::QAttribute::defaultColorAttributeName()); Qt3DRender::QAttribute *indexAttribute = new Qt3DRender::QAttribute(); indexAttribute->setAttributeType(Qt3DRender::QAttribute::IndexAttribute); indexAttribute->setBuffer(m_pIndexDataBuffer); //indexAttribute->setBuffer(m_pIndexDataBuffer.data()); indexAttribute->setDataType(Qt3DRender::QAttribute::UnsignedInt); indexAttribute->setDataSize(3); indexAttribute->setByteOffset(0); indexAttribute->setByteStride(3 * sizeof(uint)); indexAttribute->setCount(face_normals.length()); customGeometry->addAttribute(positionAttribute); customGeometry->addAttribute(normalAttribute); /*customGeometry->addAttribute(colorAttribute);*/ customGeometry->addAttribute(indexAttribute); //Set the final geometry and primitive type customMeshRenderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Triangles); customMeshRenderer->setVerticesPerPatch(3); customMeshRenderer->setGeometry(customGeometry); customMeshRenderer->setVertexCount(faces_idx.length()*3); customMeshEntity->addComponent(customMeshRenderer); customMeshEntity->addComponent(transform); setMaterial(customMeshEntity); return rootEntity; } 

What is the best way to access the framebuffer, or is there any other way to take a snapshot of the grid?

My last hope was to implement a rendering pipeline (at least from projection coordinates to pixel coordinates), but I would prefer a different solution. Unfortunately, I have to rely on Qt3D and cannot switch to other classes such as QOpenGLWidget. At least I have not yet found the opportunity to integrate it.

I am new to Qt3D, and the lack of detailed documentation does not make it easier.

+5
source share
1 answer

You can use QRenderCapture for this. This essentially means glReadPixels for you. Documentation is a bit rare on this, but there is an example on the Internet.

As an alternative, I implemented standalone rendering , which could help you if you do not need the entire 3D window.

I'm not sure what you mean by

Calculate the pixel coordinates (for example, take a picture) of a three-dimensional grid to find the two-dimensional shape of this grid from a specific camera angle

but if, for example, you want to make the entire grid in only one color (without highlighting), you can try QPerVertexColorMaterial , which gave me exactly this result.

+1
source

Source: https://habr.com/ru/post/1274632/


All Articles