2017-10-10 9 views
3

Je développe une application utilisant Qt3D et ai besoin d'accéder à des données de vertex brutes via C++. J'utilise le QObjectPicker pour raypointing, mais comme les données sont spécialisées (j'ai développé un importateur qui ajoute un attribut supplémentaire à chaque sommet contenant une lecture de température) je ne peux pas utiliser QObjectPicker pour lire les données du point commodément.Qt3D lisant des données de vertex brutes à partir de QGeometry

L'objet 3D est en cours de chargement via QMesh donc je crois que la meilleure façon d'accéder aux données brutes est QMesh membre QGeometry. Corrige moi si je me trompe. QGeometry a un vecteur de QAttribute qui détiennent les attributs vertex. (Encore une fois, corrigez-moi si je me trompe.) De ce point, je ne suis pas sûr de savoir comment lire les données d'un index de vertex spécifique. Ma conjecture est que je dois lire les données de QAttribute::buffer à une certaine position en sachant quelle est la taille de chaque morceau de données de vertex et en lisant le décalage de cela, mais comment ferais-je cela ici?

C'est ce que je suis venu avec jusqu'à présent.

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; 
     } 
    } 
} 

Répondre

2

Je pense que vous devez accéder au QBuffer de l'attribut que vous êtes intéressé par c'est probablement pas l'attribut avec defaultPositionAttributeName(), mais nom que vous lui avez donné dans votre importateur. Pour obtenir les données réelles, vous devez le convertir du type de données QByteArray vers le bon type de données et récupérer la position correcte dans les données en utilisant les informations contenues dans les champs et byteOffset. Vous pouvez également utiliser vertexSize et vertexBaseType, en fonction de la façon dont vous avez écrit votre importateur.

Quelque chose le long de ces lignes devrait fonctionner (non testé):

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; 
     } 
    } 
} 
+0

Excellent. On dirait que ça va le faire. Peu de temps avant de répondre, j'ai trouvé une autre voie très similaire. –

1

Après avoir creusé à travers les sources Qt3D, je suis venu avec ceci:

template<typename T> 
T extractIndexData(QAttribute *attribute, int index) 
{ 
    const T *typedData = reinterpret_cast<const T*>(attribute->buffer()->data().constData()); 
    const T indexValue = *(typedData + index); 
    return indexValue; 
} 

template<typename VT, typename IT> 
VT extractVertexData(QAttribute *attribute, IT index) 
{ 
    const char *buffer = attribute->buffer()->data().constData(); 
    const char *vertexData = buffer + (index * attribute->byteStride() + attribute->byteOffset()); 
    // Construct vertex from from the typed data 
    VT vertex; 
    const QAttribute::VertexBaseType type = attribute->vertexBaseType(); 
    switch (type) 
    { 
    case QAttribute::Float: { 
     const float *typedVertexData = reinterpret_cast<const float*>(vertexData); 
     const int components = attribute->vertexSize(); 
     for (int i = 0; i < components; ++i) 
      vertex[i] = typedVertexData[i]; 
     break; 
    } 
    // TODO: Handle other types as needed. 
    default: { 
     qWarning() << "Unhandled type"; 
     Q_UNREACHABLE(); 
    } 
    } 
    return vertex; 
} 

Et appelé comme ceci:

void ES3DScene::handlePickerClicked(QPickEvent *pick) 
{ 
    float *temperature = nullptr; 
    QPickTriangleEvent *trianglePick = qobject_cast<QPickTriangleEvent*>(pick); 
    auto idx = trianglePick->vertex1Index(); 

    QGeometry *geometry = m_mesh->geometry(); 
    for (QAttribute* attribute : geometry->attributes()) 
    { 
     if (attribute->name() == "vertexTemperature") 
     { 
      temperature = extractVertexData<float*>(attribute, idx); 

      break; 
     } 
    } 
} 
+0

La diffusion de QPickEvent * vers QPickTriangleEvent * aboutit à un nullptr pour moi. Y a-t-il quelque chose de spécial que vous faites qui lui permet de fonctionner? (Qt 5.9.1) –

+1

@fat_flying_pigs Oui, vous avez besoin de mettre '' QPickingSettings' PickMethod à TrianglePicking' et les signaux de prélèvement retourneront 'QPickTriangleEvent' EN QML: Entité { composants: [ RenderSettings { pickingSettings { pickMethod: PickingSettings.TrianglePicking }} ] } https://doc.qt.io/qt-5/qml-qt3d-render-pickingsettings.html –

+0

Faire note de ce résolu mon problème: je n'utilise pas QML. J'ai dû mettre activeFrameGraph de RenderSetting à activeFrameGraph de QWindow –