Search code examples
c++openglqt5qt3d

Qt3D reading raw vertex data from QGeometry


I am developing an application using Qt3D and need to access raw vertex data via C++. I am using the QObjectPicker for raypointing, but since the data is specialized (I have developed an importer that adds an extra attribute to each vertex containing a temperature reading) I cannot use QObjectPicker to read the data from the point conveniently.

The 3D object is being loaded via QMesh so I believe the best way to access the raw data is through QMesh's QGeometry member. Correct me if I'm wrong. QGeometry has a vector of QAttribute that hold the vertex attributes. (Again, correct me if I'm wrong.) From this point, I'm not sure how to read the data from a specific vertex index. My guess is I need to read the data from QAttribute::buffer at a certain position by knowing how big each piece of vertex data is and reading from the offset of that, but how would I do that here?

This is what I've come up with so far:

void ES3DScene::handlePickerClicked(QPickEvent *pick)
{
    QPickTriangleEvent *trianglePick = qobject_cast<QPickTriangleEvent*>(pick);
    // I'd like to get the vertex data from vertex1Index's position.
    qDebug() << "Clicked " << trianglePick->vertex1Index();
    QGeometry *geometry = m_mesh->geometry();
    auto attributes = geometry->attributes();
    for (auto i = 0; i < attributes.count(); ++i)
    {
        if (attributes.at(i)->name() == QAttribute::defaultPositionAttributeName())
        {
            QAttribute *attribute = attributes.at(i);
            qDebug() << "Attrib " << attribute;

            //This is where I'm stuck. I need to read the vertex attributes for the
            //vertex at trianglePick->vertex1Index();

            break;
        }
    }
}

Solution

  • I think you have to access the QBuffer of the attribute you are interested in. This is likely not the attribute with defaultPositionAttributeName(), but a name that you gave it in your importer. Getting the actual data will require you to convert it from the QByteArray to the right data type and fetch the correct position in the data by using the information contained in QAttribute's byteStride and byteOffset. You might also want to use vertexSize and vertexBaseType, depending on how your wrote your importer.

    Something along these lines should work (not tested):

    void ES3DScene::handlePickerClicked(QPickEvent *pick)
    {
        QPickTriangleEvent *trianglePick = qobject_cast<QPickTriangleEvent*>(pick);
        QGeometry *geometry = m_mesh->geometry();
        auto attributes = geometry->attributes();
        int vertexIndex = trianglePick->vertex1Index();
        for (auto i = 0; i < attributes.count(); ++i)
        {
            if (attributes.at(i)->name() == "yourattributename")
            {
                QAttribute *attribute = attributes.at(i);
                QBuffer *buffer = attribute->buffer();
                const QByteArray &data = buffer->data();
    
                int vertexOffset = vertexIndex * attribute->byteStride();
                int offset = vertexOffset + attribute.byteOffset();
    
                const char *rawData = &(data.constData()[offset]);
    
                // replace float with your data type
                float *value = reinterpret_cast<float*>(rawData);
    
                break;
            }
        }
    }