Qt Quick 3D - カスタムジオメトリの例
C++ と QML からカスタム頂点データを提供する例を示します。
この例では、Model のQQuick3DGeometry とthe geometry property を使用して、ベイク済みのアセットの代わりに、C++ と QML から指定された頂点、法線、テクスチャ座標を持つメッシュをレンダリングします。
さらに、GridGeometry のデモも行います。GridGeometry は組み込みのQQuick3DGeometry 実装で、グリッドの表示に適した線プリミティブを持つメッシュを提供します。
この例では、カスタムジオメトリを提供するコードに焦点を当てますので、まずExampleTriangleGeometry
C++ ヘッダーファイルを見てみましょう:
class ExampleTriangleGeometry : public QQuick3DGeometry { Q_OBJECT QML_NAMED_ELEMENT(ExampleTriangleGeometry) Q_PROPERTY(bool normals READ normals WRITE setNormals NOTIFY normalsChanged) Q_PROPERTY(float normalXY READ normalXY WRITE setNormalXY NOTIFY normalXYChanged) Q_PROPERTY(bool uv READ uv WRITE setUV NOTIFY uvChanged) Q_PROPERTY(float uvAdjust READ uvAdjust WRITE setUVAdjust NOTIFY uvAdjustChanged) public: ExampleTriangleGeometry(); bool normals() const { return m_hasNormals; } void setNormals(bool enable); float normalXY() const { return m_normalXY; } void setNormalXY(float xy); bool uv() const { return m_hasUV; } void setUV(bool enable); float uvAdjust() const { return m_uvAdjust; } void setUVAdjust(float f); signals: void normalsChanged(); void normalXYChanged(); void uvChanged(); void uvAdjustChanged(); private: void updateData(); bool m_hasNormals = false; float m_normalXY = 0.0f; bool m_hasUV = false; float m_uvAdjust = 0.0f; };
最も重要な点は、ExampleTriangleGeometry
クラスがQQuick3DGeometry を継承していることと、QML_NAMED_ELEMENT(ExampleTriangleGeometry)
マクロを呼び出し、QML からアクセスできるようにしていることです。また、Q_PROPERTY
マクロで定義されたいくつかのプロパティは、QML オブジェクトの中で自動的に公開されます。では、QMLモデルを見てみましょう:
Model { id: triangleModel visible: false scale: Qt.vector3d(100, 100, 100) geometry: ExampleTriangleGeometry { normals: cbNorm.checked normalXY: sliderNorm.value uv: cbUV.checked uvAdjust: sliderUV.value } materials: [ DefaultMaterial { Texture { id: baseColorMap source: "qt_logo_rect.png" } cullMode: DefaultMaterial.NoCulling diffuseMap: cbTexture.checked ? baseColorMap : null specularAmount: 0.5 } ] }
ExampleTriangleGeometry
クラスを使用するために、geometry
プロパティを指定し、関連するプロパティを指定していることに注意してください。QML 側でカスタムジオメトリを使用するために必要なことはこれだけです。
次に、C++ コードのもうひとつの重要な部分、すなわちupdateData()
メソッドを見てみましょう。このメソッドは、ExampleTriangleGeometry
クラスが作成されたり、その QML プロパティが更新されたりするたびに、カスタムジオメトリのデータを作成し、アップロードします。
void ExampleTriangleGeometry::updateData() { clear(); int stride = 3 * sizeof(float); if (m_hasNormals) stride += 3 * sizeof(float); if (m_hasUV) stride += 2 * sizeof(float); QByteArray vertexData(3 * stride, Qt::Initialization::Uninitialized); float *p = reinterpret_cast<float *>(vertexData.data()); // a triangle, front face = counter-clockwise *p++ = -1.0f; *p++ = -1.0f; *p++ = 0.0f; if (m_hasNormals) { *p++ = m_normalXY; *p++ = m_normalXY; *p++ = 1.0f; } if (m_hasUV) { *p++ = 0.0f + m_uvAdjust; *p++ = 0.0f + m_uvAdjust; } *p++ = 1.0f; *p++ = -1.0f; *p++ = 0.0f; if (m_hasNormals) { *p++ = m_normalXY; *p++ = m_normalXY; *p++ = 1.0f; } if (m_hasUV) { *p++ = 1.0f - m_uvAdjust; *p++ = 0.0f + m_uvAdjust; } *p++ = 0.0f; *p++ = 1.0f; *p++ = 0.0f; if (m_hasNormals) { *p++ = m_normalXY; *p++ = m_normalXY; *p++ = 1.0f; } if (m_hasUV) { *p++ = 1.0f - m_uvAdjust; *p++ = 1.0f - m_uvAdjust; } setVertexData(vertexData); setStride(stride); setBounds(QVector3D(-1.0f, -1.0f, 0.0f), QVector3D(+1.0f, +1.0f, 0.0f)); setPrimitiveType(QQuick3DGeometry::PrimitiveType::Triangles); addAttribute(QQuick3DGeometry::Attribute::PositionSemantic, 0, QQuick3DGeometry::Attribute::F32Type); if (m_hasNormals) { addAttribute(QQuick3DGeometry::Attribute::NormalSemantic, 3 * sizeof(float), QQuick3DGeometry::Attribute::F32Type); } if (m_hasUV) { addAttribute(QQuick3DGeometry::Attribute::TexCoordSemantic, m_hasNormals ? 6 * sizeof(float) : 3 * sizeof(float), QQuick3DGeometry::Attribute::F32Type); } }
このメソッドはまずclear()
を呼び出し、以前にアップロードされたデータをすべてクリアします。次に、法線と uv 座標の存在を考慮して頂点のストライドを計算します。次に、頂点バッファを保持するバイト配列が作成され、コーナーが(-1, -1, 0)、(1, -1, 0)、(0, 1, 0)の三角形の頂点で満たされる。
その後、頂点データがアップロードされ、setVertexData()
とsetStride()
を呼び出してストライドが設定される。ジオメトリの境界は、setBounds
を呼び出して設定します。この例では使用しませんが、境界の設定は影が機能するために必要です。次に、setPrimitiveType()
を呼び出してプリミティブタイプを設定します。最後に、位置、法線、および uv 座標のアトリビュートを、各アトリビュートに対してaddAttribute()
を呼び出すことで、先にアップロードされたバッファのメモリ上に配置する方法を指定します。
©2024 The Qt Company Ltd. ここに含まれるドキュメントの著作権は、それぞれの所有者に帰属します。 本書で提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。