2017-10-10 316 views
3

我正在開發一個使用Qt3D的應用程序,需要通過C++訪問原始頂點數據。我正在使用QObjectPicker進行射線定位,但由於數據是專用的(我開發了一個導入程序,它爲包含溫度讀數的每個頂點添加了一個額外的屬性),所以我不能使用QObjectPicker來方便地從這個點讀取數據。Qt3D從QGeometry讀取原始頂點數據

3D對象正在通過QMesh加載,所以我相信訪問原始數據的最佳方式是通過QMeshQGeometry成員。如我錯了請糾正我。 QGeometry具有保存頂點屬性的向量QAttribute。 (再次,糾正我,如果我錯了。)從這一點上,我不知道如何從特定的頂點索引讀取數據。我的猜測是,我需要從某個位置讀取QAttribute::buffer的數據,方法是知道每個頂點數據有多大,然後從偏移量讀取,但我該怎麼做?

這是我想出迄今:

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

回答

2

我認爲你必須訪問你感興趣的屬性的QBuffer這可能不符合defaultPositionAttributeName()屬性,但你在進口商給你的名字。獲取實際數據需要您將其從QByteArray轉換爲正確的數據類型,並使用QAttributebyteStridebyteOffset中包含的信息獲取數據中的正確位置。您可能還想使用vertexSizevertexBaseType,具體取決於您寫入導入程序的方式。

東西沿着這些路線應該工作(未測試):

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

非常好。看起來像這樣做。在你回答之前不久,我發現了另一種非常相似的方式。 –

1

通過Qt3D來源挖後,我想出了這個:

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

並稱爲像這樣:

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

從QPickEvent *下溯到QPickTriangleEvent *會產生一個nullptr。有沒有什麼特別的事情可以讓你工作? (QT 5.9.1) –

+1

@fat_flying_pigs是的,你需要設置'QPickingSettings' PickMethod爲'TrianglePicking',然後挑信號將返回'QPickTriangleEvent' 在QML: 實體{ 組件:[ RenderSettings { pickingSettings { pickMethod:PickingSettings.TrianglePicking }} ] } https://doc.qt.io/qt-5/qml-qt3d-render-pickingsettings.html –

+0

製作注意什麼解決我的問題:我沒有使用QML。我必須將RenderSetting的activeFrameGraph設置爲QWindow的activeFrameGraph –