summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Krus <mike.krus@kdab.com>2024-01-12 16:11:33 +0000
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2024-01-16 10:29:22 +0000
commit994be9f2fef5ae94441185246622323ea0cef41f (patch)
tree9843402a1565c3fc6848b426327dd4840d8b985e
parent6907e014f23fabdf8cf1637f6cc200adb84dd285 (diff)
Fix issue with camera shaking with large offset values
If the case where the scene uses a QCamera, and that that camera is not child of a node that has a transform component, the renderview will use the viewMatrix computed from the frontend. In all other cases, it will continue to recompute the viewMatrix based on parameters of the camera and apply parent transformations. Task-number: QTBUG-69463 Pick-to: 6.5 5.15 Change-Id: I8300a4fd82c527ad3412e81b96633409794b3b1f Reviewed-by: Paul Lemire <paul.lemire@kdab.com> (cherry picked from commit f8b1ca7bf17e53aa055e1963f60bb4fe6794e527) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> (cherry picked from commit 484f1ae5edd0d1510f49d31517752b421a3b323c)
-rw-r--r--src/plugins/renderers/opengl/renderer/renderview.cpp12
-rw-r--r--src/plugins/renderers/rhi/renderer/renderview.cpp12
-rw-r--r--src/render/backend/entity.cpp1
-rw-r--r--src/render/backend/entity_p.h3
-rw-r--r--src/render/backend/transform.cpp8
-rw-r--r--src/render/backend/transform_p.h4
-rw-r--r--src/render/jobs/updateworldtransformjob.cpp7
7 files changed, 40 insertions, 7 deletions
diff --git a/src/plugins/renderers/opengl/renderer/renderview.cpp b/src/plugins/renderers/opengl/renderer/renderview.cpp
index 324e63af9..8cd22eaa2 100644
--- a/src/plugins/renderers/opengl/renderer/renderview.cpp
+++ b/src/plugins/renderers/opengl/renderer/renderview.cpp
@@ -1077,8 +1077,16 @@ void RenderView::updateRenderCommand(const EntityRenderCommandDataSubView &subVi
void RenderView::updateMatrices()
{
if (m_renderCameraNode && m_renderCameraLens && m_renderCameraLens->isEnabled()) {
- const Matrix4x4 cameraWorld = *(m_renderCameraNode->worldTransform());
- setViewMatrix(m_renderCameraLens->viewMatrix(cameraWorld));
+ auto transform = m_renderCameraNode->renderComponent<Transform>();
+ if (m_renderCameraNode->isParentLessTransform() && transform && transform->hasViewMatrix()) {
+ // optimization: if the entity is a QCamera and it doesn't have a parent with a transform component,
+ // then we use the frontend version of the viewMatrix to avoid extra calculations that may introduce
+ // rounding errors
+ setViewMatrix(transform->viewMatrix());
+ } else {
+ const Matrix4x4 cameraWorld = *(m_renderCameraNode->worldTransform());
+ setViewMatrix(m_renderCameraLens->viewMatrix(cameraWorld));
+ }
setViewProjectionMatrix(m_renderCameraLens->projection() * viewMatrix());
//To get the eyePosition of the camera, we need to use the inverse of the
diff --git a/src/plugins/renderers/rhi/renderer/renderview.cpp b/src/plugins/renderers/rhi/renderer/renderview.cpp
index 60a447ae6..644654930 100644
--- a/src/plugins/renderers/rhi/renderer/renderview.cpp
+++ b/src/plugins/renderers/rhi/renderer/renderview.cpp
@@ -1172,8 +1172,16 @@ void RenderView::updateMatrices()
{
if (m_renderCameraNode && m_renderCameraLens
&& m_renderCameraLens->isEnabled()) {
- const Matrix4x4 cameraWorld = *(m_renderCameraNode->worldTransform());
- setViewMatrix(m_renderCameraLens->viewMatrix(cameraWorld));
+ auto transform = m_renderCameraNode->renderComponent<Transform>();
+ if (m_renderCameraNode->isParentLessTransform() && transform && transform->hasViewMatrix()) {
+ // optimization: if the entity is a QCamera and it doesn't have a parent with a transform component,
+ // then we use the frontend version of the viewMatrix to avoid extra calculations that may introduce
+ // rounding errors
+ setViewMatrix(transform->viewMatrix());
+ } else {
+ const Matrix4x4 cameraWorld = *(m_renderCameraNode->worldTransform());
+ setViewMatrix(m_renderCameraLens->viewMatrix(cameraWorld));
+ }
setViewProjectionMatrix(m_renderCameraLens->projection() * viewMatrix());
// To get the eyePosition of the camera, we need to use the inverse of the
diff --git a/src/render/backend/entity.cpp b/src/render/backend/entity.cpp
index 2b90c4996..e83b98e29 100644
--- a/src/render/backend/entity.cpp
+++ b/src/render/backend/entity.cpp
@@ -67,6 +67,7 @@ void EntityPrivate::componentRemoved(Qt3DCore::QNode *frontend)
Entity::Entity()
: BackendNode(*new EntityPrivate)
, m_nodeManagers(nullptr)
+ , m_parentLessTransform(true)
, m_boundingDirty(false)
, m_treeEnabled(true)
{
diff --git a/src/render/backend/entity_p.h b/src/render/backend/entity_p.h
index 734bc15ae..e7e6278e2 100644
--- a/src/render/backend/entity_p.h
+++ b/src/render/backend/entity_p.h
@@ -73,6 +73,8 @@ public:
Matrix4x4 *worldTransform();
const Matrix4x4 *worldTransform() const;
+ bool isParentLessTransform() const { return m_parentLessTransform; }
+ void setParentLessTransform(bool v) { m_parentLessTransform = v; }
Sphere *localBoundingVolume() const { return m_localBoundingVolume.data(); }
Sphere *worldBoundingVolume() const { return m_worldBoundingVolume.data(); }
Sphere *worldBoundingVolumeWithChildren() const { return m_worldBoundingVolumeWithChildren.data(); }
@@ -151,6 +153,7 @@ private:
QList<HEntity> m_childrenHandles;
HMatrix m_worldTransform;
+ bool m_parentLessTransform;
QSharedPointer<Sphere> m_localBoundingVolume;
QSharedPointer<Sphere> m_worldBoundingVolume;
QSharedPointer<Sphere> m_worldBoundingVolumeWithChildren;
diff --git a/src/render/backend/transform.cpp b/src/render/backend/transform.cpp
index 8999acaed..bca31a8ef 100644
--- a/src/render/backend/transform.cpp
+++ b/src/render/backend/transform.cpp
@@ -6,6 +6,7 @@
#include <Qt3DCore/private/qchangearbiter_p.h>
#include <Qt3DCore/qtransform.h>
#include <Qt3DCore/private/qtransform_p.h>
+#include <Qt3DRender/qcamera.h>
QT_BEGIN_NAMESPACE
@@ -65,6 +66,13 @@ void Transform::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
m_translation = transform->translation();
if (dirty || firstTime) {
+ auto camera = qobject_cast<const Qt3DRender::QCamera *>(transform->parentNode());
+ if (camera) {
+ m_viewMatrix = Matrix4x4(camera->viewMatrix());
+ m_hasViewMatrix = true;
+ } else {
+ m_hasViewMatrix = false;
+ }
updateMatrix();
markDirty(AbstractRenderer::TransformDirty);
}
diff --git a/src/render/backend/transform_p.h b/src/render/backend/transform_p.h
index 84a2f9962..d6ea68c0c 100644
--- a/src/render/backend/transform_p.h
+++ b/src/render/backend/transform_p.h
@@ -36,6 +36,8 @@ public:
void cleanup();
Matrix4x4 transformMatrix() const;
+ bool hasViewMatrix() const { return m_hasViewMatrix; }
+ const Matrix4x4& viewMatrix() const { return m_viewMatrix; }
QVector3D scale() const;
QQuaternion rotation() const;
QVector3D translation() const;
@@ -44,6 +46,8 @@ public:
private:
void updateMatrix();
+ bool m_hasViewMatrix;
+ Matrix4x4 m_viewMatrix;
Matrix4x4 m_transformMatrix;
QQuaternion m_rotation;
QVector3D m_scale;
diff --git a/src/render/jobs/updateworldtransformjob.cpp b/src/render/jobs/updateworldtransformjob.cpp
index ea6950bfd..f7f1528eb 100644
--- a/src/render/jobs/updateworldtransformjob.cpp
+++ b/src/render/jobs/updateworldtransformjob.cpp
@@ -28,7 +28,7 @@ struct TransformUpdate
QMatrix4x4 worldTransformMatrix;
};
-void updateWorldTransformAndBounds(NodeManagers *manager, Entity *node, const Matrix4x4 &parentTransform, QList<TransformUpdate> &updatedTransforms)
+void updateWorldTransformAndBounds(NodeManagers *manager, Entity *node, const Matrix4x4 &parentTransform, bool hasParentTransform, QList<TransformUpdate> &updatedTransforms)
{
if (!node->isEnabled())
return;
@@ -45,12 +45,13 @@ void updateWorldTransformAndBounds(NodeManagers *manager, Entity *node, const Ma
if (hasTransformComponent)
updatedTransforms.push_back({nodeTransform->peerId(), convertToQMatrix4x4(worldTransform)});
}
+ node->setParentLessTransform(!hasParentTransform);
const auto &childrenHandles = node->childrenHandles();
for (const HEntity &handle : childrenHandles) {
Entity *child = manager->renderNodesManager()->data(handle);
if (child)
- updateWorldTransformAndBounds(manager, child, worldTransform, updatedTransforms);
+ updateWorldTransformAndBounds(manager, child, worldTransform, hasParentTransform || hasTransformComponent, updatedTransforms);
}
}
@@ -101,7 +102,7 @@ void UpdateWorldTransformJob::run()
Entity *parent = m_node->parent();
if (parent != nullptr)
parentTransform = *(parent->worldTransform());
- updateWorldTransformAndBounds(m_manager, m_node, parentTransform, d->m_updatedTransforms);
+ updateWorldTransformAndBounds(m_manager, m_node, parentTransform, false, d->m_updatedTransforms);
qCDebug(Jobs) << "Exiting" << Q_FUNC_INFO << QThread::currentThread();
}