summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Lemire <paul.lemire@kdab.com>2015-01-21 15:23:39 +0100
committerPaul Lemire <paul.lemire@kdab.com>2015-01-24 14:30:24 +0100
commiteeab3dabf1b374867377128330c302228759bb5f (patch)
treefd7620fd743a0a57bf7f2f8dff9a9c756c65f100
parent7bc827504190858bccdff82f63211f4988bc48df (diff)
RenderShaderData: ModelToEye/ModelToWorld property transform
* Reuse jobs in QRenderAspect * Added FramePreparationJob which: - updates RenderShaderData with node world matrix - create bounding volume for nodes * RenderShaderData slightly modified to accommodate the transformed properties - needsUpdate now takes the viewMatrix - fix a bug where for a nested array, order wasn't maintained if not all the elements had been updated Change-Id: I0d91dc1d52c4333be74cce56c334aea70498138e Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
-rw-r--r--src/render/backend/jobs/framepreparationjob.cpp105
-rw-r--r--src/render/backend/jobs/framepreparationjob_p.h81
-rw-r--r--src/render/backend/jobs/render-jobs.pri6
-rw-r--r--src/render/backend/jobs/renderviewjob.cpp4
-rw-r--r--src/render/backend/jobs/renderviewjobutils.cpp52
-rw-r--r--src/render/backend/jobs/renderviewjobutils_p.h2
-rw-r--r--src/render/backend/qrenderaspect.cpp23
-rw-r--r--src/render/backend/qrenderaspect_p.h9
-rw-r--r--src/render/backend/rendermesh.cpp7
-rw-r--r--src/render/backend/rendermesh_p.h3
-rw-r--r--src/render/backend/rendershaderdata.cpp88
-rw-r--r--src/render/backend/rendershaderdata_p.h15
-rw-r--r--src/render/backend/renderview.cpp17
-rw-r--r--src/render/backend/renderview_p.h5
-rw-r--r--src/render/frontend/sphere.h2
15 files changed, 331 insertions, 88 deletions
diff --git a/src/render/backend/jobs/framepreparationjob.cpp b/src/render/backend/jobs/framepreparationjob.cpp
new file mode 100644
index 000000000..fff252a9b
--- /dev/null
+++ b/src/render/backend/jobs/framepreparationjob.cpp
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "framepreparationjob_p.h"
+#include <Qt3DRenderer/private/renderer_p.h>
+#include <Qt3DRenderer/private/renderentity_p.h>
+#include <Qt3DRenderer/private/rendermesh_p.h>
+#include <Qt3DRenderer/private/rendershaderdata_p.h>
+#include <Qt3DRenderer/qmeshdata.h>
+#include <Qt3DRenderer/sphere.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3D {
+
+namespace Render {
+
+FramePreparationJob::FramePreparationJob(Renderer *renderer, RenderEntity *root)
+ : m_renderer(renderer)
+ , m_root(root)
+{
+}
+
+FramePreparationJob::~FramePreparationJob()
+{
+
+}
+
+void FramePreparationJob::run()
+{
+ parseNodeTree(m_root);
+}
+
+void FramePreparationJob::parseNodeTree(RenderEntity *node)
+{
+ // Initialize worldBoundingVolume if Mesh associated
+ Qt3D::Render::RenderMesh *mesh = Q_NULLPTR;
+ if ((node->localBoundingVolume()->isNull())
+ && (mesh = node->renderComponent<RenderMesh>()) != Q_NULLPTR) {
+ if (!mesh->meshDataHandle().isNull()) {
+ Qt3D::QMeshData *meshData = mesh->meshData();
+ if (meshData != Q_NULLPTR) {
+ const QAxisAlignedBoundingBox box = meshData->boundingBox();
+ node->localBoundingVolume()->setCenter(box.center());
+ const QVector3D &radii = box.radii();
+ node->localBoundingVolume()->setRadius(qMax(radii.x(), qMax(radii.y(), radii.z())));
+ qDebug() << node->localBoundingVolume()->center() << node->localBoundingVolume()->radius();
+ }
+ }
+ }
+
+ // Update transform properties in RenderShaderData
+ QList<RenderShaderData *> shadersData = node->renderComponents<RenderShaderData>();
+ Q_FOREACH (RenderShaderData *r, shadersData) {
+ r->updateTransformedProperties(*node->worldTransform());
+ }
+
+ // Traverse children
+ Q_FOREACH (RenderEntity *child, node->children())
+ parseNodeTree(child);
+}
+
+} // Render
+
+} // Qt3D
+
+QT_END_NAMESPACE
diff --git a/src/render/backend/jobs/framepreparationjob_p.h b/src/render/backend/jobs/framepreparationjob_p.h
new file mode 100644
index 000000000..63513b82e
--- /dev/null
+++ b/src/render/backend/jobs/framepreparationjob_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3D_RENDER_FRAMEPREPARATIONJOB_H
+#define QT3D_RENDER_FRAMEPREPARATIONJOB_H
+
+#include <Qt3DCore/qaspectjob.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3D {
+
+namespace Render {
+
+class Renderer;
+class RenderEntity;
+
+class FramePreparationJob : public Qt3D::QAspectJob
+{
+public:
+ FramePreparationJob(Renderer *renderer, RenderEntity *root);
+ ~FramePreparationJob();
+
+protected:
+ void run() Q_DECL_FINAL;
+
+private:
+
+ void parseNodeTree(RenderEntity *node);
+
+ Renderer *m_renderer;
+ RenderEntity *m_root;
+};
+
+typedef QSharedPointer<FramePreparationJob> FramePreparationJobPtr;
+
+} // Render
+
+} // Qt3D
+
+QT_END_NAMESPACE
+
+#endif // QT3D_RENDER_FRAMEPREPARATIONJOB_H
diff --git a/src/render/backend/jobs/render-jobs.pri b/src/render/backend/jobs/render-jobs.pri
index 304ed0d53..4b1b750fc 100644
--- a/src/render/backend/jobs/render-jobs.pri
+++ b/src/render/backend/jobs/render-jobs.pri
@@ -7,7 +7,8 @@ HEADERS += \
$$PWD/renderviewjob_p.h \
$$PWD/renderviewjobutils_p.h \
$$PWD/loadscenejob_p.h \
- $$PWD/framecleanupjob_p.h
+ $$PWD/framecleanupjob_p.h \
+ $$PWD/framepreparationjob_p.h
SOURCES += \
$$PWD/updateworldtransformjob.cpp \
@@ -16,4 +17,5 @@ SOURCES += \
$$PWD/renderviewjob.cpp \
$$PWD/renderviewjobutils.cpp \
$$PWD/loadscenejob.cpp \
- $$PWD/framecleanupjob.cpp
+ $$PWD/framecleanupjob.cpp \
+ $$PWD/framepreparationjob.cpp
diff --git a/src/render/backend/jobs/renderviewjob.cpp b/src/render/backend/jobs/renderviewjob.cpp
index 6f1344616..565b0f67e 100644
--- a/src/render/backend/jobs/renderviewjob.cpp
+++ b/src/render/backend/jobs/renderviewjob.cpp
@@ -70,10 +70,6 @@ void RenderViewJob::run()
// Populate the renderview's configuration from the framegraph
setRenderViewConfigFromFrameGraphLeafNode(renderView, m_fgLeaf);
- // Gather resources needed for buildRenderCommand
- // Ex lights, we need all lights in the scene before we can buildRenderCommands
- preprocessRenderTree(renderView, m_renderer->renderSceneRoot());
-
// Build RenderCommand should perform the culling as we have no way to determine
// if a child has a mesh in the view frustrum while its parent isn't contained in it.
renderView->buildRenderCommands(m_renderer->renderSceneRoot());
diff --git a/src/render/backend/jobs/renderviewjobutils.cpp b/src/render/backend/jobs/renderviewjobutils.cpp
index 74d0a8a76..52f20ab03 100644
--- a/src/render/backend/jobs/renderviewjobutils.cpp
+++ b/src/render/backend/jobs/renderviewjobutils.cpp
@@ -188,58 +188,6 @@ void setRenderViewConfigFromFrameGraphLeafNode(RenderView *rv, const FrameGraphN
/*!
\internal
- Walks the scene graph of RenderEntities rooted at \p node and collects
- together any resources needed by the \p rv.
-*/
-void preprocessRenderTree(RenderView *rv, const RenderEntity *node)
-{
- // The goal is to use QShaderData in a later revision
-
- // Note : Layer filtering isn't applied there
- // TODO: Perhaps make this block of code configurable by allowing the Technique
- // or similar to provide a functor?
-
- // For each of entity that has a QShaderData component we need to save the worldTransform so that we can
- // later use the shaderData with the correct space transforms
-
- // COMMENTED FOR NOW AS THERE ARE ISSUES WITH MULTIPLE RENDERVIEWS
- // AS THE TRANSFORMS ARE COMPUTED BASED ON THE RENDERVIEWS' VIEWMATRIX
- // AND SINCE THERE CAN BE SEVERAL RENDERVIEWS FOR A SINGLE QSHADERDATA
- // THIS RESULT IN TWO JOBS UPDATING THE RENDERSHADERDATA AT THE SAME TIME
- // Moving that to the RenderView::setUniformBlock could solve that
-
- // QList<RenderShaderData *> shadersData = node->renderComponents<RenderShaderData>();
- // Q_FOREACH (RenderShaderData *r, shadersData) {
- // if (r) {
- // QHash<QString, QVariant> &shaderProperties = r->properties();
- // QHash<QString, QVariant>::iterator it = shaderProperties.begin();
- // const QHash<QString, QVariant>::iterator itEnd = shaderProperties.end();
-
- // while (it != itEnd) {
- // if (static_cast<QMetaType::Type>(it.value().type()) == QMetaType::QVector3D) {
- // // If we have a QVector3D property value, we try to look
- // // if there is a matching QShaderData::TransformType propertyTransformed
- // QVariant value = shaderProperties.value(it.key() + QStringLiteral("Transformed"));
- // // if that's the case, we apply a space transformation to the property
- // if (value.isValid() && value.type() == QVariant::Int) {
- // if (static_cast<QShaderData::TransformType>(value.toInt()) == QShaderData::ModelToEye)
- // it.value() = QVariant(rv->viewmatrix() * *node->worldTransform() * it.value().value<QVector3D>());
- // else // ModelToWorld
- // it.value() = QVariant(*node->worldTransform() * it.value().value<QVector3D>());
- // }
- // }
- // ++it;
- // }
- // }
- // }
-
- // Traverse children
- Q_FOREACH (RenderEntity *child, node->children())
- preprocessRenderTree(rv, child);
-}
-
-/*!
- \internal
Searches the \a renderer for the best matching RenderTechnique from
\a effect specified by the \a renderView.
*/
diff --git a/src/render/backend/jobs/renderviewjobutils_p.h b/src/render/backend/jobs/renderviewjobutils_p.h
index 25ee25033..b54ab0733 100644
--- a/src/render/backend/jobs/renderviewjobutils_p.h
+++ b/src/render/backend/jobs/renderviewjobutils_p.h
@@ -69,8 +69,6 @@ class Renderer;
Q_AUTOTEST_EXPORT void setRenderViewConfigFromFrameGraphLeafNode(RenderView *rv,
const FrameGraphNode *fgLeaf);
-Q_AUTOTEST_EXPORT void preprocessRenderTree(RenderView *rv, const RenderEntity *node);
-
Q_AUTOTEST_EXPORT RenderTechnique *findTechniqueForEffect(Renderer *renderer,
RenderView *renderView,
RenderEffect *effect);
diff --git a/src/render/backend/qrenderaspect.cpp b/src/render/backend/qrenderaspect.cpp
index e8ab17f0a..787d7d6c0 100644
--- a/src/render/backend/qrenderaspect.cpp
+++ b/src/render/backend/qrenderaspect.cpp
@@ -234,6 +234,11 @@ QVector<QAspectJobPtr> QRenderAspect::jobsToExecute(qint64 time)
// Create jobs to load in any meshes that are pending
if (d->m_renderer != Q_NULLPTR) {
+ d->m_framePreparationJob.reset(new Render::FramePreparationJob(d->m_renderer, d->m_renderer->renderSceneRoot()));
+ d->m_cleanupJob.reset(new Render::FrameCleanupJob(d->m_renderer));
+ d->m_worldTransformJob.reset(new Render::UpdateWorldTransformJob(d->m_renderer->renderSceneRoot()));
+ d->m_boundingVolumeJob.reset(new Render::UpdateBoundingVolumeJob(d->m_renderer->renderSceneRoot()));
+
QHash<QNodeId, QAbstractMeshFunctorPtr> meshSources = d->m_renderer->meshDataManager()->meshesPending();
Q_FOREACH (const QNodeId &meshId, meshSources.keys()) {
Render::LoadMeshDataJobPtr loadMeshJob(new Render::LoadMeshDataJob(meshSources[meshId], meshId));
@@ -251,28 +256,26 @@ QVector<QAspectJobPtr> QRenderAspect::jobsToExecute(qint64 time)
}
// Create jobs to update transforms and bounding volumes
- Render::UpdateWorldTransformJobPtr worldTransformJob(new Render::UpdateWorldTransformJob(d->m_renderer->renderSceneRoot()));
- Render::UpdateBoundingVolumeJobPtr boundingVolumeJob(new Render::UpdateBoundingVolumeJob(d->m_renderer->renderSceneRoot()));
-
// We can only update bounding volumes once all world transforms are known
- boundingVolumeJob->addDependency(worldTransformJob);
+ d->m_boundingVolumeJob->addDependency(d->m_worldTransformJob);
+ d->m_framePreparationJob->addDependency(d->m_worldTransformJob);
// Add all jobs to queue
- jobs.append(worldTransformJob);
- jobs.append(boundingVolumeJob);
+ jobs.append(d->m_worldTransformJob);
+ jobs.append(d->m_boundingVolumeJob);
+ jobs.append(d->m_framePreparationJob);
// Traverse the current framegraph and create jobs to populate
// RenderBins with RenderCommands
QVector<QAspectJobPtr> renderBinJobs = d->m_renderer->createRenderBinJobs();
// TODO: Add wrapper around ThreadWeaver::Collection
- Render::FrameCleanupJobPtr cleanupJob(new Render::FrameCleanupJob(d->m_renderer));
for (int i = 0; i < renderBinJobs.size(); ++i) {
QAspectJobPtr renderBinJob = renderBinJobs.at(i);
- renderBinJob->addDependency(boundingVolumeJob);
+ renderBinJob->addDependency(d->m_boundingVolumeJob);
jobs.append(renderBinJob);
- cleanupJob->addDependency(renderBinJob);
+ d->m_cleanupJob->addDependency(renderBinJob);
}
- jobs.append(cleanupJob);
+ jobs.append(d->m_cleanupJob);
}
return jobs;
}
diff --git a/src/render/backend/qrenderaspect_p.h b/src/render/backend/qrenderaspect_p.h
index 6320bfd09..b6e83f093 100644
--- a/src/render/backend/qrenderaspect_p.h
+++ b/src/render/backend/qrenderaspect_p.h
@@ -44,7 +44,10 @@
#include <Qt3DCore/private/qabstractaspect_p.h>
#include <Qt3DRenderer/qrenderaspect.h>
-
+#include <Qt3DRenderer/private/updateboundingvolumejob_p.h>
+#include <Qt3DRenderer/private/updateworldtransformjob_p.h>
+#include <Qt3DRenderer/private/framepreparationjob_p.h>
+#include <Qt3DRenderer/private/framecleanupjob_p.h>
#include <Qt3DRenderer/private/platformsurfacefilter_p.h>
QT_BEGIN_NAMESPACE
@@ -74,6 +77,10 @@ class QRenderAspectPrivate : public QAbstractAspectPrivate
qint64 m_time;
bool m_initialized;
+ Render::FramePreparationJobPtr m_framePreparationJob;
+ Render::FrameCleanupJobPtr m_cleanupJob;
+ Render::UpdateWorldTransformJobPtr m_worldTransformJob;
+ Render::UpdateBoundingVolumeJobPtr m_boundingVolumeJob;
};
}
diff --git a/src/render/backend/rendermesh.cpp b/src/render/backend/rendermesh.cpp
index bf5fd49c0..e99f8c23c 100644
--- a/src/render/backend/rendermesh.cpp
+++ b/src/render/backend/rendermesh.cpp
@@ -112,7 +112,12 @@ void RenderMesh::sceneChangeEvent(const QSceneChangePtr &e)
}
}
-HMeshData RenderMesh::meshData() const
+QMeshData *RenderMesh::meshData() const
+{
+ return m_meshDataManager->data(m_meshDataHandle);
+}
+
+HMeshData RenderMesh::meshDataHandle() const
{
return m_meshDataHandle;
}
diff --git a/src/render/backend/rendermesh_p.h b/src/render/backend/rendermesh_p.h
index c7563d0af..1f2451968 100644
--- a/src/render/backend/rendermesh_p.h
+++ b/src/render/backend/rendermesh_p.h
@@ -77,7 +77,8 @@ public:
void updateFromPeer(QNode *peer) Q_DECL_OVERRIDE;
void sceneChangeEvent(const QSceneChangePtr &e) Q_DECL_OVERRIDE;
- HMeshData meshData() const;
+ HMeshData meshDataHandle() const;
+ QMeshData *meshData() const;
void setMeshData(HMeshData handle);
void setMeshDataManager(MeshDataManager *manager);
diff --git a/src/render/backend/rendershaderdata.cpp b/src/render/backend/rendershaderdata.cpp
index 0466f6e67..b8f78aeb5 100644
--- a/src/render/backend/rendershaderdata.cpp
+++ b/src/render/backend/rendershaderdata.cpp
@@ -103,11 +103,37 @@ void RenderShaderData::clearUpdate()
}
// Called by renderview jobs (several concurrent threads)
-bool RenderShaderData::needsUpdate()
+/*!
+ \internal
+ Lookup if the current ShaderData or a nested ShaderData has updated properties.
+ UpdateProperties contains either the value of the propertie of a QNodeId if it's another ShaderData.
+ Transformed properties are updated for all of ShaderData that have ones at the point.
+
+ \note This needs to be performed for every top level RenderShaderData every time it is used.
+ As we don't know if the transformed properties use the same viewMatrix for all RenderViews.
+ */
+bool RenderShaderData::needsUpdate(const QMatrix4x4 &viewMatrix)
{
// We can't perform this only once as we don't know if we would be call as the root or a
// nested RenderShaderData
QMutexLocker lock(m_mutex);
+
+ // Update transformed properties
+ // We check the matrices and decide if the transform has changed since the previous call to needsUpdate
+ if (m_viewMatrix != viewMatrix) {
+ m_viewMatrix = viewMatrix;
+ const QHash<QString, QShaderData::TransformType>::const_iterator transformedEnd = m_transformedProperties.end();
+ QHash<QString, QShaderData::TransformType>::const_iterator transformedIt = m_transformedProperties.begin();
+
+ while (transformedIt != transformedEnd) {
+ if (transformedIt.value() == QShaderData::ModelToEye) {
+ m_updatedProperties.insert(transformedIt.key(), m_viewMatrix * m_worldMatrix * m_originalProperties.value(transformedIt.key()).value<QVector3D>());
+ m_properties.insert(transformedIt.key(), m_viewMatrix * m_worldMatrix * m_originalProperties.value(transformedIt.key()).value<QVector3D>());
+ }
+ ++transformedIt;
+ }
+ }
+
const QHash<QString, QVariant>::const_iterator end = m_nestedShaderDataProperties.end();
QHash<QString, QVariant>::const_iterator it = m_nestedShaderDataProperties.begin();
@@ -116,14 +142,20 @@ bool RenderShaderData::needsUpdate()
QVariantList updatedNodes;
Q_FOREACH (const QVariant &v, it.value().value<QVariantList>()) {
RenderShaderData *nested = m_manager->lookupResource(v.value<QNodeId>());
- if (nested != Q_NULLPTR && nested->needsUpdate())
+ if (nested != Q_NULLPTR) {
+ // We need to add the nested nodes the the updated property list
+ // as if we need to maintain order
+ // if node[0] doesn't need update but node[1] does,
+ // if we only have a single element, the renderer would update element [0]
+ nested->needsUpdate(viewMatrix);
updatedNodes << v;
+ }
}
if (!updatedNodes.empty())
m_updatedProperties.insert(it.key(), updatedNodes);
} else {
RenderShaderData *nested = m_manager->lookupResource(it.value().value<QNodeId>());
- if (nested != Q_NULLPTR && nested->needsUpdate())
+ if (nested != Q_NULLPTR && nested->needsUpdate(viewMatrix))
m_updatedProperties.insert(it.key(), it.value());
}
++it;
@@ -131,6 +163,27 @@ bool RenderShaderData::needsUpdate()
return m_updatedProperties.size() > 0;
}
+void RenderShaderData::updateTransformedProperties(const QMatrix4x4 &nodeWorldMatrix)
+{
+ if (m_worldMatrix != nodeWorldMatrix) {
+ m_worldMatrix = nodeWorldMatrix;
+
+ const QHash<QString, QShaderData::TransformType>::const_iterator transformedEnd = m_transformedProperties.end();
+ QHash<QString, QShaderData::TransformType>::const_iterator transformedIt = m_transformedProperties.begin();
+
+ while (transformedIt != transformedEnd) {
+ if (transformedIt.value() == QShaderData::ModelToEye) {
+ m_updatedProperties.insert(transformedIt.key(), m_viewMatrix * m_worldMatrix * m_originalProperties.value(transformedIt.key()).value<QVector3D>());
+ m_properties.insert(transformedIt.key(), m_viewMatrix * m_worldMatrix * m_originalProperties.value(transformedIt.key()).value<QVector3D>());
+ } else {
+ m_updatedProperties.insert(transformedIt.key(), m_worldMatrix * m_originalProperties.value(transformedIt.key()).value<QVector3D>());
+ m_properties.insert(transformedIt.key(), m_worldMatrix * m_originalProperties.value(transformedIt.key()).value<QVector3D>());
+ }
+ ++transformedIt;
+ }
+ }
+}
+
// This will add the RenderShaderData to be cleared from updates at the end of the frame
// by the cleanup job
// Called by renderview jobs (several concurrent threads)
@@ -157,6 +210,7 @@ void RenderShaderData::readPeerProperties(QShaderData *shaderData)
QString propertyName = QString::fromLatin1(property.name());
m_properties.insert(propertyName, propertyValue);
+ m_originalProperties.insert(propertyName, propertyValue);
// We check if the property is a QNodeId or QList<QNodeId> so that we can
// check nested QShaderData for update
@@ -168,6 +222,21 @@ void RenderShaderData::readPeerProperties(QShaderData *shaderData)
m_nestedShaderDataProperties.insert(propertyName, propertyValue);
}
}
+
+ // We look for transformed properties
+ QHash<QString, QVariant>::iterator it = m_properties.begin();
+ const QHash<QString, QVariant>::iterator end = m_properties.end();
+
+ while (it != end) {
+ if (static_cast<QMetaType::Type>(it.value().type()) == QMetaType::QVector3D) {
+ // if there is a matching QShaderData::TransformType propertyTransformed
+ QVariant value = m_properties.value(it.key() + QStringLiteral("Transformed"));
+ // if that's the case, we apply a space transformation to the property
+ if (value.isValid() && value.type() == QVariant::Int)
+ m_transformedProperties.insert(it.key(), static_cast<QShaderData::TransformType>(value.toInt()));
+ }
+ ++it;
+ }
}
void RenderShaderData::setManager(ShaderDataManager *manager)
@@ -185,7 +254,16 @@ void RenderShaderData::sceneChangeEvent(const QSceneChangePtr &e)
// Note we aren't notified about nested QShaderData in this call
// only scalar / vec properties
if (m_properties.contains(propertyName)) {
- const QVariant &val = m_propertyReader->readProperty(propertyChange->value());
+ QVariant val = m_propertyReader->readProperty(propertyChange->value());
+ // If this is a Transformed property, we need to multiply against the correct
+ // matrices
+ m_originalProperties.insert(propertyName, val);
+ if (m_transformedProperties.contains(propertyName)) {
+ if (m_transformedProperties[propertyName] == QShaderData::ModelToEye)
+ val = m_viewMatrix * m_worldMatrix * val.value<QVector3D>();
+ else
+ val = m_worldMatrix * val.value<QVector3D>();
+ }
m_properties.insert(propertyName, val);
m_updatedProperties.insert(propertyName, val);
}
@@ -193,11 +271,13 @@ void RenderShaderData::sceneChangeEvent(const QSceneChangePtr &e)
}
case NodeAdded: {
m_properties.insert(propertyName, m_propertyReader->readProperty(propertyChange->value()));
+ m_originalProperties.insert(propertyName, m_propertyReader->readProperty(propertyChange->value()));
m_nestedShaderDataProperties.insert(propertyName, propertyChange->value());
break;
}
case NodeRemoved: {
if (m_properties.contains(propertyName)) {
+ m_originalProperties.remove(propertyName);
m_properties.remove(propertyName);
m_nestedShaderDataProperties.remove(propertyName);
}
diff --git a/src/render/backend/rendershaderdata_p.h b/src/render/backend/rendershaderdata_p.h
index 79c4a9aeb..6e74117ac 100644
--- a/src/render/backend/rendershaderdata_p.h
+++ b/src/render/backend/rendershaderdata_p.h
@@ -46,6 +46,7 @@
#include <private/shadervariables_p.h>
#include <Qt3DRenderer/qshaderdata.h>
#include <QMutex>
+#include <QMatrix4x4>
QT_BEGIN_NAMESPACE
@@ -64,7 +65,6 @@ public:
~RenderShaderData();
void updateFromPeer(QNode *peer) Q_DECL_OVERRIDE;
- inline QHash<QString, QVariant> & properties() { return m_properties; }
inline QHash<QString, QVariant> properties() const { return m_properties; }
inline QHash<QString, QVariant> updatedProperties() const { return m_updatedProperties; }
@@ -75,19 +75,30 @@ public:
// Call by RenderViewJobs
void addToClearUpdateList();
- bool needsUpdate();
+ bool needsUpdate(const QMatrix4x4 &viewMatrix);
+
+ void updateTransformedProperties(const QMatrix4x4 &nodeWordlTransform);
protected:
void sceneChangeEvent(const QSceneChangePtr &e) Q_DECL_OVERRIDE;
private:
+ // 1 to 1 match with frontend properties, modified only by sceneChangeEvent
+ QHash<QString, QVariant> m_originalProperties;
+ // 1 to 1 match with frontend properties apart from Transformed
+ // properties which contain the matrices product
QHash<QString, QVariant> m_properties;
+ // only updated properties, Transformed properties have the same
+ // value as in m_properties
QHash<QString, QVariant> m_updatedProperties;
PropertyReaderInterfacePtr m_propertyReader;
QHash<QString, QVariant> m_nestedShaderDataProperties;
+ QHash<QString, QShaderData::TransformType> m_transformedProperties;
ShaderDataManager *m_manager;
QMutex *m_mutex;
static QList<QNodeId> m_updatedShaderData;
+ QMatrix4x4 m_worldMatrix;
+ QMatrix4x4 m_viewMatrix;
void readPeerProperties(QShaderData *peer);
void setManager(ShaderDataManager *manager);
diff --git a/src/render/backend/renderview.cpp b/src/render/backend/renderview.cpp
index 0d62ab486..ae05da252 100644
--- a/src/render/backend/renderview.cpp
+++ b/src/render/backend/renderview.cpp
@@ -330,9 +330,8 @@ void RenderView::buildRenderCommands(RenderEntity *node)
if (node->componentHandle<RenderMesh, 16>() != HMesh()
&& (mesh = node->renderComponent<RenderMesh>()) != Q_NULLPTR
&& mesh->isEnabled()) {
- if (!mesh->meshData().isNull())
- {
- // Perform culling here
+ if (!mesh->meshDataHandle().isNull()) {
+ // TO DO: Perform culling here
// As shaders may be deforming, transforming the mesh
// We might want to make that optional or dependent on an explicit bounding box item
@@ -361,7 +360,7 @@ void RenderView::buildRenderCommands(RenderEntity *node)
Q_FOREACH (RenderRenderPass *pass, passes) {
RenderCommand *command = m_allocator->allocate<RenderCommand>();
command->m_depth = m_data->m_eyePos.distanceToPoint(node->worldBoundingVolume()->center());
- command->m_meshData = mesh->meshData();
+ command->m_meshData = mesh->meshDataHandle();
command->m_instancesCount = 0;
// TODO: Build the state set for a render pass only once per-pass. Not once per rendercommand and pass.
@@ -496,13 +495,14 @@ void RenderView::setUniformBlockValue(QUniformPack &uniformPack, RenderShader *s
// If rShaderData has been updated (property has changed or one of the nested properties has changed)
// foreach property defined in the QShaderData, we try to fill the value of the corresponding active uniform(s)
// for all the updated properties (all the properties if the UBO was just created)
- if (rShaderData->needsUpdate() || uboNeedsUpdate) {
+ if (rShaderData->needsUpdate(*m_data->m_viewMatrix) || uboNeedsUpdate) {
// Clear previous values remaining in the hash
m_activeUniformNamesToValue.clear();
// Retrieve names and description of each active uniforms in the uniform block
const QHash<QString, ShaderUniform> &activeProperties = shader->activeUniformsForBlock(block.m_index);
- const QHash<QString, QVariant> &properties = uboNeedsUpdate ? rShaderData->properties() : rShaderData->updatedProperties();
+ // We want a copy here in case another RenderViewJobs modifies the updatedProperties of the RenderShaderData
+ const QHash<QString, QVariant> properties = uboNeedsUpdate ? rShaderData->properties() : rShaderData->updatedProperties();
QHash<QString, QVariant>::const_iterator it = properties.begin();
const QHash<QString, QVariant>::const_iterator end = properties.end();
@@ -527,6 +527,8 @@ void RenderView::setDefaultUniformBlockShaderDataValue(QUniformPack &uniformPack
RenderShaderData *rShaderData = m_renderer->shaderDataManager()->lookupResource(shaderData->id());
if (rShaderData) {
+ // updates transformed properties;
+ rShaderData->needsUpdate(*m_data->m_viewMatrix);
// Retrieve names and description of each active uniforms in the uniform block
const QHash<QString, ShaderUniform> &activeUniformsInDefaultBlock = shader->activeUniformsForBlock(-1);
@@ -576,8 +578,7 @@ void RenderView::setShaderAndUniforms(RenderCommand *command, RenderRenderPass *
// For each ParameterBinder in the RenderPass -> create a QUniformPack
// Once that works, improve that to try and minimize QUniformPack updates
- if (rPass != Q_NULLPTR)
- {
+ if (rPass != Q_NULLPTR) {
// Index RenderShader by Shader UUID
command->m_shader = m_renderer->shaderManager()->lookupHandle(rPass->shaderProgram());
RenderShader *shader = Q_NULLPTR;
diff --git a/src/render/backend/renderview_p.h b/src/render/backend/renderview_p.h
index 1fbc1d976..bc3401d68 100644
--- a/src/render/backend/renderview_p.h
+++ b/src/render/backend/renderview_p.h
@@ -253,7 +253,10 @@ private:
QUniformValue *time(const QMatrix4x4 &model) const;
void setUniformValue(QUniformPack &uniformPack, const QString &name, const QVariant &value);
- void setUniformBlockValue(QUniformPack &uniformPack, RenderShader *shader, const ShaderUniformBlock &block, const QVariant &value);
+ void setUniformBlockValue(QUniformPack &uniformPack,
+ RenderShader *shader,
+ const ShaderUniformBlock &block,
+ const QVariant &value);
void buildActiveUniformNameValueMap(const QHash<QString, ShaderUniform> &uniforms,
const QString &blockName,
const QString &qmlPropertyName,
diff --git a/src/render/frontend/sphere.h b/src/render/frontend/sphere.h
index 24b584367..252a5ec95 100644
--- a/src/render/frontend/sphere.h
+++ b/src/render/frontend/sphere.h
@@ -67,6 +67,8 @@ public:
void setCenter(const QVector3D &c);
QVector3D center() const;
+ inline bool isNull() { return m_center == QVector3D() && m_radius == 0.0f; }
+
void setRadius(float r);
float radius() const;