Qt Quick 3D - 自定义几何形状示例
演示从 C++ 和 QML 提供自定义顶点数据。
本示例使用 QQuick3DGeometry 和模型 几何属性 来渲染一个网格,该网格的顶点、法线和纹理坐标是从 C++ 和 QML 中指定的,而不是预烘焙的资产。
此外,还演示了 GridGeometry。 GridGeometry 是一个内置的 QQuick3DGeometry 实现,它提供了一个适用于显示网格的线图元网格。
本示例将重点放在提供自定义几何形状的代码上,因此让我们首先看看 C++ 的头文件 ExampleTriangleGeometry
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 } ] }
注意,我们指定了 geometry
属性以使用我们的 ExampleTriangleGeometry
类,并指定了相关属性。这是 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()
设置原语类型。最后,我们通过为每个属性调用 addAttribute()
来指定在先前上载的缓冲区中内存中如何布局位置、法线和 uv 坐标属性。
文件
- customgeometry/CMakeLists.txt
- customgeometry/Main.qml
- customgeometry/TorusMesh.qml
- customgeometry/customgeometry.pro
- customgeometry/examplegeometry.cpp
- customgeometry/examplegeometry.h
- customgeometry/main.cpp
- customgeometry/qmldir
图像
© 2024Qt公司。本文件中包含的文档贡献权属于各自所有者。提供的文档受GNU自由文档许可证版本1.3的条款约束,由自由软件基金会颁布。Qt及其相关标识是芬兰及/或其他国家/地区的商标,归Qt公司所有。其他所有商标归各自所有者所有。