42void QQuick3DNodePrivate::setLocalTransform(
const QMatrix4x4 &transform)
51 if (QSSGUtils::mat44::decompose(transform, position, scale, rotation)) {
53 q->setRotation(rotation);
54 q->setPosition(position);
60 m_localTransform = transform;
63 m_hasExplicitLocalTransform =
true;
384void QQuick3DNodePrivate::calculateGlobalVariables()
387 m_sceneTransformDirty =
false;
388 QMatrix4x4 localTransform = QSSGRenderNode::calculateTransformMatrix(m_position, m_scale, m_pivot, m_rotation);
389 QQuick3DNode *parent = q->parentNode();
391 m_sceneTransform = localTransform;
392 m_hasInheritedUniformScale =
true;
395 QQuick3DNodePrivate *privateParent = QQuick3DNodePrivate::get(parent);
397 if (privateParent->m_sceneTransformDirty)
398 privateParent->calculateGlobalVariables();
399 m_sceneTransform = privateParent->m_sceneTransform * localTransform;
403 m_hasInheritedUniformScale = privateParent->m_hasInheritedUniformScale;
404 if (m_hasInheritedUniformScale) {
405 const QVector3D ps = privateParent->m_scale;
406 m_hasInheritedUniformScale = qFuzzyCompare(ps.x(), ps.y()) && qFuzzyCompare(ps.x(), ps.z());
415QMatrix4x4 QQuick3DNodePrivate::sceneRotationMatrix()
const
417 Q_Q(
const QQuick3DNode);
419 if (m_sceneTransformDirty) {
421 const_cast<QQuick3DNodePrivate *>(
this)->calculateGlobalVariables();
424 if (m_hasInheritedUniformScale) {
428 QMatrix4x4 rotationMatrix = q->sceneTransform();
429 QSSGUtils::mat44::normalize(rotationMatrix);
430 return rotationMatrix;
436 const QMatrix4x4 parentRotationMatrix = QQuick3DNodePrivate::get(q->parentNode())->sceneRotationMatrix();
437 return parentRotationMatrix * localRotationMatrix();
440void QQuick3DNodePrivate::emitChangesToSceneTransform()
443 const QVector3D prevPosition = QSSGUtils::mat44::getPosition(m_sceneTransform);
444 const QQuaternion prevRotation = QQuaternion::fromRotationMatrix(QSSGUtils::mat44::getUpper3x3(m_sceneTransform)).normalized();
445 const QVector3D prevScale = QSSGUtils::mat44::getScale(m_sceneTransform);
446 QVector3D prevForward, prevUp, prevRight;
447 QVector3D newForward, newUp, newRight;
449 bool emitDirectionChanges = (m_directionConnectionCount > 0);
450 if (emitDirectionChanges) {
454 QMatrix3x3 theDirMatrix = m_sceneTransform.normalMatrix();
455 prevForward = QSSGUtils::mat33::transform(theDirMatrix, QVector3D(0, 0, -1)).normalized();
456 prevUp = QSSGUtils::mat33::transform(theDirMatrix, QVector3D(0, 1, 0)).normalized();
457 prevRight = QSSGUtils::mat33::transform(theDirMatrix, QVector3D(1, 0, 0)).normalized();
460 calculateGlobalVariables();
462 const QVector3D newPosition = QSSGUtils::mat44::getPosition(m_sceneTransform);
463 const QQuaternion newRotation = QQuaternion::fromRotationMatrix(QSSGUtils::mat44::getUpper3x3(m_sceneTransform)).normalized();
464 const QVector3D newScale = QSSGUtils::mat44::getScale(m_sceneTransform);
465 if (emitDirectionChanges) {
466 QMatrix3x3 theDirMatrix = m_sceneTransform.normalMatrix();
467 newForward = QSSGUtils::mat33::transform(theDirMatrix, QVector3D(0, 0, -1)).normalized();
468 newUp = QSSGUtils::mat33::transform(theDirMatrix, QVector3D(0, 1, 0)).normalized();
469 newRight = QSSGUtils::mat33::transform(theDirMatrix, QVector3D(1, 0, 0)).normalized();
472 const bool positionChanged = prevPosition != newPosition;
473 const bool rotationChanged = prevRotation != newRotation;
474 const bool scaleChanged = !qFuzzyCompare(prevScale, newScale);
476 if (!positionChanged && !rotationChanged && !scaleChanged)
479 emit q->sceneTransformChanged();
482 emit q->scenePositionChanged();
484 emit q->sceneRotationChanged();
486 emit q->sceneScaleChanged();
487 if (emitDirectionChanges) {
488 const bool forwardChanged = prevForward != newForward;
489 const bool upChanged = prevUp != newUp;
490 const bool rightChanged = prevRight != newRight;
492 Q_EMIT q->forwardChanged();
494 Q_EMIT q->upChanged();
496 Q_EMIT q->rightChanged();
500bool QQuick3DNodePrivate::isSceneTransformRelatedSignal(
const QMetaMethod &signal)
const
504 static const QMetaMethod sceneTransformSignal = QMetaMethod::fromSignal(&QQuick3DNode::sceneTransformChanged);
505 static const QMetaMethod scenePositionSignal = QMetaMethod::fromSignal(&QQuick3DNode::scenePositionChanged);
506 static const QMetaMethod sceneRotationSignal = QMetaMethod::fromSignal(&QQuick3DNode::sceneRotationChanged);
507 static const QMetaMethod sceneScaleSignal = QMetaMethod::fromSignal(&QQuick3DNode::sceneScaleChanged);
509 return (signal == sceneTransformSignal
510 || signal == scenePositionSignal
511 || signal == sceneRotationSignal
512 || signal == sceneScaleSignal);
558void QQuick3DNodePrivate::markSceneTransformDirty()
570 if (m_sceneTransformDirty)
573 m_sceneTransformDirty =
true;
575 if (m_sceneTransformConnectionCount > 0 || m_directionConnectionCount > 0)
576 emitChangesToSceneTransform();
578 auto children = QQuick3DObjectPrivate::get(q)->childItems;
579 for (
auto child : children) {
580 if (
auto node = qobject_cast<QQuick3DNode *>(child)) {
581 QQuick3DNodePrivate::get(node)->markSceneTransformDirty();
625void QQuick3DNode::setRotation(
const QQuaternion &rotation)
628 if (d->m_rotation == rotation)
631 d->m_hasExplicitLocalTransform =
false;
632 d->m_rotation = rotation;
633 d->markSceneTransformDirty();
634 emit rotationChanged();
635 emit eulerRotationChanged();
640void QQuick3DNode::setPosition(
const QVector3D &position)
643 if (d->m_position == position)
646 const bool xUnchanged = qFuzzyCompare(position.x(), d->m_position.x());
647 const bool yUnchanged = qFuzzyCompare(position.y(), d->m_position.y());
648 const bool zUnchanged = qFuzzyCompare(position.z(), d->m_position.z());
650 d->m_position = position;
651 d->markSceneTransformDirty();
652 emit positionChanged();
661 d->m_hasExplicitLocalTransform =
false;
725void QQuick3DNode::setEulerRotation(
const QVector3D &eulerRotation) {
728 if (d->m_rotation == eulerRotation)
731 d->m_hasExplicitLocalTransform =
false;
732 d->m_rotation = eulerRotation;
734 emit rotationChanged();
735 d->markSceneTransformDirty();
736 emit eulerRotationChanged();
755void QQuick3DNode::rotate(qreal degrees,
const QVector3D &axis, TransformSpace space)
759 const QQuaternion addRotationQuat = QQuaternion::fromAxisAndAngle(axis,
float(degrees));
760 const QMatrix4x4 addRotationMatrix = QMatrix4x4(addRotationQuat.toRotationMatrix());
761 QMatrix4x4 newRotationMatrix;
765 newRotationMatrix = d->localRotationMatrix() * addRotationMatrix;
768 newRotationMatrix = addRotationMatrix * d->localRotationMatrix();
771 if (
const auto parent = parentNode()) {
772 const QMatrix4x4 lrm = d->localRotationMatrix();
773 const QMatrix4x4 prm = QQuick3DNodePrivate::get(parent)->sceneRotationMatrix();
774 newRotationMatrix = prm.inverted() * addRotationMatrix * prm * lrm;
776 newRotationMatrix = d->localRotationMatrix() * addRotationMatrix;
781 const QQuaternion newRotationQuaternion = QQuaternion::fromRotationMatrix(QSSGUtils::mat44::getUpper3x3(newRotationMatrix)).normalized();
783 if (d->m_rotation == newRotationQuaternion)
786 d->m_hasExplicitLocalTransform =
false;
787 d->m_rotation = newRotationQuaternion;
788 d->markSceneTransformDirty();
790 emit rotationChanged();
791 emit eulerRotationChanged();
796QSSGRenderGraphObject *QQuick3DNode::updateSpatialNode(QSSGRenderGraphObject *node)
801 node =
new QSSGRenderNode();
803 QQuick3DObject::updateSpatialNode(node);
804 auto spacialNode =
static_cast<QSSGRenderNode *>(node);
805 bool transformIsDirty =
false;
807 if (spacialNode->pivot != d->m_pivot) {
808 transformIsDirty =
true;
809 spacialNode->pivot = d->m_pivot;
812 if (!qFuzzyCompare(spacialNode->localOpacity, d->m_opacity)) {
813 spacialNode->localOpacity = d->m_opacity;
814 spacialNode->markDirty(QSSGRenderNode::DirtyFlag::OpacityDirty);
817 if (d->m_hasExplicitLocalTransform) {
818 spacialNode->localTransform = d->m_localTransform;
819 spacialNode->markDirty(QSSGRenderNode::DirtyFlag::TransformDirty);
820 d->m_hasExplicitLocalTransform =
false;
822 if (!transformIsDirty && !qFuzzyCompare(d->m_position, QSSGUtils::mat44::getPosition(spacialNode->localTransform)))
823 transformIsDirty =
true;
825 if (!transformIsDirty && !qFuzzyCompare(d->m_scale, QSSGUtils::mat44::getScale(spacialNode->localTransform)))
826 transformIsDirty =
true;
828 if (!transformIsDirty && !qFuzzyCompare(d->m_rotation, QQuaternion::fromRotationMatrix(QSSGUtils::mat44::getUpper3x3(spacialNode->localTransform))))
829 transformIsDirty =
true;
831 if (transformIsDirty) {
832 spacialNode->localTransform = QSSGRenderNode::calculateTransformMatrix(d->m_position, d->m_scale, d->m_pivot, d->m_rotation);
833 spacialNode->markDirty(QSSGRenderNode::DirtyFlag::TransformDirty);
837 if (d->m_tag != spacialNode->tag) {
838 spacialNode->tag = d->m_tag;
839 spacialNode->markDirty(QSSGRenderNode::DirtyFlag::TagDirty);
842 spacialNode->staticFlags = d->m_staticFlags;
845 if (d->m_isHiddenInEditor)
846 spacialNode->setState(QSSGRenderNode::LocalState::Active,
false);
848 spacialNode->setState(QSSGRenderNode::LocalState::Active, d->m_visible);
850 DebugViewHelpers::ensureDebugObjectName(spacialNode,
this);
945QVector3D QQuick3DNode::mapDirectionFromScene(
const QVector3D &sceneDirection)
const
947 QMatrix3x3 theDirMatrix = QSSGUtils::mat44::getUpper3x3(sceneTransform());
948 theDirMatrix = theDirMatrix.transposed();
949 return QSSGUtils::mat33::transform(theDirMatrix, sceneDirection);