How can I get transform matrix for QQuickItem?

2019-05-03 09:03发布

I worked for a long time with QGraphicsItem and it has transform() function. Now I wont to do same thing with QQuickItem but unfortunately it misses transform(). So my question - how can I get transform matrix for QQuickItem?

标签: qt qml qtquick2
3条回答
闹够了就滚
2楼-- · 2019-05-03 09:41

The QSGTransformNode class implements transformations in the scene graph. In updatePaintNode function, argument updatePaintNodeData provides a pointer to the QSGTransformNode associated with this QQuickItem.

QSGNode *MyQuickItem::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data)
{
     QSGTransformNode *transformNode = data->transformNode;
     qDebug() << transformNode->matrix();
查看更多
干净又极端
3楼-- · 2019-05-03 09:58

Actually the QQuickItem provides the transform() method, however it returns the list of all transformations assigned to given item. It is because multiple transformations can be assigned to a single Item. The return type of QQuickItem::transform is QQmlListProperty<QQuickTransform> — it is a wrapper to QML list<Transform> type (see documentation for Item). It can be iterated over, yielding QQuickTransform * elements. QQuickTransform is a base class for a transformation that provides a virtual method applyTo taking a QMatrix4x4 * argument and applying the transformation upon it.

The QML allows instantiating several QQuickTransform subclasses (for translation, rotation and scale) and user is allowed to defined custom transformations (eg. for skew).

To obtain a single transformation matrix you need, you have to start with identity matrix and sequentially apply all the transformations of given QQuickItem.

QMatrix4x4 transformOfItem(QQuickItem *item)
{
    QQmlListProperty transformations = item->transform();

    const int count = transformations.count(&transformations);

    // Prepare result structure, it will be default-initialized to be an identity matrix
    QMatrix4x4 transformMatrix;

    // Apply sequentially all transformation from the item
    for(int i = 0; i applyTo(&transformMatrix);
    }

    return transformMatrix;
}

Note that the function returns a tranformation matrix as QMatrix4x4 — it is more than old QTransform that was based on 3x3 transformation matrix, so it cannot be converted without loss. If you want, you may use QMatrix4x4::toAffine to get the QMatrix (3x3) and use it to create QTransform object. However, if your QQuickItem transformations contain non-affinic elements, they will be lost.

Edit

There's one more thing to note: the method I posted works only for transformations defined by assigning to transform property. It does not check for scale and rotation properties. If you use them, you should check their values with appropriate QQuickItem methods and adjust returned matrix to include these two additional tranformations.

查看更多
▲ chillily
4楼-- · 2019-05-03 10:01

Here's a correct solution, based on the code provided by Michael earlier, but fixed to work actually, so you don't have to spend 20 minutes figuring out how to use QQmlListProperty

QMatrix4x4 YourQQuickItem::get_model_matrix() {
    QMatrix4x4 result;

    // Compose model matrix from our transform properties in the QML
    QQmlListProperty<QQuickTransform> transformations = transform();
    const int count = transformations.count(&transformations);
    for (int i=0; i<count; i++) {
        QQuickTransform *transform = transformations.at(&transformations, i);
        transform->applyTo(&result);
    }

    return result;
}

In my use case I use this to get the model matrix for my object, then multiply together with view and projection matrixes to calculate the model-view-projection matrix.

查看更多
登录 后发表回答