44void QQuick3DNodePrivate::setLocalTransform(
const QMatrix4x4 &transform)
53 if (QSSGUtils::mat44::decompose(transform, position, scale, rotation)) {
55 q->setRotation(rotation);
56 q->setPosition(position);
62 m_localTransform = transform;
65 m_hasExplicitLocalTransform =
true;
386void QQuick3DNodePrivate::calculateGlobalVariables()
389 m_sceneTransformDirty =
false;
390 QMatrix4x4 localTransform = QSSGRenderNode::calculateTransformMatrix(m_position, m_scale, m_pivot, m_rotation);
391 QQuick3DNode *parent = q->parentNode();
393 m_sceneTransform = localTransform;
394 m_hasInheritedUniformScale =
true;
397 QQuick3DNodePrivate *privateParent = QQuick3DNodePrivate::get(parent);
399 if (privateParent->m_sceneTransformDirty)
400 privateParent->calculateGlobalVariables();
401 m_sceneTransform = privateParent->m_sceneTransform * localTransform;
405 m_hasInheritedUniformScale = privateParent->m_hasInheritedUniformScale;
406 if (m_hasInheritedUniformScale) {
407 const QVector3D ps = privateParent->m_scale;
408 m_hasInheritedUniformScale = qFuzzyCompare(ps.x(), ps.y()) && qFuzzyCompare(ps.x(), ps.z());
417QMatrix4x4 QQuick3DNodePrivate::sceneRotationMatrix()
const
419 Q_Q(
const QQuick3DNode);
421 if (m_sceneTransformDirty) {
423 const_cast<QQuick3DNodePrivate *>(
this)->calculateGlobalVariables();
426 if (m_hasInheritedUniformScale) {
430 QMatrix4x4 rotationMatrix = q->sceneTransform();
431 QSSGUtils::mat44::normalize(rotationMatrix);
432 return rotationMatrix;
438 const QMatrix4x4 parentRotationMatrix = QQuick3DNodePrivate::get(q->parentNode())->sceneRotationMatrix();
439 return parentRotationMatrix * localRotationMatrix();
442void QQuick3DNodePrivate::emitChangesToSceneTransform()
445 const QVector3D prevPosition = QSSGUtils::mat44::getPosition(m_sceneTransform);
446 const QQuaternion prevRotation = QQuaternion::fromRotationMatrix(QSSGUtils::mat44::getUpper3x3(m_sceneTransform)).normalized();
447 const QVector3D prevScale = QSSGUtils::mat44::getScale(m_sceneTransform);
448 QVector3D prevForward, prevUp, prevRight;
449 QVector3D newForward, newUp, newRight;
451 bool emitDirectionChanges = (m_directionConnectionCount > 0);
452 if (emitDirectionChanges) {
456 QMatrix3x3 theDirMatrix = m_sceneTransform.normalMatrix();
457 prevForward = QSSGUtils::mat33::transform(theDirMatrix, QVector3D(0, 0, -1)).normalized();
458 prevUp = QSSGUtils::mat33::transform(theDirMatrix, QVector3D(0, 1, 0)).normalized();
459 prevRight = QSSGUtils::mat33::transform(theDirMatrix, QVector3D(1, 0, 0)).normalized();
462 calculateGlobalVariables();
464 const QVector3D newPosition = QSSGUtils::mat44::getPosition(m_sceneTransform);
465 const QQuaternion newRotation = QQuaternion::fromRotationMatrix(QSSGUtils::mat44::getUpper3x3(m_sceneTransform)).normalized();
466 const QVector3D newScale = QSSGUtils::mat44::getScale(m_sceneTransform);
467 if (emitDirectionChanges) {
468 QMatrix3x3 theDirMatrix = m_sceneTransform.normalMatrix();
469 newForward = QSSGUtils::mat33::transform(theDirMatrix, QVector3D(0, 0, -1)).normalized();
470 newUp = QSSGUtils::mat33::transform(theDirMatrix, QVector3D(0, 1, 0)).normalized();
471 newRight = QSSGUtils::mat33::transform(theDirMatrix, QVector3D(1, 0, 0)).normalized();
474 const bool positionChanged = prevPosition != newPosition;
475 const bool rotationChanged = prevRotation != newRotation;
476 const bool scaleChanged = !qFuzzyCompare(prevScale, newScale);
478 if (!positionChanged && !rotationChanged && !scaleChanged)
481 emit q->sceneTransformChanged();
484 emit q->scenePositionChanged();
486 emit q->sceneRotationChanged();
488 emit q->sceneScaleChanged();
489 if (emitDirectionChanges) {
490 const bool forwardChanged = prevForward != newForward;
491 const bool upChanged = prevUp != newUp;
492 const bool rightChanged = prevRight != newRight;
494 Q_EMIT q->forwardChanged();
496 Q_EMIT q->upChanged();
498 Q_EMIT q->rightChanged();
502bool QQuick3DNodePrivate::isSceneTransformRelatedSignal(
const QMetaMethod &signal)
const
506 static const QMetaMethod sceneTransformSignal = QMetaMethod::fromSignal(&QQuick3DNode::sceneTransformChanged);
507 static const QMetaMethod scenePositionSignal = QMetaMethod::fromSignal(&QQuick3DNode::scenePositionChanged);
508 static const QMetaMethod sceneRotationSignal = QMetaMethod::fromSignal(&QQuick3DNode::sceneRotationChanged);
509 static const QMetaMethod sceneScaleSignal = QMetaMethod::fromSignal(&QQuick3DNode::sceneScaleChanged);
511 return (signal == sceneTransformSignal
512 || signal == scenePositionSignal
513 || signal == sceneRotationSignal
514 || signal == sceneScaleSignal);
560void QQuick3DNodePrivate::markSceneTransformDirty()
572 if (m_sceneTransformDirty)
575 m_sceneTransformDirty =
true;
577 if (m_sceneTransformConnectionCount > 0 || m_directionConnectionCount > 0)
578 emitChangesToSceneTransform();
580 auto children = QQuick3DObjectPrivate::get(q)->childItems;
581 for (
auto child : children) {
582 if (
auto node = qobject_cast<QQuick3DNode *>(child)) {
583 QQuick3DNodePrivate::get(node)->markSceneTransformDirty();
627void QQuick3DNode::setRotation(
const QQuaternion &rotation)
630 if (d->m_rotation == rotation)
633 d->m_hasExplicitLocalTransform =
false;
634 d->m_rotation = rotation;
635 d->markSceneTransformDirty();
636 emit rotationChanged();
637 emit eulerRotationChanged();
642void QQuick3DNode::setPosition(
const QVector3D &position)
645 if (d->m_position == position)
648 const bool xUnchanged = qFuzzyCompare(position.x(), d->m_position.x());
649 const bool yUnchanged = qFuzzyCompare(position.y(), d->m_position.y());
650 const bool zUnchanged = qFuzzyCompare(position.z(), d->m_position.z());
652 d->m_position = position;
653 d->markSceneTransformDirty();
654 emit positionChanged();
663 d->m_hasExplicitLocalTransform =
false;
727void QQuick3DNode::setEulerRotation(
const QVector3D &eulerRotation) {
730 if (d->m_rotation == eulerRotation)
733 d->m_hasExplicitLocalTransform =
false;
734 d->m_rotation = eulerRotation;
736 emit rotationChanged();
737 d->markSceneTransformDirty();
738 emit eulerRotationChanged();
757void QQuick3DNode::rotate(qreal degrees,
const QVector3D &axis, TransformSpace space)
761 const QQuaternion addRotationQuat = QQuaternion::fromAxisAndAngle(axis,
float(degrees));
762 const QMatrix4x4 addRotationMatrix = QMatrix4x4(addRotationQuat.toRotationMatrix());
763 QMatrix4x4 newRotationMatrix;
767 newRotationMatrix = d->localRotationMatrix() * addRotationMatrix;
770 newRotationMatrix = addRotationMatrix * d->localRotationMatrix();
773 if (
const auto parent = parentNode()) {
774 const QMatrix4x4 lrm = d->localRotationMatrix();
775 const QMatrix4x4 prm = QQuick3DNodePrivate::get(parent)->sceneRotationMatrix();
776 newRotationMatrix = prm.inverted() * addRotationMatrix * prm * lrm;
778 newRotationMatrix = d->localRotationMatrix() * addRotationMatrix;
783 const QQuaternion newRotationQuaternion = QQuaternion::fromRotationMatrix(QSSGUtils::mat44::getUpper3x3(newRotationMatrix)).normalized();
785 if (d->m_rotation == newRotationQuaternion)
788 d->m_hasExplicitLocalTransform =
false;
789 d->m_rotation = newRotationQuaternion;
790 d->markSceneTransformDirty();
792 emit rotationChanged();
793 emit eulerRotationChanged();
798QSSGRenderGraphObject *QQuick3DNode::updateSpatialNode(QSSGRenderGraphObject *node)
803 node =
new QSSGRenderNode();
805 QQuick3DObject::updateSpatialNode(node);
806 auto spacialNode =
static_cast<QSSGRenderNode *>(node);
807 bool transformIsDirty =
false;
809 if (spacialNode->pivot != d->m_pivot) {
810 transformIsDirty =
true;
811 spacialNode->pivot = d->m_pivot;
814 if (!qFuzzyCompare(spacialNode->localOpacity, d->m_opacity)) {
815 spacialNode->localOpacity = d->m_opacity;
816 spacialNode->markDirty(QSSGRenderNode::DirtyFlag::OpacityDirty);
819 if (d->m_hasExplicitLocalTransform) {
820 spacialNode->localTransform = d->m_localTransform;
821 spacialNode->markDirty(QSSGRenderNode::DirtyFlag::TransformDirty);
822 d->m_hasExplicitLocalTransform =
false;
824 if (!transformIsDirty && !qFuzzyCompare(d->m_position, QSSGUtils::mat44::getPosition(spacialNode->localTransform)))
825 transformIsDirty =
true;
827 if (!transformIsDirty && !qFuzzyCompare(d->m_scale, QSSGUtils::mat44::getScale(spacialNode->localTransform)))
828 transformIsDirty =
true;
830 if (!transformIsDirty && !qFuzzyCompare(d->m_rotation, QQuaternion::fromRotationMatrix(QSSGUtils::mat44::getUpper3x3(spacialNode->localTransform))))
831 transformIsDirty =
true;
833 if (transformIsDirty) {
834 spacialNode->localTransform = QSSGRenderNode::calculateTransformMatrix(d->m_position, d->m_scale, d->m_pivot, d->m_rotation);
835 spacialNode->markDirty(QSSGRenderNode::DirtyFlag::TransformDirty);
839 if (d->m_tag != spacialNode->tag) {
840 spacialNode->tag = d->m_tag;
841 spacialNode->markDirty(QSSGRenderNode::DirtyFlag::TagDirty);
844 spacialNode->staticFlags = d->m_staticFlags;
847 if (d->m_isHiddenInEditor)
848 spacialNode->setState(QSSGRenderNode::LocalState::Active,
false);
850 spacialNode->setState(QSSGRenderNode::LocalState::Active, d->m_visible);
852 DebugViewHelpers::ensureDebugObjectName(spacialNode,
this);
947QVector3D QQuick3DNode::mapDirectionFromScene(
const QVector3D &sceneDirection)
const
949 QMatrix3x3 theDirMatrix = QSSGUtils::mat44::getUpper3x3(sceneTransform());
950 theDirMatrix = theDirMatrix.transposed();
951 return QSSGUtils::mat33::transform(theDirMatrix, sceneDirection);