Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QGeometryRenderer: How to render an isosurface from quadrilateral patches?



  • The question is a mirror of a stackoverflow post.

    I extracted an isosurface with the dual marching cubes algorithm.

    From the algorithm, I got the following data:

    # cube.obj wavefront file
    ## shared vertices (cartesian coordinates)
    v 1.0 1.0 0.0
    v 0.0 1.0 0.0
    v 0.0 0.0 0.0
    v 1.0 0.0 0.0
    v 1.0 0.0 1.0
    v 0.0 0.0 1.0
    v 0.0 1.0 1.0
    v 1.0 1.0 1.0
    ## faces (vertex indices are forming quad patches)
    f 1 4 3 2
    f 5 6 3 4
    f 7 2 3 6
    f 8 5 4 1
    f 8 1 2 7
    f 8 7 6 5
    

    (Plotting triangulated surfaces is explained here).

    Main question: Is it possible to render an isosurface from this quadrilateral face data with Qt3d?

    Bonus question: How can I make the surface transparent or plot it as a wireframe?

    This is how far I got:

    #include <QApplication>
    #include <QWidget>
    #include <Qt3DExtras/Qt3DWindow>
    #include <Qt3DExtras/QOrbitCameraController>
    #include <Qt3DRender/QCamera>
    #include <Qt3DCore/QEntity>
    #include <Qt3DCore/QTransform>
    #include <Qt3DRender/QGeometryRenderer>
    #include <Qt3DRender/QAttribute>
    #include <Qt3DRender/QBuffer>
    #include <Qt3DExtras/QPhongAlphaMaterial>
    
    int main(int argc, char* argv[])
    {
        QApplication app(argc, argv);
    
        // Root entity
        auto *rootEntity = new Qt3DCore::QEntity();
    
        // Window container
        auto qt3DWindow = new Qt3DExtras::Qt3DWindow();
        qt3DWindow->setRootEntity(rootEntity);
        auto widget = QWidget::createWindowContainer(qt3DWindow);
    
        // Camera
        auto *camController = new Qt3DExtras::QOrbitCameraController(rootEntity);
    
        qt3DWindow->setRootEntity(rootEntity);
        qt3DWindow->camera()->lens()->setPerspectiveProjection(45.0f, 16.0f / 9.0f, 0.1f, 100.0f);
        qt3DWindow->camera()->setPosition(QVector3D(2.5, -8, 0.0));
        qt3DWindow->camera()->setViewCenter(QVector3D(0, 0, 0));
    
        // For camera controls
        camController->setLinearSpeed(50.f);
        camController->setLookSpeed(180.f);
        camController->setCamera(qt3DWindow->camera());
    
        // Material
        auto *material = new Qt3DExtras::QPhongAlphaMaterial(rootEntity);
        material->setSpecular(Qt::white);
        material->setShininess(0);
        material->setAmbient(Qt::red);
        material->setAlpha(0.5);
    
        // Transform
        auto *transform = new Qt3DCore::QTransform;
        transform->setScale(1.0f);
    
        auto *customMeshEntity = new Qt3DCore::QEntity(rootEntity);
    
        // Custom Mesh
        auto *customMeshRenderer = new Qt3DRender::QGeometryRenderer;
        auto *customGeometry = new Qt3DRender::QGeometry(customMeshRenderer);
    
        auto *vertexDataBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::VertexBuffer, customGeometry);
        auto *indexDataBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::IndexBuffer, customGeometry);
    
        // Vertices
        auto nVertices = 8;
        auto nCoordinates = 3; // cartesian coordinates
        QByteArray vertexBufferData;
        vertexBufferData.resize(nVertices * nCoordinates * sizeof(float));
    
        auto *rawVertexArray = reinterpret_cast<float *>(vertexBufferData.data());
        // Vertex 1
        rawVertexArray[0*nCoordinates+0] = 1.0f;
        rawVertexArray[0*nCoordinates+1] = 1.0f;
        rawVertexArray[0*nCoordinates+2] = 0.0f;
        // Vertex 2
        rawVertexArray[1*nCoordinates+0] = 0.0f;
        rawVertexArray[1*nCoordinates+1] = 1.0f;
        rawVertexArray[1*nCoordinates+2] = 0.0f;
        // Vertex 3
        rawVertexArray[2*nCoordinates+0] = 0.0f;
        rawVertexArray[2*nCoordinates+1] = 0.0f;
        rawVertexArray[2*nCoordinates+2] = 0.0f;
        // Vertex 4
        rawVertexArray[3*nCoordinates+0] = 1.0f;
        rawVertexArray[3*nCoordinates+1] = 0.0f;
        rawVertexArray[3*nCoordinates+2] = 0.0f;
        // Vertex 5
        rawVertexArray[4*nCoordinates+0] = 1.0f;
        rawVertexArray[4*nCoordinates+1] = 0.0f;
        rawVertexArray[4*nCoordinates+2] = 1.0f;
        // Vertex 6
        rawVertexArray[5*nCoordinates+0] = 0.0f;
        rawVertexArray[5*nCoordinates+1] = 0.0f;
        rawVertexArray[5*nCoordinates+2] = 1.0f;
        // Vertex 7
        rawVertexArray[6*nCoordinates+0] = 0.0f;
        rawVertexArray[6*nCoordinates+1] = 1.0f;
        rawVertexArray[6*nCoordinates+2] = 1.0f;
        // Vertex 8
        rawVertexArray[7*nCoordinates+0] = 1.0f;
        rawVertexArray[7*nCoordinates+1] = 1.0f;
        rawVertexArray[7*nCoordinates+2] = 1.0f;
    
        vertexDataBuffer->setData(vertexBufferData);
    
        // Faces
        unsigned nFaces = 6;
        unsigned nIndicesPerFace = 4;
        QByteArray indexBufferData;
        indexBufferData.resize(nFaces * nIndicesPerFace * sizeof(ushort));
    
        auto *rawIndexArray = reinterpret_cast<ushort *>(indexBufferData.data());
        // Face 1
        rawIndexArray[0*nIndicesPerFace+0] = 1;
        rawIndexArray[0*nIndicesPerFace+1] = 4;
        rawIndexArray[0*nIndicesPerFace+2] = 3;
        rawIndexArray[0*nIndicesPerFace+3] = 2;
        // Face 2
        rawIndexArray[1*nIndicesPerFace+0] = 5;
        rawIndexArray[1*nIndicesPerFace+1] = 6;
        rawIndexArray[1*nIndicesPerFace+2] = 3;
        rawIndexArray[1*nIndicesPerFace+3] = 4;
        // Face 3
        rawIndexArray[2*nIndicesPerFace+0] = 7;
        rawIndexArray[2*nIndicesPerFace+1] = 2;
        rawIndexArray[2*nIndicesPerFace+2] = 3;
        rawIndexArray[2*nIndicesPerFace+3] = 6;
        // Face 4
        rawIndexArray[3*nIndicesPerFace+0] = 8;
        rawIndexArray[3*nIndicesPerFace+1] = 5;
        rawIndexArray[3*nIndicesPerFace+2] = 4;
        rawIndexArray[3*nIndicesPerFace+3] = 1;
        // Face 5
        rawIndexArray[4*nIndicesPerFace+0] = 8;
        rawIndexArray[4*nIndicesPerFace+1] = 1;
        rawIndexArray[4*nIndicesPerFace+2] = 2;
        rawIndexArray[4*nIndicesPerFace+3] = 7;
        // Face 6
        rawIndexArray[5*nIndicesPerFace+0] = 8;
        rawIndexArray[5*nIndicesPerFace+1] = 7;
        rawIndexArray[5*nIndicesPerFace+2] = 6;
        rawIndexArray[5*nIndicesPerFace+3] = 5;
    
        indexDataBuffer->setData(indexBufferData);
    
        // Attributes
        auto *positionAttribute = new Qt3DRender::QAttribute();
        positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
        positionAttribute->setBuffer(vertexDataBuffer);
        positionAttribute->setDataType(Qt3DRender::QAttribute::Float);
        positionAttribute->setDataSize(nCoordinates);
        positionAttribute->setByteOffset(0);
        positionAttribute->setByteStride(nCoordinates * sizeof(float));
        positionAttribute->setCount(nVertices);
        positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
    
        auto *indexAttribute = new Qt3DRender::QAttribute();
        indexAttribute->setAttributeType(Qt3DRender::QAttribute::IndexAttribute);
        indexAttribute->setBuffer(indexDataBuffer);
        indexAttribute->setDataType(Qt3DRender::QAttribute::UnsignedShort);
        indexAttribute->setDataSize(1);
        indexAttribute->setByteOffset(0);
        indexAttribute->setByteStride(0);
        indexAttribute->setCount(nFaces*nIndicesPerFace);
    
        customGeometry->addAttribute(positionAttribute);
        customGeometry->addAttribute(indexAttribute);
    
        customMeshRenderer->setInstanceCount(1);
        customMeshRenderer->setFirstVertex(0);
        customMeshRenderer->setIndexOffset(1); // first index is 1
        customMeshRenderer->setFirstInstance(0);
        customMeshRenderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Patches);
        customMeshRenderer->setVerticesPerPatch(nIndicesPerFace);
        customMeshRenderer->setGeometry(customGeometry);
        customMeshRenderer->setVertexCount(nFaces * nIndicesPerFace);
    
        customMeshEntity->addComponent(customMeshRenderer);
        customMeshEntity->addComponent(transform);
        customMeshEntity->addComponent(material);
    
        qt3DWindow->setRootEntity(rootEntity);
        widget->show();
    
        return QApplication::exec();
    }
    

    The rendered scene remains empty, so I assume I did something wrong here. I am grateful for any help!



  • @Finn I need some help in extracting the isosurface https://forum.qt.io/topic/98234/surface-rendering-of-volumetric-data



  • I found a solution. Please see my stackoverflow post.


Log in to reply