Search code examples
animationtransformqt3d

Animation of Qt3D entities by reference


I'm trying to animate a Qt3D entity without having to call QTransform setters each time a value of the underlying object changes. QTransform takes references as arguments to setTranslation, setMatrix, etc. One would expect that when the value of the object passed as a reference argument changes, the transform would be automatically updated at the next scene refresh. However I see that the reference passed to setTranslation is converted to a value, meaning that changes to the source reference object are not propagated to the QTransform.

QVector3D position = QVector3D(1.0f, 2.0f, 3.0f);

Qt3DCore::QTransform transform = new Qt3DCore::QTransform();
transform->setTranslation(position);

qDebug() << transform->translation();

position.setX(2.0f);

qDebug() << transform->translation();

The output of this is :

QVector3D(1, 2, 3)
QVector3D(1, 2, 3)

But the desired result would be:

QVector3D(1, 2, 3)
QVector3D(2, 2, 3)

Is there any way to pass a reference or pointer to QTransform such that changes to objects passed by reference to its setters would automatically be propagated to the transform without having to explicitly call one of its setters with the new values?


Solution

  • Short answer:

    No, there isn't.

    Explanation:

    To understand why you need to know how Qt3D works internally. There are these so-called frontend nodes which are the ones that you can create in code (like in your example). Without you noticing, Qt3D creates a backend node for each frontend node on its creation. These two are linked and a separate thread takes care of taking any updated values from the frontend node to the backend node. I.e. when you set a value on the frontend node, the frontend node signals that it received a value change and the update thread can set the values on the backend.

    The actual rendering then only uses the backend nodes, the renderer never sees your created frontend nodes directly. If you now in any way bypass the setter of the frontend node's attributes, they will never get passed to the backend (aside from being technically infeasible for the reason you stated in your question, i.e. that the reference gets stored as a value).

    You can see the backend nodes for rendering here: https://github.com/qt/qt3d/tree/dev/src/render/backend

    But maybe it's also not that bad to use the setter? I get your point that you would have to only change one matrix and all nodes have their updates but it's just 2-3 lines more to use the setters in a loop. And computationally is neglectable since a for-loop even with 10.000 objects is usually executed pretty fast and I guess that the heavier load is on the thread updating all the backend nodes.