Qt Quick 3D - 커스텀 모핑 애니메이션
모프 타깃이 있는 C++ 커스텀 지오메트리를 작성하는 방법을 보여줍니다.
이 예제에서는 기본 모양과 모프 타깃을 포함하는 복잡한 커스텀 지오메트리를 C++로 정의하는 방법과 두 가지 모두에 대해 노멀 벡터를 사용하는 방법을 보여줍니다.
커스텀 지오메트리
이 예제의 주요 부분은 모프 타깃이 있는 커스텀 지오메트리를 만드는 것입니다. QQuick3DGeometry 을 서브클래싱하여 이를 수행합니다:
class MorphGeometry : public QQuick3DGeometry { Q_OBJECT QML_NAMED_ELEMENT(MorphGeometry) Q_PROPERTY(int gridSize READ gridSize WRITE setGridSize NOTIFY gridSizeChanged) public: MorphGeometry(QQuick3DObject *parent = nullptr); int gridSize() { return m_gridSize; } void setGridSize(int gridSize); signals: void gridSizeChanged(); private: void calculateGeometry(); void updateData(); QList<QVector3D> m_positions; QList<QVector3D> m_normals; QList<QVector4D> m_colors; QList<QVector3D> m_targetPositions; QList<QVector3D> m_targetNormals; QList<QVector4D> m_targetColors; QList<quint32> m_indexes; QByteArray m_vertexBuffer; QByteArray m_indexBuffer; QByteArray m_targetBuffer; int m_gridSize = 50; QVector3D boundsMin; QVector3D boundsMax; };
생성자는 메시 데이터의 레이아웃을 정의합니다:
MorphGeometry::MorphGeometry(QQuick3DObject *parent) : QQuick3DGeometry(parent) { updateData(); }
updateData
함수는 메시 지오메트리의 실제 업로드를 수행합니다:
void MorphGeometry::updateData() { clear(); calculateGeometry(); addAttribute(QQuick3DGeometry::Attribute::PositionSemantic, 0, QQuick3DGeometry::Attribute::ComponentType::F32Type); addAttribute(QQuick3DGeometry::Attribute::NormalSemantic, 3 * sizeof(float), QQuick3DGeometry::Attribute::ComponentType::F32Type); addAttribute(QQuick3DGeometry::Attribute::ColorSemantic, 6 * sizeof(float), QQuick3DGeometry::Attribute::ComponentType::F32Type); addTargetAttribute(0, QQuick3DGeometry::Attribute::PositionSemantic, 0); addTargetAttribute(0, QQuick3DGeometry::Attribute::NormalSemantic, m_targetPositions.size() * sizeof(float) * 3); addTargetAttribute(0, QQuick3DGeometry::Attribute::ColorSemantic, m_targetPositions.size() * sizeof(float) * 3 + m_targetNormals.size() * sizeof(float) * 3); addAttribute(QQuick3DGeometry::Attribute::IndexSemantic, 0, QQuick3DGeometry::Attribute::ComponentType::U32Type); const int numVertexes = m_positions.size(); m_vertexBuffer.resize(numVertexes * sizeof(Vertex)); Vertex *vert = reinterpret_cast<Vertex *>(m_vertexBuffer.data()); for (int i = 0; i < numVertexes; ++i) { Vertex &v = vert[i]; v.position = m_positions[i]; v.normal = m_normals[i]; v.color = m_colors[i]; } m_targetBuffer.append(QByteArray(reinterpret_cast<char *>(m_targetPositions.data()), m_targetPositions.size() * sizeof(QVector3D))); m_targetBuffer.append(QByteArray(reinterpret_cast<char *>(m_targetNormals.data()), m_targetNormals.size() * sizeof(QVector3D))); m_targetBuffer.append(QByteArray(reinterpret_cast<char *>(m_targetColors.data()), m_targetColors.size() * sizeof(QVector4D))); setStride(sizeof(Vertex)); setVertexData(m_vertexBuffer); setTargetData(m_targetBuffer); setPrimitiveType(QQuick3DGeometry::PrimitiveType::Triangles); setBounds(boundsMin, boundsMax); m_indexBuffer = QByteArray(reinterpret_cast<char *>(m_indexes.data()), m_indexes.size() * sizeof(quint32)); setIndexData(m_indexBuffer); }
생성자에서 updateData
함수를 호출하고 프로퍼티가 변경되면 호출합니다.
calculateGeometry
함수는 도형과 법선 벡터를 계산하는 지루한 수학을 모두 포함하고 있습니다. 이는 이 예시에만 해당되며 코드에 대해서는 자세히 설명하지 않겠습니다. 일반적으로 부드러운 음영을 구현하려면 각 정점에 대한 노멀 벡터를 계산해야 합니다. 수학적으로 노멀 벡터는 평면을 설명하는 함수의 부분 도함수에서 계산할 수 있습니다:
이 예에서는 기본 도형에 코사인파를 사용하고 그 도함수가 사인 함수라는 것을 알기 때문에 간단하게 계산할 수 있습니다.
실제로 노멀 벡터는 기하학적 추론으로 결정할 수 있는 경우가 많습니다. 모프 대상의 경우, 구의 중심에서 표면까지의 모든 벡터가 해당 지점에서 구에 대해 법선이라는 사실을 사용합니다. QtQuick3D 의 노멀 벡터는 단위 길이가 있어야 하며, QVector3D::normalized()을 사용하여 이를 수행할 수 있습니다.
QML 부분
사용자 정의 지오메트리에서 만든 것에 해당하는 모프 타겟을 정의하고 가중치에 애니메이션을 적용하여 두 모양 사이를 순환하도록 합니다:
MorphTarget { id: morphtarget attributes: MorphTarget.Position | MorphTarget.Normal | MorphTarget.Color SequentialAnimation on weight { PauseAnimation { duration: 1000 } NumberAnimation { from: 0; to: 1; duration: 4000 } PauseAnimation { duration: 1000 } NumberAnimation { from: 1; to: 0; duration: 4000 } loops: Animation.Infinite } }
마지막으로 커스텀 지오메트리를 사용하여 모델을 만들고 모프 타깃을 적용합니다:
Model { y: -1 geometry: MorphGeometry {} morphTargets: [ morphtarget ] materials: [ material ] }
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.