summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaj Grönholm <kaj.gronholm@qt.io>2018-09-13 08:14:49 +0300
committerLaszlo Agocs <laszlo.agocs@qt.io>2018-10-24 16:18:24 +0000
commit3db4c4b180b3afb105f6f531f2f070adf0c2ec64 (patch)
tree6de4ac16e0f33eb51f5be438754a225f41d1cd90
parent5d6a5f0238c31f48c9ffac335783116a40cf6a4e (diff)
Support stereoscopic rendering
This patch provides stereoscopic rendering support for Qt Studio qt3d-runtime. Contains API to switch between stereo modes (mono, top-bottom, left-right, analyph red-cyan & green-magenta) and to control eye (camera) separation. Adds menu into Q3DSViewer for these. Task-number: QT3DS-1023 Change-Id: I3da3d34606a07178978eba83236ca6cb6360e893 Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
-rw-r--r--src/runtime/profileui/q3dsprofileui.cpp4
-rw-r--r--src/runtime/q3dsengine.cpp29
-rw-r--r--src/runtime/q3dsengine_p.h3
-rw-r--r--src/runtime/q3dsres.qrc6
-rw-r--r--src/runtime/q3dsscenemanager.cpp1045
-rw-r--r--src/runtime/q3dsscenemanager_p.h176
-rw-r--r--src/runtime/q3dsviewportsettings.cpp26
-rw-r--r--src/runtime/q3dsviewportsettings_p.h19
-rw-r--r--src/runtime/shaders/compositor_ms2_stereoscopic.frag49
-rw-r--r--src/runtime/shaders/compositor_ms2_stereoscopic_core.frag48
-rw-r--r--src/runtime/shaders/compositor_ms4_stereoscopic.frag49
-rw-r--r--src/runtime/shaders/compositor_ms4_stereoscopic_core.frag48
-rw-r--r--src/runtime/shaders/compositor_stereoscopic.frag43
-rw-r--r--src/runtime/shaders/compositor_stereoscopic_core.frag45
-rw-r--r--tests/auto/slides/tst_q3dsslides.cpp4
-rw-r--r--tools/q3dsviewer/q3dsmainwindow.cpp124
16 files changed, 1323 insertions, 395 deletions
diff --git a/src/runtime/profileui/q3dsprofileui.cpp b/src/runtime/profileui/q3dsprofileui.cpp
index cdb5e21..85f5ac5 100644
--- a/src/runtime/profileui/q3dsprofileui.cpp
+++ b/src/runtime/profileui/q3dsprofileui.cpp
@@ -675,8 +675,8 @@ void Q3DSProfileView::addLayerWindow()
+ QByteArrayLiteral("\nTAA: ") + (layer3DS->layerFlags().testFlag(Q3DSLayerNode::TemporalAA) ? "Yes": "No");
ImGui::Text("%s", aa.constData());
ImGui::NextColumn();
- const bool timeDep = data->effectActive && data->effectData.combinedEffectFlags.testFlag(Q3DSEffect::ReliesOnTime);
- ImGui::Text("%d active%s", data->effectActive ? data->effectData.activeEffectCount : 0, timeDep ? " [TD]" : "");
+ const bool timeDep = data->effectActive && data->eyeMono->effectData.combinedEffectFlags.testFlag(Q3DSEffect::ReliesOnTime);
+ ImGui::Text("%d active%s", data->effectActive ? data->eyeMono->effectData.activeEffectCount : 0, timeDep ? " [TD]" : "");
ImGui::NextColumn();
ImGui::Text("%s", data->wasDirty ? "true" : "false");
ImGui::NextColumn();
diff --git a/src/runtime/q3dsengine.cpp b/src/runtime/q3dsengine.cpp
index 2405184..b05c911 100644
--- a/src/runtime/q3dsengine.cpp
+++ b/src/runtime/q3dsengine.cpp
@@ -1246,6 +1246,28 @@ void Q3DSEngine::setViewportSettings(Q3DSViewportSettings *viewportSettings)
m_uipPresentations[0].sceneManager->setMatteColor(m_viewportSettings->matteColor());
}
});
+
+ connect(m_viewportSettings, &Q3DSViewportSettings::stereoModeChanged, [this] {
+ if (!m_uipPresentations.isEmpty()) {
+ m_uipPresentations[0].sceneManager->updateViewportRects();
+
+ if (isStereoscopic() != m_wasStereoscopic)
+ emit stereoscopicChanged();
+
+ m_wasStereoscopic = isStereoscopic();
+
+ // Force a refresh
+ resize(m_size, m_dpr);
+ }
+ });
+
+ connect(m_viewportSettings, &Q3DSViewportSettings::stereoEyeSeparationChanged, [this] {
+ if (!m_uipPresentations.isEmpty()) {
+ // Force a refresh
+ resize(m_size, m_dpr);
+ }
+ });
+
}
void Q3DSEngine::setOnDemandRendering(bool enabled)
@@ -1312,6 +1334,11 @@ void Q3DSEngine::resize(const QSize &size, qreal dpr, bool forceSynchronous)
}
}
+bool Q3DSEngine::isStereoscopic() const
+{
+ return m_viewportSettings->stereoMode() != Q3DSViewportSettings::StereoModeMono;
+}
+
bool Q3DSEngine::isProfileUiVisible() const
{
Q3DSSceneManager *sm = !m_uipPresentations.isEmpty() ? m_uipPresentations[0].sceneManager : nullptr;
@@ -1903,7 +1930,7 @@ Qt3DCore::QNodeId Q3DSEngine::layerTextureNodeId(Q3DSLayerNode *layer3DS) const
if (!data)
return Qt3DCore::QNodeId();
- Qt3DRender::QAbstractTexture *t = data->effectActive ? data->effLayerTexture : data->layerTexture;
+ Qt3DRender::QAbstractTexture *t = data->effectActive ? data->eyeMono->effLayerTexture : data->eyeMono->layerTexture;
if (!t)
return Qt3DCore::QNodeId();
diff --git a/src/runtime/q3dsengine_p.h b/src/runtime/q3dsengine_p.h
index d434a7f..d349dec 100644
--- a/src/runtime/q3dsengine_p.h
+++ b/src/runtime/q3dsengine_p.h
@@ -186,6 +186,7 @@ public:
void setAutoToggleProfileUi(bool enabled) { m_autoToggleProfileUi = enabled; }
void setProfileUiVisible(bool visible, bool openLogAndConsole = false);
+ bool isStereoscopic() const;
bool isProfileUiVisible() const;
void configureProfileUi(float scale);
float profileUiScaleFactor() const { return m_profileUiScale; }
@@ -229,6 +230,7 @@ Q_SIGNALS:
void slideExited(Q3DSGraphObject *context, int index, const QString &name);
void layerResized(Q3DSLayerNode *layer3DS);
void layerTextureNodeChanged(Q3DSLayerNode *layer3DS);
+ void stereoscopicChanged();
private:
Q_DISABLE_COPY(Q3DSEngine)
@@ -313,6 +315,7 @@ private:
QMutex m_renderLoopStatsMutex;
float m_quickDeltaSum = 0;
int m_quickDeltaCount = 0;
+ bool m_wasStereoscopic = false;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(Q3DSEngine::Flags)
diff --git a/src/runtime/q3dsres.qrc b/src/runtime/q3dsres.qrc
index 9b44feb..94c6a4e 100644
--- a/src/runtime/q3dsres.qrc
+++ b/src/runtime/q3dsres.qrc
@@ -13,6 +13,12 @@
<file>shaders/text_core.frag</file>
<file>shaders/text.vert</file>
<file>shaders/text.frag</file>
+ <file>shaders/compositor_stereoscopic_core.frag</file>
+ <file>shaders/compositor_stereoscopic.frag</file>
+ <file>shaders/compositor_ms2_stereoscopic.frag</file>
+ <file>shaders/compositor_ms2_stereoscopic_core.frag</file>
+ <file>shaders/compositor_ms4_stereoscopic.frag</file>
+ <file>shaders/compositor_ms4_stereoscopic_core.frag</file>
<file alias="res/DataModelMetadata/en-us/MetaData.xml">../../res/DataModelMetadata/en-us/MetaData.xml</file>
<file alias="res/effectlib/abbeNumberIOR.glsllib">../../res/effectlib/abbeNumberIOR.glsllib</file>
<file alias="res/effectlib/anisotropyConversion.glsllib">../../res/effectlib/anisotropyConversion.glsllib</file>
diff --git a/src/runtime/q3dsscenemanager.cpp b/src/runtime/q3dsscenemanager.cpp
index 4748e8e..250ac0d 100644
--- a/src/runtime/q3dsscenemanager.cpp
+++ b/src/runtime/q3dsscenemanager.cpp
@@ -39,6 +39,7 @@
#include "q3dsslideplayer_p.h"
#include "q3dsimagemanager_p.h"
#include "q3dslogging_p.h"
+#include "q3dsviewportsettings_p.h"
#if QT_CONFIG(q3ds_profileui)
#include "profileui/q3dsprofileui_p.h"
#include "q3dsconsolecommands_p.h"
@@ -543,6 +544,9 @@ void Q3DSSceneManager::updateSizes(const QSize &size, qreal dpr, const QRect &vi
});
if (forceTreeVisit)
syncScene();
+
+ // Setup scene viewport sizes
+ updateViewportRects();
}
void Q3DSSceneManager::setCurrentSlide(Q3DSSlide *newSlide, bool flush)
@@ -722,6 +726,8 @@ Q3DSSceneManager::Scene Q3DSSceneManager::buildScene(Q3DSUipPresentation *presen
this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
}
+ QObject::disconnect(m_engine, &Q3DSEngine::stereoscopicChanged, 0, 0);
+
// Kick off the Qt3D scene.
m_rootEntity = new Qt3DCore::QEntity;
m_rootEntity->setObjectName(QString(QLatin1String("non-layer root for presentation %1")).arg(m_presentation->name()));
@@ -957,8 +963,12 @@ void Q3DSSceneManager::updateSubPresentationHosts()
if (it->colorTex) {
qCDebug(lcScene, "Directing subpresentation %s to layer %s", qPrintable(it->id), layer3DS->id().constData());
Q3DSLayerAttached *layerData = static_cast<Q3DSLayerAttached *>(layer3DS->attached());
- layerData->layerTexture = it->colorTex;
- layerData->compositorSourceParam->setValue(QVariant::fromValue(layerData->layerTexture));
+ layerData->eyeMono->layerTexture = it->colorTex;
+ layerData->eyeMono->compositorSourceParam->setValue(QVariant::fromValue(layerData->eyeMono->layerTexture));
+ layerData->eyeLeft->layerTexture = it->colorTex;
+ layerData->eyeRight->layerTexture = it->colorTex;
+ layerData->eyeLeft->compositorSourceParam->setValue(QVariant::fromValue(layerData->eyeLeft->layerTexture));
+ layerData->eyeRight->compositorSourceParam->setValue(QVariant::fromValue(layerData->eyeRight->layerTexture));
layerData->updateSubPresentationSize();
}
} else {
@@ -1125,93 +1135,106 @@ void Q3DSSceneManager::initSubTree(Q3DSGraphObject *subTreeRoot)
});
}
-void Q3DSSceneManager::buildLayer(Q3DSLayerNode *layer3DS,
- Qt3DRender::QFrameGraphNode *parent,
- const QSize &parentSize)
+void Q3DSSceneManager::updateViewportRects()
{
- Qt3DRender::QFrameGraphNode *layerFgRoot = new Qt3DRender::QFrameGraphNode(parent);
-
- // main passes, generating the layer texture
- Qt3DRender::QRenderTargetSelector *rtSelector = new Qt3DRender::QRenderTargetSelector(layerFgRoot);
+ if (m_viewports.isEmpty())
+ return;
- int ssaaScaleFactor = 1;
- if (layer3DS->multisampleAA() == Q3DSLayerNode::SSAA) {
- ssaaScaleFactor = 2;
- qCDebug(lcPerf, "Layer %s uses %dx SSAA", layer3DS->id().constData(), ssaaScaleFactor);
+ for (ViewportSet viewports : m_viewports) {
+ // Note: updateCamerasStatus() gets called when switching between mono <-> stereo
+ // and it handles properly hiding views.
+ switch (m_engine->viewportSettings()->stereoMode()) {
+ case Q3DSViewportSettings::StereoModeMono:
+ viewports.viewportMono->setNormalizedRect(QRectF(0, 0, 1, 1));
+ // Not sure if hiding Qt3D viewports currently affects anything,
+ // but shouldn't harm either
+ viewports.viewportMono->setEnabled(true);
+ viewports.viewportLeft->setEnabled(false);
+ viewports.viewportRight->setEnabled(false);
+ break;
+ case Q3DSViewportSettings::StereoModeTopBottom:
+ viewports.viewportLeft->setNormalizedRect(QRectF(0, 0, 1, 0.5));
+ viewports.viewportRight->setNormalizedRect(QRectF(0, 0.5, 1, 0.5));
+ viewports.viewportMono->setEnabled(false);
+ viewports.viewportLeft->setEnabled(true);
+ viewports.viewportRight->setEnabled(true);
+ break;
+ case Q3DSViewportSettings::StereoModeLeftRight:
+ viewports.viewportLeft->setNormalizedRect(QRectF(0, 0, 0.5, 1));
+ viewports.viewportRight->setNormalizedRect(QRectF(0.5, 0, 0.5, 1));
+ viewports.viewportMono->setEnabled(false);
+ viewports.viewportLeft->setEnabled(true);
+ viewports.viewportRight->setEnabled(true);
+ break;
+ case Q3DSViewportSettings::StereoModeAnaglyphRedCyan:
+ Q_FALLTHROUGH();
+ case Q3DSViewportSettings::StereoModeAnaglyphGreenMagenta:
+ viewports.viewportLeft->setNormalizedRect(QRectF(0, 0, 1, 1));
+ viewports.viewportRight->setNormalizedRect(QRectF(0, 0, 1, 1));
+ viewports.viewportMono->setEnabled(false);
+ viewports.viewportLeft->setEnabled(true);
+ viewports.viewportRight->setEnabled(true);
+ break;
+ default:
+ Q_UNREACHABLE();
+ break;
+ }
}
- int msaaSampleCount = 0;
- switch (layer3DS->multisampleAA()) {
- case Q3DSLayerNode::MSAA2x:
- msaaSampleCount = 2;
- break;
- case Q3DSLayerNode::MSAA4x:
- msaaSampleCount = 4;
- break;
- default:
- break;
- }
- if (m_flags.testFlag(Force4xMSAA))
- msaaSampleCount = 4;
+ // Update mode into shader parameter
+ m_stereoMode->setValue(m_engine->viewportSettings()->stereoMode());
+}
- // Layer MSAA is only available through multisample textures (GLES 3.1+ or GL 3.2+) at the moment. (QTBUG-63382)
- // Revert to no-MSAA when this is not supported.
- if (msaaSampleCount > 1 && !m_gfxLimits.multisampleTextureSupported) {
- qCDebug(lcScene, "Layer MSAA requested but not supported; ignoring request");
- msaaSampleCount = 0;
+void Q3DSSceneManager::updateCamerasStatus(Q3DSLayerAttached *layerData)
+{
+ Q_ASSERT(layerData);
+ if (m_engine->isStereoscopic()) {
+ layerData->eyeMono->cameraSelector->setEnabled(false);
+ layerData->eyeLeft->cameraSelector->setEnabled(true);
+ layerData->eyeRight->cameraSelector->setEnabled(true);
+ } else {
+ layerData->eyeMono->cameraSelector->setEnabled(true);
+ layerData->eyeLeft->cameraSelector->setEnabled(false);
+ layerData->eyeRight->cameraSelector->setEnabled(false);
}
+}
- if (msaaSampleCount > 1)
- qCDebug(lcPerf, "Layer %s uses multisample texture", layer3DS->id().constData());
-
- // parentSize could well be (0, 0) at this stage still, nevermind that
- const QSize layerSize = calculateLayerSize(layer3DS, parentSize);
- const QSize layerPixelSize = safeLayerPixelSize(layerSize, ssaaScaleFactor);
-
- // Create color and depth-stencil buffers for this layer
- Qt3DRender::QAbstractTexture *colorTex;
- Qt3DRender::QAbstractTexture *dsTexOrRb;
- Qt3DRender::QRenderTarget *rt = newLayerRenderTarget(layerPixelSize, msaaSampleCount, &colorTex, &dsTexOrRb, layerFgRoot, layer3DS);
- m_profiler->trackNewObject(rt, Q3DSProfiler::RenderTargetObject,
- "RT for layer %s", layer3DS->id().constData());
- rtSelector->setTarget(rt);
-
- Qt3DRender::QViewport *viewport = new Qt3DRender::QViewport(rtSelector);
- viewport->setNormalizedRect(QRectF(0, 0, 1, 1));
-
- Qt3DRender::QCameraSelector *cameraSelector = new Qt3DRender::QCameraSelector(viewport);
- Qt3DRender::QTechniqueFilter *mainTechniqueSelector = new Qt3DRender::QTechniqueFilter(cameraSelector);
+Q3DSEyeData *Q3DSSceneManager::buildEye(Q3DSLayerNode *layer3DS, Qt3DRender::QViewport *viewport)
+{
+ Q3DSEyeData *eyeData = new Q3DSEyeData;
+ eyeData->cameraSelector = new Qt3DRender::QCameraSelector(viewport);
+ Qt3DRender::QTechniqueFilter *mainTechniqueSelector = new Qt3DRender::QTechniqueFilter(eyeData->cameraSelector);
Qt3DRender::QFilterKey *techniqueFilterKey = new Qt3DRender::QFilterKey;
techniqueFilterKey->setName(QLatin1String("type"));
techniqueFilterKey->setValue(QLatin1String("main"));
mainTechniqueSelector->addMatch(techniqueFilterKey);
- Qt3DRender::QLayer *opaqueTag = new Qt3DRender::QLayer(m_rootEntity);
- opaqueTag->setObjectName(QLatin1String("Opaque pass"));
- Qt3DRender::QLayer *transparentTag = new Qt3DRender::QLayer(m_rootEntity);
- transparentTag->setObjectName(QLatin1String("Transparent pass"));
+ eyeData->opaqueTag = new Qt3DRender::QLayer(m_rootEntity);
+ eyeData->opaqueTag->setObjectName(QLatin1String("Opaque pass"));
+ eyeData->transparentTag = new Qt3DRender::QLayer(m_rootEntity);
+ eyeData->transparentTag->setObjectName(QLatin1String("Transparent pass"));
// Depth texture pass, optional, with its own rendertarget and clear. Just
// a placeholder for now since it is disabled by default.
- Qt3DRender::QRenderTargetSelector *depthRtSelector = new Qt3DRender::QRenderTargetSelector(mainTechniqueSelector);
+ eyeData->depthRtSelector = new Qt3DRender::QRenderTargetSelector(mainTechniqueSelector);
// Having a NoDraw leaf is essential while the depth texture is not
// generated (since we must not make draw calls from this leaf), and will
// [hopefully] not cause any harm later on, when depthRtSelector gets
// another child, either.
- new Qt3DRender::QNoDraw(depthRtSelector);
+ new Qt3DRender::QNoDraw(eyeData->depthRtSelector);
// ditto for SSAO
- Qt3DRender::QRenderTargetSelector *ssaoRtSelector = new Qt3DRender::QRenderTargetSelector(mainTechniqueSelector);
- new Qt3DRender::QNoDraw(ssaoRtSelector);
+ eyeData->ssaoRtSelector = new Qt3DRender::QRenderTargetSelector(mainTechniqueSelector);
+ new Qt3DRender::QNoDraw(eyeData->ssaoRtSelector);
// ditto for shadow maps but here there will be multiple rendertargetselectors later, so use a dummy node as root
- Qt3DRender::QFrameGraphNode *shadowRoot = new Qt3DRender::QFrameGraphNode(mainTechniqueSelector);
- new Qt3DRender::QNoDraw(shadowRoot);
+ eyeData->shadowRoot = new Qt3DRender::QFrameGraphNode(mainTechniqueSelector);
+ new Qt3DRender::QNoDraw(eyeData->shadowRoot);
// Clear op for depth pre, opaque, transparent passes.
- Qt3DRender::QClearBuffers *clearBuffers = new Qt3DRender::QClearBuffers(mainTechniqueSelector);
- clearBuffers->setBuffers(Qt3DRender::QClearBuffers::ColorDepthStencilBuffer);
- new Qt3DRender::QNoDraw(clearBuffers);
+ eyeData->clearBuffers = new Qt3DRender::QClearBuffers(mainTechniqueSelector);
+ eyeData->clearBuffers->setBuffers(Qt3DRender::QClearBuffers::ColorDepthStencilBuffer);
+ new Qt3DRender::QNoDraw(eyeData->clearBuffers);
// Depth pre-pass, optional
Qt3DRender::QRenderPassFilter *depthPreFilter = new Qt3DRender::QRenderPassFilter(mainTechniqueSelector);
@@ -1224,7 +1247,7 @@ void Q3DSSceneManager::buildLayer(Q3DSLayerNode *layer3DS,
const bool depthPrePassEnabled = !layer3DS->layerFlags().testFlag(Q3DSLayerNode::DisableDepthPrePass)
&& !layer3DS->layerFlags().testFlag(Q3DSLayerNode::DisableDepthTest);
if (depthPrePassEnabled)
- depthPreLayerFilter->addLayer(opaqueTag); // opaque only, transparent objects must not be present
+ depthPreLayerFilter->addLayer(eyeData->opaqueTag); // opaque only, transparent objects must not be present
const bool transparentPassOnly = layer3DS->layerFlags().testFlag(Q3DSLayerNode::DisableDepthTest);
@@ -1237,7 +1260,7 @@ void Q3DSSceneManager::buildLayer(Q3DSLayerNode *layer3DS,
opaqueFilter->addMatch(opaqueFilterKey);
Qt3DRender::QSortPolicy *opaqueSortPolicy = opaquePassSortPolicy(opaqueFilter);
Qt3DRender::QLayerFilter *opaqueLayerFilter = new Qt3DRender::QLayerFilter(opaqueSortPolicy);
- opaqueLayerFilter->addLayer(opaqueTag);
+ opaqueLayerFilter->addLayer(eyeData->opaqueTag);
}
// Transparent pass, sort back to front
@@ -1248,19 +1271,109 @@ void Q3DSSceneManager::buildLayer(Q3DSLayerNode *layer3DS,
transFilter->addMatch(transFilterKey);
Qt3DRender::QSortPolicy *transSortPolicy = transparentPassSortPolicy(transFilter);
Qt3DRender::QLayerFilter *transLayerFilter = new Qt3DRender::QLayerFilter(transSortPolicy);
- transLayerFilter->addLayer(transparentTag);
+ transLayerFilter->addLayer(eyeData->transparentTag);
if (transparentPassOnly)
- transLayerFilter->addLayer(opaqueTag);
+ transLayerFilter->addLayer(eyeData->opaqueTag);
// Post-processing effect passes
- Qt3DRender::QFrameGraphNode *effectRoot = new Qt3DRender::QFrameGraphNode(mainTechniqueSelector);
- new Qt3DRender::QNoDraw(effectRoot);
+ eyeData->effectRoot = new Qt3DRender::QFrameGraphNode(mainTechniqueSelector);
+ new Qt3DRender::QNoDraw(eyeData->effectRoot);
+
+ return eyeData;
+}
+
+void Q3DSSceneManager::buildLayer(Q3DSLayerNode *layer3DS,
+ Qt3DRender::QFrameGraphNode *parent,
+ const QSize &parentSize)
+{
+ Qt3DRender::QFrameGraphNode *layerFgRoot = new Qt3DRender::QFrameGraphNode(parent);
- Qt3DCore::QEntity *layerSceneRootEntity = new Qt3DCore::QEntity(rtSelector);
+ // main passes, generating the layer texture
+ Qt3DRender::QRenderTargetSelector *rtSelector =
+ new Qt3DRender::QRenderTargetSelector(layerFgRoot);
+ Qt3DRender::QRenderTargetSelector *rtSelectorLeft =
+ new Qt3DRender::QRenderTargetSelector(layerFgRoot);
+ Qt3DRender::QRenderTargetSelector *rtSelectorRight =
+ new Qt3DRender::QRenderTargetSelector(layerFgRoot);
+
+ int ssaaScaleFactor = 1;
+ if (layer3DS->multisampleAA() == Q3DSLayerNode::SSAA) {
+ ssaaScaleFactor = 2;
+ qCDebug(lcPerf, "Layer %s uses %dx SSAA", layer3DS->id().constData(), ssaaScaleFactor);
+ }
+
+ int msaaSampleCount = 0;
+ switch (layer3DS->multisampleAA()) {
+ case Q3DSLayerNode::MSAA2x:
+ msaaSampleCount = 2;
+ break;
+ case Q3DSLayerNode::MSAA4x:
+ msaaSampleCount = 4;
+ break;
+ default:
+ break;
+ }
+ if (m_flags.testFlag(Force4xMSAA))
+ msaaSampleCount = 4;
+
+ // Layer MSAA is only available through multisample textures (GLES 3.1+ or GL 3.2+) at the moment. (QTBUG-63382)
+ // Revert to no-MSAA when this is not supported.
+ if (msaaSampleCount > 1 && !m_gfxLimits.multisampleTextureSupported) {
+ qCDebug(lcScene, "Layer MSAA requested but not supported; ignoring request");
+ msaaSampleCount = 0;
+ }
+
+ if (msaaSampleCount > 1)
+ qCDebug(lcPerf, "Layer %s uses multisample texture", layer3DS->id().constData());
+
+ // parentSize could well be (0, 0) at this stage still, nevermind that
+ const QSize layerSize = calculateLayerSize(layer3DS, parentSize);
+ const QSize layerPixelSize = safeLayerPixelSize(layerSize, ssaaScaleFactor);
+
+ Q3DSLayerAttached *layerData = new Q3DSLayerAttached;
+ ViewportSet viewports;
+
+ // Create color and depth-stencil buffers for this layer
+ // Normal mono viewport
+ Qt3DRender::QAbstractTexture *colorTex;
+ Qt3DRender::QAbstractTexture *dsTexOrRb;
+ Qt3DRender::QRenderTarget *rt = newLayerRenderTarget(layerPixelSize, msaaSampleCount, &colorTex, &dsTexOrRb, layerFgRoot, layer3DS);
+ m_profiler->trackNewObject(rt, Q3DSProfiler::RenderTargetObject,
+ "RT for layer %s", layer3DS->id().constData());
+ rtSelector->setTarget(rt);
+
+ viewports.viewportMono = new Qt3DRender::QViewport(rtSelector);
+ layerData->eyeMono = buildEye(layer3DS, viewports.viewportMono);
+
+ // Create color and depth-stencil buffers for this layer
+ // Stereoscopic left-eye
+ Qt3DRender::QAbstractTexture *colorTexLeft;
+ Qt3DRender::QAbstractTexture *dsTexOrRbLeft;
+ Qt3DRender::QRenderTarget *rtLeft = newLayerRenderTarget(layerPixelSize, msaaSampleCount, &colorTexLeft, &dsTexOrRbLeft, layerFgRoot, layer3DS);
+ m_profiler->trackNewObject(rtLeft, Q3DSProfiler::RenderTargetObject,
+ "RT for layer %s", layer3DS->id().constData());
+ rtSelectorLeft->setTarget(rtLeft);
+
+ viewports.viewportLeft = new Qt3DRender::QViewport(rtSelectorLeft);
+ layerData->eyeLeft = buildEye(layer3DS, viewports.viewportLeft);
+
+ // Create color and depth-stencil buffers for this layer
+ // Stereoscopic right-eye
+ Qt3DRender::QAbstractTexture *colorTexRight;
+ Qt3DRender::QAbstractTexture *dsTexOrRbRight;
+ Qt3DRender::QRenderTarget *rtRight = newLayerRenderTarget(layerPixelSize, msaaSampleCount, &colorTexRight, &dsTexOrRbRight, layerFgRoot, layer3DS);
+ m_profiler->trackNewObject(rtRight, Q3DSProfiler::RenderTargetObject,
+ "RT for layer %s", layer3DS->id().constData());
+ rtSelectorRight->setTarget(rtRight);
+
+ viewports.viewportRight = new Qt3DRender::QViewport(rtSelectorRight);
+ layerData->eyeRight = buildEye(layer3DS, viewports.viewportRight);
+
+ // Note: Moved layerSceneRootEntity to be child of layerFgRoot instead of rtSelector
+ Qt3DCore::QEntity *layerSceneRootEntity = new Qt3DCore::QEntity(layerFgRoot);
layerSceneRootEntity->setObjectName(QObject::tr("root for %1").arg(QString::fromUtf8(layer3DS->id())));
m_profiler->reportQt3DSceneGraphRoot(layerSceneRootEntity);
- Q3DSLayerAttached *layerData = new Q3DSLayerAttached;
// Must set an entity to make Q3DSLayerNode properties animatable.
// also, this must be the general purpose "root" (### why?)
layerData->entity = m_rootEntity;
@@ -1272,39 +1385,88 @@ void Q3DSSceneManager::buildLayer(Q3DSLayerNode *layer3DS,
layerData->layerFgRoot = layerFgRoot;
layerData->layerFgRootParent = layerFgRoot->parentNode();
layerData->layerFgDummyParent = new Qt3DCore::QNode(layerData->entity);
- layerData->cameraSelector = cameraSelector;
- layerData->clearBuffers = clearBuffers;
- layerData->rtSelector = rtSelector;
- layerData->layerTexture = colorTex;
- layerData->layerDS = dsTexOrRb;
- layerData->compositorSourceParam = new Qt3DRender::QParameter(QLatin1String("tex"), layerData->layerTexture);
+ layerData->eyeMono->rtSelector = rtSelector;
+ layerData->eyeMono->layerTexture = colorTex;
+ layerData->eyeMono->layerDS = dsTexOrRb;
+ layerData->eyeMono->compositorSourceParam = new Qt3DRender::QParameter(QLatin1String("tex"), layerData->eyeMono->layerTexture);
layerData->layerSize = layerSize;
layerData->parentSize = parentSize;
layerData->msaaSampleCount = msaaSampleCount;
layerData->ssaaScaleFactor = ssaaScaleFactor;
- layerData->opaqueTag = opaqueTag;
- layerData->transparentTag = transparentTag;
layerData->cameraPropertiesParam = new Qt3DRender::QParameter(QLatin1String("camera_properties"), QVector2D(10, 5000), m_rootEntity);
- layerData->depthTextureData.rtSelector = depthRtSelector;
- layerData->ssaoTextureData.rtSelector = ssaoRtSelector;
- layerData->shadowMapData.shadowRoot = shadowRoot;
- layerData->effectData.effectRoot = effectRoot;
+ layerData->eyeMono->depthTextureData.rtSelector = layerData->eyeMono->depthRtSelector;
+ layerData->ssaoTextureData.rtSelector = layerData->eyeMono->ssaoRtSelector;
+ layerData->shadowMapData.shadowRoot = layerData->eyeMono->shadowRoot;
+ layerData->eyeMono->effectData.effectRoot = layerData->eyeMono->effectRoot;
// textures that are resized automatically to match the layer's dimensions
layerData->sizeManagedTextures << colorTex << dsTexOrRb;
+ // Setup for stereo left / eye
+ layerData->eyeLeft->layerTexture = colorTexLeft;
+ layerData->eyeRight->layerTexture = colorTexRight;
+ layerData->eyeLeft->layerDS = dsTexOrRbLeft;
+ layerData->eyeRight->layerDS = dsTexOrRbRight;
+ layerData->eyeLeft->compositorSourceParam = new Qt3DRender::QParameter(QLatin1String("texLeft"), layerData->eyeLeft->layerTexture);
+ layerData->eyeRight->compositorSourceParam = new Qt3DRender::QParameter(QLatin1String("texRight"), layerData->eyeRight->layerTexture);
+ layerData->eyeLeft->rtSelector = rtSelectorLeft;
+ layerData->eyeRight->rtSelector = rtSelectorRight;
+ layerData->eyeLeft->depthTextureData.rtSelector = layerData->eyeLeft->depthRtSelector;
+ layerData->eyeRight->depthTextureData.rtSelector = layerData->eyeRight->depthRtSelector;
+
+ layerData->sizeManagedTextures << colorTexLeft << dsTexOrRbLeft;
+ layerData->sizeManagedTextures << colorTexRight << dsTexOrRbRight;
+
+ layerData->eyeLeft->effectData.effectRoot = layerData->eyeLeft->effectRoot;
+ layerData->eyeRight->effectData.effectRoot = layerData->eyeRight->effectRoot;
+
+ // Enable/disable correct cameras depending on mode
+ updateCamerasStatus(layerData);
+
+ m_stereoMode = new Qt3DRender::QParameter(QLatin1String("stereoMode"),
+ m_engine->viewportSettings()->stereoMode());
+
// The effective texture for the layer can change over time (for example
// when a postproc effect or progaa becomes active or inactive). Keep the
// engine notified about this.
- QObject::connect(layerData->compositorSourceParam, &Qt3DRender::QParameter::valueChanged,
+ QObject::connect(layerData->eyeMono->compositorSourceParam, &Qt3DRender::QParameter::valueChanged,
+ [this, layer3DS](const QVariant &value)
+ {
+ if (value.isValid())
+ emit m_engine->layerTextureNodeChanged(layer3DS);
+ });
+
+ QObject::connect(layerData->eyeLeft->compositorSourceParam, &Qt3DRender::QParameter::valueChanged,
+ [this, layer3DS](const QVariant &value)
+ {
+ if (value.isValid())
+ emit m_engine->layerTextureNodeChanged(layer3DS);
+ });
+
+ QObject::connect(layerData->eyeRight->compositorSourceParam, &Qt3DRender::QParameter::valueChanged,
[this, layer3DS](const QVariant &value)
{
if (value.isValid())
emit m_engine->layerTextureNodeChanged(layer3DS);
});
+ QObject::connect(m_engine, &Q3DSEngine::stereoscopicChanged,
+ [this, layer3DS, layerData]()
+ {
+ // When switching between stereo <-> non-stereo, update used shader
+ // TODO: Here we disable effects when rendering stereo as msaa+effect currently doesn't work for stereo
+ int activeEffectCount = layerData->eyeMono->effectData.activeEffectCount;
+ layerData->effectActive = m_engine->isStereoscopic() ? false : activeEffectCount > 0;
+
+ updateLayerCompositorProgram(layer3DS);
+ // And enable/disable related cameras
+ updateCamerasStatus(layerData);
+ });
+
layer3DS->setAttached(layerData);
+ m_viewports.append(viewports);
+
// Add the scene contents.
Q3DSGraphObject *obj = layer3DS->firstChild();
m_componentNodeStack.clear();
@@ -1318,8 +1480,9 @@ void Q3DSSceneManager::buildLayer(Q3DSLayerNode *layer3DS,
if (layer3DS->firstChild()) {
auto rayCaster = new Qt3DRender::QRayCaster(layerSceneRootEntity);
rayCaster->setFilterMode(Qt3DRender::QAbstractRayCaster::AcceptAnyMatchingLayers);
- rayCaster->addLayer(layerData->opaqueTag);
- rayCaster->addLayer(layerData->transparentTag);
+ // Note: picking is done always with eyeMono layers, doesn't change if switching to stereo
+ rayCaster->addLayer(layerData->eyeMono->opaqueTag);
+ rayCaster->addLayer(layerData->eyeMono->transparentTag);
rayCaster->setRunMode(Qt3DRender::QAbstractRayCaster::SingleShot);
layerSceneRootEntity->addComponent(rayCaster);
layerData->layerRayCaster = rayCaster;
@@ -1376,10 +1539,17 @@ void Q3DSSceneManager::buildSubPresentationLayer(Q3DSLayerNode *layer3DS, const
data->layerSize = calculateLayerSize(layer3DS, parentSize);
data->parentSize = parentSize;
+ // Initialize empty datasets for sub presentations
+ data->eyeMono = new Q3DSEyeData;
+ data->eyeLeft = new Q3DSEyeData;
+ data->eyeRight = new Q3DSEyeData;
+
// camera and stuff stays null, no such thing for subpresentation layers
// leave compositorSourceParam dummy for now, we don't know the actual texture yet
- data->compositorSourceParam = new Qt3DRender::QParameter(QLatin1String("tex"), dummyTexture(layer3DS->id()));
+ data->eyeMono->compositorSourceParam = new Qt3DRender::QParameter(QLatin1String("tex"), dummyTexture(layer3DS->id()));
+ data->eyeLeft->compositorSourceParam = new Qt3DRender::QParameter(QLatin1String("texLeft"), dummyTexture(layer3DS->id()));
+ data->eyeRight->compositorSourceParam = new Qt3DRender::QParameter(QLatin1String("texRight"), dummyTexture(layer3DS->id()));
m_pendingSubPresLayers.insert(layer3DS);
// subpresentations associated with layers follow the size of the layer
@@ -1740,14 +1910,8 @@ static bool isVerticalAdjust(Q3DSCameraNode *cam3DS, float presentationAspect, f
|| cam3DS->scaleMode() == Q3DSCameraNode::FitVertical;
}
-void Q3DSSceneManager::setLayerCameraSizeProperties(Q3DSLayerNode *layer3DS, const QVector2D &offset)
+void Q3DSSceneManager::setSingleCameraSizeProperties(Q3DSLayerAttached *data, Qt3DRender::QCamera *camera, const QVector2D &offset)
{
- Q3DSLayerAttached *data = static_cast<Q3DSLayerAttached *>(layer3DS->attached());
- if (!data->cam3DS)
- return;
-
- Qt3DRender::QCamera *camera = static_cast<Qt3DRender::QCamera *>(data->cameraSelector->camera());
-
// The aspect ratio is not simply based on the viewport (layer)
const float layerAspect = data->layerSize.height() ? data->layerSize.width() / float(data->layerSize.height()) : 0.0f;
// ...but may take the presentation design size into account as well.
@@ -1811,6 +1975,34 @@ void Q3DSSceneManager::setLayerCameraSizeProperties(Q3DSLayerNode *layer3DS, con
}
}
+void Q3DSSceneManager::setLayerCameraSizeProperties(Q3DSLayerNode *layer3DS, const QVector2D &offset)
+{
+ Q3DSLayerAttached *data = static_cast<Q3DSLayerAttached *>(layer3DS->attached());
+ if (!data->cam3DS)
+ return;
+
+ Qt3DRender::QCamera *camera = static_cast<Qt3DRender::QCamera *>(data->eyeMono->cameraSelector->camera());
+ setSingleCameraSizeProperties(data, camera, offset);
+ if (m_engine->isStereoscopic()) {
+ Qt3DRender::QCamera *cameraLeft = static_cast<Qt3DRender::QCamera *>(data->eyeLeft->cameraSelector->camera());
+ setSingleCameraSizeProperties(data, cameraLeft, offset);
+ Qt3DRender::QCamera *cameraRight = static_cast<Qt3DRender::QCamera *>(data->eyeRight->cameraSelector->camera());
+ setSingleCameraSizeProperties(data, cameraRight, offset);
+
+ // Adjust left & right camera eyeseparation
+ const float eyeSeparation = m_engine->viewportSettings()->stereoEyeSeparation();
+ cameraLeft->setPosition(camera->position());
+ cameraRight->setPosition(camera->position());
+ cameraLeft->setViewCenter(camera->viewCenter());
+ cameraRight->setViewCenter(camera->viewCenter());
+ QVector3D leftMovement(-eyeSeparation, 0, 0);
+ QVector3D rightMovement(eyeSeparation, 0, 0);
+ cameraLeft->translate(leftMovement, Qt3DRender::QCamera::TranslateViewCenter);
+ cameraRight->translate(rightMovement, Qt3DRender::QCamera::TranslateViewCenter);
+ }
+
+}
+
void Q3DSSceneManager::setLayerSizeProperties(Q3DSLayerNode *layer3DS)
{
Q3DSLayerAttached *data = static_cast<Q3DSLayerAttached *>(layer3DS->attached());
@@ -1865,8 +2057,13 @@ void Q3DSSceneManager::setLayerProperties(Q3DSLayerNode *layer3DS)
Q3DSLayerAttached *data = static_cast<Q3DSLayerAttached *>(layer3DS->attached());
Q_ASSERT(data);
- if (data->clearBuffers) // not available for subpresentation layers
- setClearColorForClearBuffers(data->clearBuffers, layer3DS);
+ // not available for subpresentation layers
+ if (data->eyeMono->clearBuffers)
+ setClearColorForClearBuffers(data->eyeMono->clearBuffers, layer3DS);
+ if (data->eyeLeft->clearBuffers)
+ setClearColorForClearBuffers(data->eyeLeft->clearBuffers, layer3DS);
+ if (data->eyeRight->clearBuffers)
+ setClearColorForClearBuffers(data->eyeRight->clearBuffers, layer3DS);
if (data->compositorEntity) // may not exist if this is still buildLayer()
data->compositorEntity->setEnabled(layer3DS->flags().testFlag(Q3DSNode::Active) && (data->visibilityTag == Q3DSGraphObjectAttached::Visible));
@@ -1988,25 +2185,39 @@ void Q3DSSceneManager::setLayerProperties(Q3DSLayerNode *layer3DS)
}
}
-Qt3DRender::QCamera *Q3DSSceneManager::buildCamera(Q3DSCameraNode *cam3DS, Q3DSLayerNode *layer3DS, Qt3DCore::QEntity *parent)
+QVector<Qt3DRender::QCamera *> Q3DSSceneManager::buildCameras(Q3DSCameraNode *cam3DS,
+ Q3DSLayerNode *layer3DS,
+ Qt3DCore::QEntity *parent)
{
+ QVector<Qt3DRender::QCamera *> cameras;
Qt3DRender::QCamera *camera = new Qt3DRender::QCamera(parent);
+ cameras << camera;
camera->setObjectName(QObject::tr("camera %1 for %2").arg(QString::fromUtf8(cam3DS->id())).arg(QString::fromUtf8(layer3DS->id())));
+ Qt3DRender::QCamera *cameraLeft = new Qt3DRender::QCamera(parent);
+ cameras << cameraLeft;
+ cameraLeft->setObjectName(QObject::tr("left camera %1 for %2").arg(QString::fromUtf8(cam3DS->id())).arg(QString::fromUtf8(layer3DS->id())));
+ Qt3DRender::QCamera *cameraRight = new Qt3DRender::QCamera(parent);
+ cameras << cameraRight;
+ cameraRight->setObjectName(QObject::tr("right camera %1 for %2").arg(QString::fromUtf8(cam3DS->id())).arg(QString::fromUtf8(layer3DS->id())));
+
Q3DSCameraAttached *data = new Q3DSCameraAttached;
data->transform = new Qt3DCore::QTransform;
data->camera = camera;
+ data->cameraLeft = cameraLeft;
+ data->cameraRight = cameraRight;
data->layer3DS = layer3DS;
cam3DS->setAttached(data);
// Make sure data->entity, globalTransform, etc. are usable. Note however
// that during the initial scene building globalVisibility will typically
// be false at this stage due to the slideplayer only generating visibility
// changes later on.
+ // TODO: Need to handle separate cameras here somehow?
setNodeProperties(cam3DS, camera, data->transform, NodePropUpdateAttached | NodePropUpdateGlobalsRecursively);
setCameraProperties(cam3DS, Q3DSNode::TransformChanges);
data->propertyChangeObserverIndex = cam3DS->addPropertyChangeObserver(
std::bind(&Q3DSSceneManager::handlePropertyChange, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
data->eventObserverIndex = cam3DS->addEventHandler(QString(), std::bind(&Q3DSSceneManager::handleEvent, this, std::placeholders::_1));
- return camera;
+ return cameras;
}
static QMatrix4x4 composeTransformMatrix(const QVector3D &position, const QVector3D &rotation, const QVector3D &scale)
@@ -2040,12 +2251,8 @@ static void adjustRotationLeftToRight(QMatrix4x4 *m)
p[8 + 1] *= -1;
}
-void Q3DSSceneManager::setCameraProperties(Q3DSCameraNode *camNode, int changeFlags)
+void Q3DSSceneManager::setEyeCameraProperties(Q3DSCameraNode *camNode, Qt3DRender::QCamera *camera)
{
- Q3DSCameraAttached *data = static_cast<Q3DSCameraAttached *>(camNode->attached());
- Q_ASSERT(data);
- Qt3DRender::QCamera *camera = data->camera;
-
camera->setProjectionType(camNode->orthographic() ? Qt3DRender::QCameraLens::OrthographicProjection
: Qt3DRender::QCameraLens::PerspectiveProjection);
if (camNode->orthographic()) {
@@ -2058,6 +2265,24 @@ void Q3DSSceneManager::setCameraProperties(Q3DSCameraNode *camNode, int changeFl
}
camera->setNearPlane(camNode->clipNear());
camera->setFarPlane(camNode->clipFar());
+}
+
+void Q3DSSceneManager::setCameraProperties(Q3DSCameraNode *camNode, int changeFlags)
+{
+ Q3DSCameraAttached *data = static_cast<Q3DSCameraAttached *>(camNode->attached());
+ Q_ASSERT(data);
+
+ // Main camera
+ Qt3DRender::QCamera *camera = data->camera;
+ setEyeCameraProperties(camNode, camera);
+
+ // Left camera
+ Qt3DRender::QCamera *cameraLeft = data->cameraLeft;
+ setEyeCameraProperties(camNode, cameraLeft);
+
+ // Right camera
+ Qt3DRender::QCamera *cameraRight = data->cameraRight;
+ setEyeCameraProperties(camNode, cameraRight);
if (!(changeFlags & Q3DSNode::TransformChanges))
return;
@@ -2071,16 +2296,22 @@ void Q3DSSceneManager::setCameraProperties(Q3DSCameraNode *camNode, int changeFl
adjustRotationLeftToRight(&t);
const QVector3D pos(t(0, 3), t(1, 3), lhFactor * t(2, 3));
camera->setPosition(pos);
+ cameraLeft->setPosition(pos);
+ cameraRight->setPosition(pos);
// For the viewCenter make up some point in the correct direction.
const QVector3D d = directionFromTransform(t, leftHanded);
const QVector3D center(pos + d);
camera->setViewCenter(center);
+ cameraLeft->setViewCenter(center);
+ cameraRight->setViewCenter(center);
// roll is handled in the up vector
QVector3D upVec(0, 1, 0);
QMatrix4x4 rotZ;
rotZ.rotate(camNode->rotation().z(), 0, 0, -lhFactor);
upVec = rotZ * upVec;
camera->setUpVector(upVec);
+ cameraLeft->setUpVector(upVec);
+ cameraRight->setUpVector(upVec);
}
// Returns true if the camera actually changed
@@ -2091,9 +2322,13 @@ bool Q3DSSceneManager::setActiveLayerCamera(Q3DSCameraNode *cam3DS, Q3DSLayerNod
layerData->cam3DS = cam3DS;
if (cam3DS) {
Q3DSCameraAttached *activeCameraData = static_cast<Q3DSCameraAttached *>(cam3DS->attached());
- layerData->cameraSelector->setCamera(activeCameraData->camera);
+ layerData->eyeMono->cameraSelector->setCamera(activeCameraData->camera);
+ layerData->eyeLeft->cameraSelector->setCamera(activeCameraData->cameraLeft);
+ layerData->eyeRight->cameraSelector->setCamera(activeCameraData->cameraRight);
} else {
- layerData->cameraSelector->setCamera(nullptr);
+ layerData->eyeMono->cameraSelector->setCamera(nullptr);
+ layerData->eyeLeft->cameraSelector->setCamera(nullptr);
+ layerData->eyeRight->cameraSelector->setCamera(nullptr);
}
if (cam3DS) {
@@ -2160,17 +2395,15 @@ static void prepareSizeDependentTexture(Qt3DRender::QAbstractTexture *texture,
data->sizeManagedTextures << Q3DSLayerAttached::SizeManagedTexture(texture, callback, flags);
}
-void Q3DSSceneManager::setDepthTextureEnabled(Q3DSLayerNode *layer3DS, bool enabled)
+void Q3DSSceneManager::setEyeDepthTextureEnabled(Q3DSLayerNode *layer3DS, Q3DSEyeData *eyeData, bool enabled)
{
- Q3DSLayerAttached *data = static_cast<Q3DSLayerAttached *>(layer3DS->attached());
- Q_ASSERT(data);
- if (enabled == data->depthTextureData.enabled)
+ if (enabled == eyeData->depthTextureData.enabled)
return;
- data->depthTextureData.enabled = enabled;
+ eyeData->depthTextureData.enabled = enabled;
qCDebug(lcPerf, "Depth texture enabled for layer %s is now %d", layer3DS->id().constData(), enabled);
if (enabled) {
- if (!data->depthTextureData.depthTexture) {
+ if (!eyeData->depthTextureData.depthTexture) {
Qt3DRender::QTexture2D *depthTex = new Qt3DRender::QTexture2D;
m_profiler->trackNewObject(depthTex, Q3DSProfiler::Texture2DObject,
"Depth texture for layer %s", layer3DS->id().constData());
@@ -2178,45 +2411,54 @@ void Q3DSSceneManager::setDepthTextureEnabled(Q3DSLayerNode *layer3DS, bool enab
depthTex->setMinificationFilter(Qt3DRender::QAbstractTexture::Linear);
depthTex->setMagnificationFilter(Qt3DRender::QAbstractTexture::Linear);
prepareSizeDependentTexture(depthTex, layer3DS);
- data->depthTextureData.depthTexture = depthTex;
+ eyeData->depthTextureData.depthTexture = depthTex;
Qt3DRender::QRenderTarget *depthRt = new Qt3DRender::QRenderTarget;
m_profiler->trackNewObject(depthRt, Q3DSProfiler::RenderTargetObject,
"Depth texture RT for layer %s", layer3DS->id().constData());
Qt3DRender::QRenderTargetOutput *depthRtOutput = new Qt3DRender::QRenderTargetOutput;
depthRtOutput->setAttachmentPoint(Qt3DRender::QRenderTargetOutput::Depth);
- depthRtOutput->setTexture(data->depthTextureData.depthTexture);
+ depthRtOutput->setTexture(eyeData->depthTextureData.depthTexture);
depthRt->addOutput(depthRtOutput);
- data->depthTextureData.rtSelector->setTarget(depthRt);
+ eyeData->depthTextureData.rtSelector->setTarget(depthRt);
- data->depthTextureData.clearBuffers = new Qt3DRender::QClearBuffers(data->depthTextureData.rtSelector);
- data->depthTextureData.clearBuffers->setBuffers(Qt3DRender::QClearBuffers::DepthBuffer);
- new Qt3DRender::QNoDraw(data->depthTextureData.clearBuffers);
+ eyeData->depthTextureData.clearBuffers = new Qt3DRender::QClearBuffers(eyeData->depthTextureData.rtSelector);
+ eyeData->depthTextureData.clearBuffers->setBuffers(Qt3DRender::QClearBuffers::DepthBuffer);
+ new Qt3DRender::QNoDraw(eyeData->depthTextureData.clearBuffers);
- Qt3DRender::QRenderPassFilter *depthTexFilter = new Qt3DRender::QRenderPassFilter(data->depthTextureData.rtSelector);
+ Qt3DRender::QRenderPassFilter *depthTexFilter = new Qt3DRender::QRenderPassFilter(eyeData->depthTextureData.rtSelector);
Qt3DRender::QFilterKey *depthFilterKey = new Qt3DRender::QFilterKey;
depthFilterKey->setName(QLatin1String("pass"));
depthFilterKey->setValue(QLatin1String("depth"));
depthTexFilter->addMatch(depthFilterKey);
Qt3DRender::QSortPolicy *sortPolicy = opaquePassSortPolicy(depthTexFilter);
- data->depthTextureData.layerFilterOpaque = new Qt3DRender::QLayerFilter(sortPolicy);
+ eyeData->depthTextureData.layerFilterOpaque = new Qt3DRender::QLayerFilter(sortPolicy);
- depthTexFilter = new Qt3DRender::QRenderPassFilter(data->depthTextureData.rtSelector);
+ depthTexFilter = new Qt3DRender::QRenderPassFilter(eyeData->depthTextureData.rtSelector);
depthTexFilter->addMatch(depthFilterKey);
sortPolicy = transparentPassSortPolicy(depthTexFilter);
- data->depthTextureData.layerFilterTransparent = new Qt3DRender::QLayerFilter(sortPolicy);
+ eyeData->depthTextureData.layerFilterTransparent = new Qt3DRender::QLayerFilter(sortPolicy);
}
- data->depthTextureData.clearBuffers->setEnabled(true);
- data->depthTextureData.layerFilterOpaque->addLayer(data->opaqueTag);
- data->depthTextureData.layerFilterTransparent->addLayer(data->transparentTag);
- } else if (data->depthTextureData.depthTexture) {
- data->depthTextureData.clearBuffers->setEnabled(false);
- data->depthTextureData.layerFilterOpaque->removeLayer(data->opaqueTag);
- data->depthTextureData.layerFilterTransparent->removeLayer(data->transparentTag);
+ eyeData->depthTextureData.clearBuffers->setEnabled(true);
+ eyeData->depthTextureData.layerFilterOpaque->addLayer(eyeData->opaqueTag);
+ eyeData->depthTextureData.layerFilterTransparent->addLayer(eyeData->transparentTag);
+ } else if (eyeData->depthTextureData.depthTexture) {
+ eyeData->depthTextureData.clearBuffers->setEnabled(false);
+ eyeData->depthTextureData.layerFilterOpaque->removeLayer(eyeData->opaqueTag);
+ eyeData->depthTextureData.layerFilterTransparent->removeLayer(eyeData->transparentTag);
}
}
+void Q3DSSceneManager::setDepthTextureEnabled(Q3DSLayerNode *layer3DS, bool enabled)
+{
+ Q3DSLayerAttached *data = static_cast<Q3DSLayerAttached *>(layer3DS->attached());
+ Q_ASSERT(data);
+ setEyeDepthTextureEnabled(layer3DS, data->eyeMono, enabled);
+ setEyeDepthTextureEnabled(layer3DS, data->eyeLeft, enabled);
+ setEyeDepthTextureEnabled(layer3DS, data->eyeRight, enabled);
+}
+
void Q3DSSceneManager::setSsaoTextureEnabled(Q3DSLayerNode *layer3DS, bool enabled)
{
Q3DSLayerAttached *data = static_cast<Q3DSLayerAttached *>(layer3DS->attached());
@@ -2266,7 +2508,8 @@ void Q3DSSceneManager::setSsaoTextureEnabled(Q3DSLayerNode *layer3DS, bool enabl
data->ssaoTextureData.depthSampler = new Qt3DRender::QParameter;
data->ssaoTextureData.depthSampler->setName(QLatin1String("depth_sampler"));
- data->ssaoTextureData.depthSampler->setValue(QVariant::fromValue(data->depthTextureData.depthTexture));
+ // TODO: Duplicate this method if ssaoTextureData is also duplicated and do for all eyes
+ data->ssaoTextureData.depthSampler->setValue(QVariant::fromValue(data->eyeMono->depthTextureData.depthTexture));
data->ssaoTextureData.aoDataBuf = new Qt3DRender::QBuffer(data->entity);
data->ssaoTextureData.aoDataBuf->setObjectName(QLatin1String("ambient occlusion pass constant buffer"));
@@ -2321,8 +2564,8 @@ void Q3DSSceneManager::updateAoParameters(Q3DSLayerNode *layer3DS)
layer3DS->shadowBias());
float R2 = layer3DS->aoDistance() * layer3DS->aoDistance() * 0.16f;
- float rw = data->depthTextureData.depthTexture->width();
- float rh = data->depthTextureData.depthTexture->height();
+ float rw = data->eyeMono->depthTextureData.depthTexture->width();
+ float rh = data->eyeMono->depthTextureData.depthTexture->height();
float fov = data->cam3DS ? qDegreesToRadians(data->cam3DS->verticalFov(rw / rh)) : 1.0f;
float tanHalfFovY = qTan(0.5f * fov * (rh / rw));
float invFocalLenX = tanHalfFovY * (rw / rh);
@@ -2432,8 +2675,11 @@ void Q3DSSceneManager::updateCubeShadowCam(Q3DSLayerAttached::PerLightShadowMapD
shadowCam->setAspectRatio(1);
}
-void Q3DSSceneManager::genCubeBlurPassFg(Q3DSLayerAttached::PerLightShadowMapData *d, Qt3DRender::QAbstractTexture *inTex,
- Qt3DRender::QAbstractTexture *outTex, const QString &passName, Q3DSLightNode *light3DS)
+void Q3DSSceneManager::genCubeBlurPassFg(Q3DSLayerAttached::PerLightShadowMapData *d,
+ Qt3DRender::QAbstractTexture *inTex,
+ Qt3DRender::QAbstractTexture *outTex,
+ const QString &passName,
+ Q3DSLightNode *light3DS)
{
Qt3DRender::QRenderTargetSelector *rtSelector = new Qt3DRender::QRenderTargetSelector(d->subTreeRoot);
Qt3DRender::QRenderTarget *rt = new Qt3DRender::QRenderTarget;
@@ -2815,8 +3061,12 @@ void Q3DSSceneManager::updateShadowMapStatus(Q3DSLayerNode *layer3DS, bool *smDi
}
// verify no globally used parameters get parented to this volatile framegraph subtree
- Q_ASSERT(layerData->opaqueTag->parent());
- Q_ASSERT(layerData->transparentTag->parent());
+ Q_ASSERT(layerData->eyeMono->opaqueTag->parent());
+ Q_ASSERT(layerData->eyeMono->transparentTag->parent());
+ Q_ASSERT(layerData->eyeLeft->opaqueTag->parent());
+ Q_ASSERT(layerData->eyeLeft->transparentTag->parent());
+ Q_ASSERT(layerData->eyeRight->opaqueTag->parent());
+ Q_ASSERT(layerData->eyeRight->transparentTag->parent());
Q_ASSERT(layerData->cameraPropertiesParam->parent());
Q_ASSERT(m_fsQuadTag->parent());
@@ -2864,7 +3114,9 @@ void Q3DSSceneManager::updateShadowMapStatus(Q3DSLayerNode *layer3DS, bool *smDi
shadowFilter->addMatch(shadowFilterKey);
Qt3DRender::QSortPolicy *sortPolicyOpaque = opaquePassSortPolicy(shadowFilter);
Qt3DRender::QLayerFilter *layerFilterOpaque = new Qt3DRender::QLayerFilter(sortPolicyOpaque);
- layerFilterOpaque->addLayer(layerData->opaqueTag);
+ layerFilterOpaque->addLayer(layerData->eyeMono->opaqueTag);
+ layerFilterOpaque->addLayer(layerData->eyeLeft->opaqueTag);
+ layerFilterOpaque->addLayer(layerData->eyeRight->opaqueTag);
shadowFilter->addParameter(d->cameraPositionParam);
shadowFilter->addParameter(layerData->cameraPropertiesParam);
@@ -2872,16 +3124,19 @@ void Q3DSSceneManager::updateShadowMapStatus(Q3DSLayerNode *layer3DS, bool *smDi
shadowFilter->addMatch(shadowFilterKey);
Qt3DRender::QSortPolicy *sortPolicyTransparent = transparentPassSortPolicy(shadowFilter);
Qt3DRender::QLayerFilter *layerFilterTransparent = new Qt3DRender::QLayerFilter(sortPolicyTransparent);
- layerFilterTransparent->addLayer(layerData->transparentTag);
+ layerFilterTransparent->addLayer(layerData->eyeMono->transparentTag);
+ layerFilterTransparent->addLayer(layerData->eyeLeft->transparentTag);
+ layerFilterTransparent->addLayer(layerData->eyeRight->transparentTag);
shadowFilter->addParameter(d->cameraPositionParam);
shadowFilter->addParameter(layerData->cameraPropertiesParam);
}
-
// Now two blur passes that output to the final texture, play ping pong.
if (m_gfxLimits.maxDrawBuffers >= 6) { // ###
// Draws a fullscreen quad into the 6 faces of the cubemap texture (COLOR0..5), with the other texture as input.
- genCubeBlurPassFg(d, d->shadowMapTexture, d->shadowMapTextureTemp, QLatin1String("shadowCubeBlurX"), light3DS);
- genCubeBlurPassFg(d, d->shadowMapTextureTemp, d->shadowMapTexture, QLatin1String("shadowCubeBlurY"), light3DS);
+ genCubeBlurPassFg(d, d->shadowMapTexture, d->shadowMapTextureTemp,
+ QLatin1String("shadowCubeBlurX"), light3DS);
+ genCubeBlurPassFg(d, d->shadowMapTextureTemp, d->shadowMapTexture,
+ QLatin1String("shadowCubeBlurY"), light3DS);
}
// set QParameter names and values
@@ -2925,18 +3180,21 @@ void Q3DSSceneManager::updateShadowMapStatus(Q3DSLayerNode *layer3DS, bool *smDi
shadowFilter->addMatch(shadowFilterKey);
Qt3DRender::QSortPolicy *sortPolicyOpaque = opaquePassSortPolicy(shadowFilter);
Qt3DRender::QLayerFilter *layerFilterOpaque = new Qt3DRender::QLayerFilter(sortPolicyOpaque);
- layerFilterOpaque->addLayer(layerData->opaqueTag);
+ layerFilterOpaque->addLayer(layerData->eyeMono->opaqueTag);
+ layerFilterOpaque->addLayer(layerData->eyeLeft->opaqueTag);
+ layerFilterOpaque->addLayer(layerData->eyeRight->opaqueTag);
shadowFilter = new Qt3DRender::QRenderPassFilter(camSel);
shadowFilter->addMatch(shadowFilterKey);
Qt3DRender::QSortPolicy *sortPolicyTransparent = transparentPassSortPolicy(shadowFilter);
Qt3DRender::QLayerFilter *layerFilterTransparent = new Qt3DRender::QLayerFilter(sortPolicyTransparent);
- layerFilterTransparent->addLayer(layerData->transparentTag);
+ layerFilterTransparent->addLayer(layerData->eyeMono->transparentTag);
+ layerFilterTransparent->addLayer(layerData->eyeLeft->transparentTag);
+ layerFilterTransparent->addLayer(layerData->eyeRight->transparentTag);
// 2 blur passes
genOrthoBlurPassFg(d, d->shadowMapTexture, d->shadowMapTextureTemp, QLatin1String("shadowOrthoBlurX"), light3DS);
genOrthoBlurPassFg(d, d->shadowMapTextureTemp, d->shadowMapTexture, QLatin1String("shadowOrthoBlurY"), light3DS);
-
// set QParameter names and values
updateOrthoShadowMapParams(d, light3DS, lightIndexStr);
custMatOrthoShadowMaps.append(QVariant::fromValue(d->shadowMapTexture));
@@ -3046,7 +3304,7 @@ static QVector2D adjustedProgressiveTemporalAAVertexOffset(const QVector2D &vert
vertexOffset.y() / (layerPixelSize.height() / 2.0f) * camZ);
}
-void Q3DSSceneManager::stealLayerRenderTarget(Qt3DRender::QAbstractTexture **stolenColorBuf, Q3DSLayerNode *layer3DS)
+void Q3DSSceneManager::stealLayerRenderTarget(Qt3DRender::QAbstractTexture **stolenColorBuf, Q3DSLayerNode *layer3DS, Q3DSEyeData *eyeData)
{
Q3DSLayerAttached *data = static_cast<Q3DSLayerAttached *>(layer3DS->attached());
if (*stolenColorBuf) {
@@ -3054,7 +3312,7 @@ void Q3DSSceneManager::stealLayerRenderTarget(Qt3DRender::QAbstractTexture **sto
data->sizeManagedTextures.removeOne(*stolenColorBuf);
delete *stolenColorBuf;
}
- *stolenColorBuf = data->effectActive ? data->effLayerTexture : data->layerTexture;
+ *stolenColorBuf = data->effectActive ? eyeData->effLayerTexture : eyeData->layerTexture;
// create a whole new render target for the layer
data->sizeManagedTextures.removeOne(*stolenColorBuf);
const QSize layerPixelSize = safeLayerPixelSize(data);
@@ -3065,16 +3323,16 @@ void Q3DSSceneManager::stealLayerRenderTarget(Qt3DRender::QAbstractTexture **sto
&colorTex, &dsTexOrRb,
data->layerFgRoot,
layer3DS,
- data->layerDS); // keep using the existing depth-stencil buffer
- Qt3DRender::QRenderTarget *oldRt = data->rtSelector->target();
- data->rtSelector->setTarget(rt);
+ eyeData->layerDS); // keep using the existing depth-stencil buffer
+ Qt3DRender::QRenderTarget *oldRt = eyeData->rtSelector->target();
+ eyeData->rtSelector->setTarget(rt);
delete oldRt;
if (data->effectActive) {
data->sizeManagedTextures.append(colorTex);
- data->effLayerTexture = colorTex;
+ eyeData->effLayerTexture = colorTex;
} else {
data->sizeManagedTextures.insert(0, colorTex);
- data->layerTexture = colorTex;
+ eyeData->layerTexture = colorTex;
}
// update descriptions for profiler
@@ -3099,26 +3357,16 @@ Qt3DRender::QAbstractTexture *Q3DSSceneManager::createProgressiveTemporalAAExtra
static const int MAX_AA_LEVELS = 8;
-// Called once per frame (in the preparation step from the frame action) for
-// each progressive AA enabled layer.
-bool Q3DSSceneManager::updateProgressiveAA(Q3DSLayerNode *layer3DS)
+// Called once per eye (mono, left, right) for each progressive AA enabled layer.
+bool Q3DSSceneManager::updateEyeProgressiveAA(Q3DSLayerNode *layer3DS, Q3DSLayerAttached *data, Q3DSEyeData *eyeData)
{
- Q3DSLayerAttached *data = static_cast<Q3DSLayerAttached *>(layer3DS->attached());
- if (!data || !data->cam3DS)
- return false;
-
- // No prog.aa for msaa/ssaa layers - 3DS1 supports this (would need the
- // usual resolve step with blitframebuffer) but we'll live with this
- // limitation for now.
- if (data->msaaSampleCount > 1 || data->ssaaScaleFactor > 1)
- return false;
-
// When a frame applies an offset to the camera's matrix, the next frame
// must reset it. This must happen regardless of having PAA active in the
// next frame.
- if (data->progAA.cameraAltered) {
- data->progAA.cameraAltered = false;
- setLayerCameraSizeProperties(layer3DS);
+ if (eyeData->progAA.cameraAltered) {
+ eyeData->progAA.cameraAltered = false;
+ Qt3DRender::QCamera *camera = static_cast<Qt3DRender::QCamera *>(eyeData->cameraSelector->camera());
+ setSingleCameraSizeProperties(data, camera);
}
if (data->layerSize.isEmpty())
@@ -3129,7 +3377,7 @@ bool Q3DSSceneManager::updateProgressiveAA(Q3DSLayerNode *layer3DS)
// the pass index otherwise.
#ifndef PAA_ALWAYS_ON
if (data->wasDirty)
- data->progAA.pass = 0;
+ eyeData->progAA.pass = 0;
#endif
// Do not start accumulating before at least 2 non-dirty frames. This is
@@ -3154,32 +3402,31 @@ bool Q3DSSceneManager::updateProgressiveAA(Q3DSLayerNode *layer3DS)
break;
}
- if (data->progAA.pass > maxPass) {
+ if (eyeData->progAA.pass > maxPass) {
// State is Idle. Keep displaying the output in currentOutputTexture until
// wasDirty becomes true and so pass gets reset.
- if (data->progAA.layerFilter->layers().contains(m_fsQuadTag))
- data->progAA.layerFilter->removeLayer(m_fsQuadTag);
+ if (eyeData->progAA.layerFilter->layers().contains(m_fsQuadTag))
+ eyeData->progAA.layerFilter->removeLayer(m_fsQuadTag);
#ifdef PAA_ALWAYS_ON
- data->progAA.pass = 0;
+ eyeData->progAA.pass = 0;
#endif
return true;
}
- if (data->progAA.pass < 1 + PROGAA_FRAME_DELAY) {
+ if (eyeData->progAA.pass < 1 + PROGAA_FRAME_DELAY) {
// State is Inactive. Must make sure no progAA output is shown.
- ++data->progAA.pass;
- if (data->progAA.enabled) {
+ ++eyeData->progAA.pass;
+ if (eyeData->progAA.enabled) {
qCDebug(lcScene, "Stopping progressive AA for layer %s", layer3DS->id().constData());
- data->progAA.enabled = false;
- data->compositorSourceParam->setValue(QVariant::fromValue(data->effectActive ? data->effLayerTexture : data->layerTexture));
-
+ eyeData->progAA.enabled = false;
+ eyeData->compositorSourceParam->setValue(QVariant::fromValue(data->effectActive ? eyeData->effLayerTexture : eyeData->layerTexture));
// Do not delete and then recreate the framegraph subtree since
// that is likely way too expensive. Keep it around instead and
// disable it by making sure it has no renderable entities. This
// could have already been done in the > maxPass branch above but
// won't hurt to repeat since we may get a dirty frame before
// reaching the maximum accumulation level.
- data->progAA.layerFilter->removeLayer(m_fsQuadTag);
+ eyeData->progAA.layerFilter->removeLayer(m_fsQuadTag);
}
return false;
}
@@ -3208,21 +3455,22 @@ bool Q3DSSceneManager::updateProgressiveAA(Q3DSLayerNode *layer3DS)
QVector2D(0.111111f, 0.888889f), // 8x
};
- const int factorsIdx = data->progAA.pass - (1 + PROGAA_FRAME_DELAY);
+ const int factorsIdx = eyeData->progAA.pass - (1 + PROGAA_FRAME_DELAY);
const QVector2D vertexOffset = adjustedProgressiveTemporalAAVertexOffset(vertexOffsets[factorsIdx], data);
const QVector2D blendFactor = blendFactors[factorsIdx];
- if (!data->progAA.enabled && data->progAA.fg && data->progAA.layerFilter)
- data->progAA.layerFilter->addLayer(m_fsQuadTag);
+ if (!eyeData->progAA.enabled && eyeData->progAA.fg && eyeData->progAA.layerFilter)
+ eyeData->progAA.layerFilter->addLayer(m_fsQuadTag);
- data->progAA.enabled = true;
+ eyeData->progAA.enabled = true;
if (factorsIdx == 0)
qCDebug(lcPerf, "Kicking off progressive AA for layer %s", layer3DS->id().constData());
// Alter the camera's matrix by a little movement based on the current
// vertexOffset. This applies to the camera used by the main layer passes.
- setLayerCameraSizeProperties(layer3DS, vertexOffset);
- data->progAA.cameraAltered = true;
+ Qt3DRender::QCamera *camera = static_cast<Qt3DRender::QCamera *>(eyeData->cameraSelector->camera());
+ setSingleCameraSizeProperties(data, camera, vertexOffset);
+ eyeData->progAA.cameraAltered = true;
// data->layerTexture is the original contents (albeit with jiggled
// camera), generated by the main layer passes. Have two additional
@@ -3230,24 +3478,24 @@ bool Q3DSSceneManager::updateProgressiveAA(Q3DSLayerNode *layer3DS)
// be used as output in the next frame). The layer compositor will be
// switched over to use always the one that is the (blended) output.
- if (!data->progAA.extraColorBuf)
- data->progAA.extraColorBuf = createProgressiveTemporalAAExtraBuffer(layer3DS);
+ if (!eyeData->progAA.extraColorBuf)
+ eyeData->progAA.extraColorBuf = createProgressiveTemporalAAExtraBuffer(layer3DS);
// ### depth, ssao, shadow passes in the main layer framegraph subtree should be disabled when pass > 0
// For the other buffer there is no new texture needed - instead,
// steal data->(eff)layerTexture. (note: already in sizeManagedTextures)
if (factorsIdx == 0) {
- stealLayerRenderTarget(&data->progAA.stolenColorBuf, layer3DS);
+ stealLayerRenderTarget(&eyeData->progAA.stolenColorBuf, layer3DS, eyeData);
// start with the existing color buffer as the accumulator
- data->progAA.currentAccumulatorTexture = data->progAA.stolenColorBuf;
- data->progAA.currentOutputTexture = data->progAA.extraColorBuf;
+ eyeData->progAA.currentAccumulatorTexture = eyeData->progAA.stolenColorBuf;
+ eyeData->progAA.currentOutputTexture = eyeData->progAA.extraColorBuf;
}
// ### have to do this on every new PAA run since accumulatorTexture changes above.
// It is an overkill though since the framegraph could be generated just once.
if (factorsIdx == 0) {
- delete data->progAA.fg;
+ delete eyeData->progAA.fg;
// set up a framegraph subtree to render a quad
@@ -3256,8 +3504,8 @@ bool Q3DSSceneManager::updateProgressiveAA(Q3DSLayerNode *layer3DS)
// ones. This is probably more efficient anyways (since it results in
// binding a different FBO, without altering attachments).
- data->progAA.curTarget = 0;
- for (Qt3DRender::QAbstractTexture *t : { data->progAA.currentOutputTexture, data->progAA.currentAccumulatorTexture }) {
+ eyeData->progAA.curTarget = 0;
+ for (Qt3DRender::QAbstractTexture *t : { eyeData->progAA.currentOutputTexture, eyeData->progAA.currentAccumulatorTexture }) {
Qt3DRender::QRenderTargetOutput *rtOutput = new Qt3DRender::QRenderTargetOutput;
rtOutput->setAttachmentPoint(Qt3DRender::QRenderTargetOutput::Color0);
rtOutput->setTexture(t);
@@ -3265,39 +3513,39 @@ bool Q3DSSceneManager::updateProgressiveAA(Q3DSLayerNode *layer3DS)
m_profiler->trackNewObject(rt, Q3DSProfiler::RenderTargetObject, layer3DS->id(),
"Progressive AA RT for layer %s", layer3DS->id().constData());
rt->addOutput(rtOutput);
- data->progAA.rts[data->progAA.curTarget++] = rt;
+ eyeData->progAA.rts[eyeData->progAA.curTarget++] = rt;
}
- data->progAA.curTarget = 0;
+ eyeData->progAA.curTarget = 0;
auto rtSel = createProgressiveTemporalAAFramegraph(data->layerFgRoot,
- data->progAA.rts[data->progAA.curTarget],
+ eyeData->progAA.rts[eyeData->progAA.curTarget],
m_fsQuadTag,
- &data->progAA.layerFilter,
- &data->progAA.accumTexParam,
- &data->progAA.lastTexParam,
- &data->progAA.blendFactorsParam);
- data->progAA.fg = data->progAA.rtSel = rtSel;
+ &eyeData->progAA.layerFilter,
+ &eyeData->progAA.accumTexParam,
+ &eyeData->progAA.lastTexParam,
+ &eyeData->progAA.blendFactorsParam);
+ eyeData->progAA.fg = eyeData->progAA.rtSel = rtSel;
}
// Input
- data->progAA.accumTexParam->setValue(QVariant::fromValue(data->progAA.currentAccumulatorTexture));
- data->progAA.lastTexParam->setValue(QVariant::fromValue(data->effectActive ? data->effLayerTexture : data->layerTexture));
- data->progAA.blendFactorsParam->setValue(blendFactor);
+ eyeData->progAA.accumTexParam->setValue(QVariant::fromValue(eyeData->progAA.currentAccumulatorTexture));
+ eyeData->progAA.lastTexParam->setValue(QVariant::fromValue(data->effectActive ? eyeData->effLayerTexture : eyeData->layerTexture));
+ eyeData->progAA.blendFactorsParam->setValue(blendFactor);
// Output
- data->progAA.rtSel->setTarget(data->progAA.rts[data->progAA.curTarget]);
+ eyeData->progAA.rtSel->setTarget(eyeData->progAA.rts[eyeData->progAA.curTarget]);
// have the compositor use the blended results instead of the layer texture
- data->compositorSourceParam->setValue(QVariant::fromValue(data->progAA.currentOutputTexture));
+ eyeData->compositorSourceParam->setValue(QVariant::fromValue(eyeData->progAA.currentOutputTexture));
// In the next PAA round (i.e. the frame after the next one) reuse accumTex
// as the output and the current output as accumTex...
- std::swap(data->progAA.currentAccumulatorTexture, data->progAA.currentOutputTexture);
+ std::swap(eyeData->progAA.currentAccumulatorTexture, eyeData->progAA.currentOutputTexture);
// ...whereas the output of the next frame will be used as input, so flip the
// index to use the correct render target.
- data->progAA.curTarget = 1 - data->progAA.curTarget;
+ eyeData->progAA.curTarget = 1 - eyeData->progAA.curTarget;
- ++data->progAA.pass;
+ ++eyeData->progAA.pass;
// Make sure layer caching does not interfere and the layer's framegraph subtree
// is still active as long as PAA accumulation is active.
@@ -3306,26 +3554,42 @@ bool Q3DSSceneManager::updateProgressiveAA(Q3DSLayerNode *layer3DS)
return true;
}
-void Q3DSSceneManager::updateTemporalAA(Q3DSLayerNode *layer3DS)
+// Called once per frame (in the preparation step from the frame action) for
+// each progressive AA enabled layer.
+bool Q3DSSceneManager::updateProgressiveAA(Q3DSLayerNode *layer3DS)
{
- static const int MAX_TEMPORAL_AA_LEVELS = 2;
-
- Q3DSLayerAttached *data = layer3DS->attached<Q3DSLayerAttached>();
+ Q3DSLayerAttached *data = static_cast<Q3DSLayerAttached *>(layer3DS->attached());
if (!data || !data->cam3DS)
- return;
+ return false;
- // No TempAA for MSAA/SSAA layers for now.
+ // No prog.aa for msaa/ssaa layers - 3DS1 supports this (would need the
+ // usual resolve step with blitframebuffer) but we'll live with this
+ // limitation for now.
if (data->msaaSampleCount > 1 || data->ssaaScaleFactor > 1)
- return;
+ return false;
+
+ bool returnValue = false;
+ if (!m_engine->isStereoscopic()) {
+ returnValue = updateEyeProgressiveAA(layer3DS, data, data->eyeMono);
+ } else {
+ updateEyeProgressiveAA(layer3DS, data, data->eyeLeft);
+ returnValue = updateEyeProgressiveAA(layer3DS, data, data->eyeRight);
+ }
+ return returnValue;
+}
+
+void Q3DSSceneManager::updateEyeTemporalAA(Q3DSLayerNode *layer3DS, Q3DSLayerAttached *data, Q3DSEyeData *eyeData)
+{
+ static const int MAX_TEMPORAL_AA_LEVELS = 2;
// Temporal AA is like a 2x progressive AA while the layer has movement (is
// dirty). Accumulation stops after 2 non-dirty frames but apart from that
// it is "always on".
if (data->wasDirty)
- data->tempAA.nonDirtyPass = 0;
+ eyeData->tempAA.nonDirtyPass = 0;
- if (data->tempAA.nonDirtyPass >= MAX_TEMPORAL_AA_LEVELS)
+ if (eyeData->tempAA.nonDirtyPass >= MAX_TEMPORAL_AA_LEVELS)
return;
static const QVector2D vertexOffsets[MAX_TEMPORAL_AA_LEVELS] = {
@@ -3334,18 +3598,18 @@ void Q3DSSceneManager::updateTemporalAA(Q3DSLayerNode *layer3DS)
};
static const QVector2D blendFactor(0.5f, 0.5f);
- const QVector2D vertexOffset = adjustedProgressiveTemporalAAVertexOffset(vertexOffsets[data->tempAA.passIndex], data);
+ const QVector2D vertexOffset = adjustedProgressiveTemporalAAVertexOffset(vertexOffsets[eyeData->tempAA.passIndex], data);
- if (!data->tempAA.fg) {
- data->tempAA.extraColorBuf = createProgressiveTemporalAAExtraBuffer(layer3DS);
+ if (!eyeData->tempAA.fg) {
+ eyeData->tempAA.extraColorBuf = createProgressiveTemporalAAExtraBuffer(layer3DS);
- stealLayerRenderTarget(&data->tempAA.stolenColorBuf, layer3DS);
+ stealLayerRenderTarget(&eyeData->tempAA.stolenColorBuf, layer3DS, eyeData);
// start with the existing color buffer as the accumulator
- data->tempAA.currentAccumulatorTexture = data->tempAA.stolenColorBuf;
- data->tempAA.currentOutputTexture = data->tempAA.extraColorBuf;
+ eyeData->tempAA.currentAccumulatorTexture = eyeData->tempAA.stolenColorBuf;
+ eyeData->tempAA.currentOutputTexture = eyeData->tempAA.extraColorBuf;
int i = 0;
- for (Qt3DRender::QAbstractTexture *t : { data->tempAA.currentOutputTexture, data->tempAA.currentAccumulatorTexture }) {
+ for (Qt3DRender::QAbstractTexture *t : { eyeData->tempAA.currentOutputTexture, eyeData->tempAA.currentAccumulatorTexture }) {
Qt3DRender::QRenderTargetOutput *rtOutput = new Qt3DRender::QRenderTargetOutput;
rtOutput->setAttachmentPoint(Qt3DRender::QRenderTargetOutput::Color0);
rtOutput->setTexture(t);
@@ -3353,44 +3617,63 @@ void Q3DSSceneManager::updateTemporalAA(Q3DSLayerNode *layer3DS)
m_profiler->trackNewObject(rt, Q3DSProfiler::RenderTargetObject, layer3DS->id(),
"Temporal AA RT for layer %s", layer3DS->id().constData());
rt->addOutput(rtOutput);
- data->tempAA.rts[i++] = rt;
+ eyeData->tempAA.rts[i++] = rt;
}
auto rtSel = createProgressiveTemporalAAFramegraph(data->layerFgRoot,
- data->tempAA.rts[0],
+ eyeData->tempAA.rts[0],
m_fsQuadTag,
- &data->tempAA.layerFilter,
- &data->tempAA.accumTexParam,
- &data->tempAA.lastTexParam,
- &data->tempAA.blendFactorsParam);
- data->tempAA.fg = data->tempAA.rtSel = rtSel;
+ &eyeData->tempAA.layerFilter,
+ &eyeData->tempAA.accumTexParam,
+ &eyeData->tempAA.lastTexParam,
+ &eyeData->tempAA.blendFactorsParam);
+ eyeData->tempAA.fg = eyeData->tempAA.rtSel = rtSel;
- data->tempAA.layerFilter->addLayer(m_fsQuadTag);
+ eyeData->tempAA.layerFilter->addLayer(m_fsQuadTag);
}
// Jiggle
- setLayerCameraSizeProperties(layer3DS, vertexOffset);
+ Qt3DRender::QCamera *camera = static_cast<Qt3DRender::QCamera *>(eyeData->cameraSelector->camera());
+ setSingleCameraSizeProperties(data, camera, vertexOffset);
// Input
- data->tempAA.accumTexParam->setValue(QVariant::fromValue(data->tempAA.currentAccumulatorTexture));
- data->tempAA.lastTexParam->setValue(QVariant::fromValue(data->effectActive ? data->effLayerTexture : data->layerTexture));
- data->tempAA.blendFactorsParam->setValue(blendFactor);
+ eyeData->tempAA.accumTexParam->setValue(QVariant::fromValue(eyeData->tempAA.currentAccumulatorTexture));
+ eyeData->tempAA.lastTexParam->setValue(QVariant::fromValue(data->effectActive ? eyeData->effLayerTexture : eyeData->layerTexture));
+ eyeData->tempAA.blendFactorsParam->setValue(blendFactor);
// Output
- data->tempAA.rtSel->setTarget(data->tempAA.rts[data->tempAA.passIndex]);
+ eyeData->tempAA.rtSel->setTarget(eyeData->tempAA.rts[eyeData->tempAA.passIndex]);
// have the compositor use the blended results instead of the layer texture
- data->compositorSourceParam->setValue(QVariant::fromValue(data->tempAA.currentOutputTexture));
+ eyeData->compositorSourceParam->setValue(QVariant::fromValue(eyeData->tempAA.currentOutputTexture));
// play ping-pong with the buffers
- std::swap(data->tempAA.currentAccumulatorTexture, data->tempAA.currentOutputTexture);
+ std::swap(eyeData->tempAA.currentAccumulatorTexture, eyeData->tempAA.currentOutputTexture);
// Make sure layer caching does not interfere and the layer's framegraph subtree
// is still active as long as TAA accumulation is active.
m_layerUncachePending = true;
- data->tempAA.passIndex = (data->tempAA.passIndex + 1) % MAX_TEMPORAL_AA_LEVELS;
- ++data->tempAA.nonDirtyPass;
+ eyeData->tempAA.passIndex = (eyeData->tempAA.passIndex + 1) % MAX_TEMPORAL_AA_LEVELS;
+ ++eyeData->tempAA.nonDirtyPass;
+}
+
+void Q3DSSceneManager::updateTemporalAA(Q3DSLayerNode *layer3DS)
+{
+ Q3DSLayerAttached *data = layer3DS->attached<Q3DSLayerAttached>();
+ if (!data || !data->cam3DS)
+ return;
+
+ // No TempAA for MSAA/SSAA layers for now.
+ if (data->msaaSampleCount > 1 || data->ssaaScaleFactor > 1)
+ return;
+
+ if (!m_engine->isStereoscopic()) {
+ updateEyeTemporalAA(layer3DS, data, data->eyeMono);
+ } else {
+ updateEyeTemporalAA(layer3DS, data, data->eyeLeft);
+ updateEyeTemporalAA(layer3DS, data, data->eyeRight);
+ }
}
static void setLayerBlending(Qt3DRender::QBlendEquation *blendFunc,
@@ -3516,10 +3799,23 @@ void Q3DSSceneManager::buildLayerQuadEntity(Q3DSLayerNode *layer3DS, Qt3DCore::Q
if (!flags.testFlag(LayerQuadCustomShader)) {
updateLayerCompositorProgram(layer3DS);
- if (!data->compositorSourceParam->parent())
- data->compositorSourceParam->setParent(data->layerSceneRootEntity);
+ if (!data->eyeMono->compositorSourceParam->parent())
+ data->eyeMono->compositorSourceParam->setParent(data->layerSceneRootEntity);
+
+ renderPass->addParameter(data->eyeMono->compositorSourceParam);
+
+ if (!data->eyeLeft->compositorSourceParam->parent())
+ data->eyeLeft->compositorSourceParam->setParent(data->layerSceneRootEntity);
+
+ renderPass->addParameter(data->eyeLeft->compositorSourceParam);
- renderPass->addParameter(data->compositorSourceParam);
+ if (!data->eyeRight->compositorSourceParam->parent())
+ data->eyeRight->compositorSourceParam->setParent(data->layerSceneRootEntity);
+
+ renderPass->addParameter(data->eyeRight->compositorSourceParam);
+
+ // Add stereo parameter
+ renderPass->addParameter(m_stereoMode);
}
technique->addRenderPass(renderPass);
@@ -3563,14 +3859,18 @@ void Q3DSSceneManager::updateLayerCompositorProgram(Q3DSLayerNode *layer3DS)
fragSuffix = QLatin1String("_core.frag");
}
+ QString stereoString;
+ if (m_engine->isStereoscopic())
+ stereoString = QLatin1String("_stereoscopic");
+
const QString vertSrc = QLatin1String("qrc:/q3ds/shaders/compositor") + vertSuffix;
shaderProgram->setVertexShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(vertSrc)));
QString fragSrc;
if (msaa)
- fragSrc = QLatin1String("qrc:/q3ds/shaders/compositor_ms") + QString::number(data->msaaSampleCount) + fragSuffix;
+ fragSrc = QLatin1String("qrc:/q3ds/shaders/compositor_ms") + QString::number(data->msaaSampleCount) + stereoString + fragSuffix;
else
- fragSrc = QLatin1String("qrc:/q3ds/shaders/compositor") + fragSuffix;
+ fragSrc = QLatin1String("qrc:/q3ds/shaders/compositor") + stereoString + fragSuffix;
shaderProgram->setFragmentShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(fragSrc)));
@@ -3815,7 +4115,8 @@ void Q3DSSceneManager::rebuildCompositorLayerChain()
baseLayerParam->setValue(QVariant::fromValue(data->advBlend.tempTexture));
Qt3DRender::QParameter *blendLayerParam = new Qt3DRender::QParameter;
blendLayerParam->setName(QLatin1String("blend_layer"));
- blendLayerParam->setValue(QVariant::fromValue(data->effectActive ? data->effLayerTexture : data->layerTexture));
+ // TODO: Needs to be duplicated for all eyes?
+ blendLayerParam->setValue(QVariant::fromValue(data->effectActive ? data->eyeMono->effLayerTexture : data->eyeMono->layerTexture));
renderPass->addParameter(baseLayerParam);
renderPass->addParameter(blendLayerParam);
} else {
@@ -4034,6 +4335,7 @@ void Q3DSSceneManager::buildLayerScene(Q3DSGraphObject *obj, Q3DSLayerNode *laye
}
Qt3DCore::QEntity *newEntity = nullptr;
+ QVector<Qt3DRender::QCamera *> cameras;
switch (obj->type()) {
case Q3DSGraphObject::Light:
@@ -4080,8 +4382,10 @@ void Q3DSSceneManager::buildLayerScene(Q3DSGraphObject *obj, Q3DSLayerNode *laye
}
break;
case Q3DSGraphObject::Camera:
- newEntity = buildCamera(static_cast<Q3DSCameraNode *>(obj), layer3DS, parent);
- addChildren(obj, newEntity);
+ cameras = buildCameras(static_cast<Q3DSCameraNode *>(obj), layer3DS, parent);
+ addChildren(obj, cameras.at(0));
+ addChildren(obj, cameras.at(1));
+ addChildren(obj, cameras.at(2));
break;
case Q3DSGraphObject::Alias:
{
@@ -5057,12 +5361,24 @@ void Q3DSSceneManager::retagSubMeshes(Q3DSModelNode *model3DS)
}
if (data->globalEffectiveVisibility) {
- Qt3DRender::QLayer *newTag = sm.hasTransparency ? layerData->transparentTag : layerData->opaqueTag;
+ Qt3DRender::QLayer *newTag = sm.hasTransparency ? layerData->eyeMono->transparentTag : layerData->eyeMono->opaqueTag;
if (!sm.entity->components().contains(newTag)) {
- Qt3DRender::QLayer *prevTag = newTag == layerData->transparentTag ? layerData->opaqueTag : layerData->transparentTag;
+ Qt3DRender::QLayer *prevTag = newTag == layerData->eyeMono->transparentTag ? layerData->eyeMono->opaqueTag : layerData->eyeMono->transparentTag;
sm.entity->removeComponent(prevTag);
sm.entity->addComponent(newTag);
}
+ Qt3DRender::QLayer *newTagLeft = sm.hasTransparency ? layerData->eyeLeft->transparentTag : layerData->eyeLeft->opaqueTag;
+ if (!sm.entity->components().contains(newTagLeft)) {
+ Qt3DRender::QLayer *prevTagLeft = newTagLeft == layerData->eyeLeft->transparentTag ? layerData->eyeLeft->opaqueTag : layerData->eyeLeft->transparentTag;
+ sm.entity->removeComponent(prevTagLeft);
+ sm.entity->addComponent(newTagLeft);
+ }
+ Qt3DRender::QLayer *newTagRight = sm.hasTransparency ? layerData->eyeRight->transparentTag : layerData->eyeRight->opaqueTag;
+ if (!sm.entity->components().contains(newTagRight)) {
+ Qt3DRender::QLayer *prevTagRight = newTagRight == layerData->eyeRight->transparentTag ? layerData->eyeRight->opaqueTag : layerData->eyeRight->transparentTag;
+ sm.entity->removeComponent(prevTagRight);
+ sm.entity->addComponent(newTagRight);
+ }
}
profData.needsBlending = sm.hasTransparency;
@@ -5915,26 +6231,26 @@ void Q3DSSceneManager::updateCustomMaterial(Q3DSCustomMaterialInstance *m, Q3DSR
}
}
-void Q3DSSceneManager::initEffect(Q3DSEffectInstance *eff3DS, Q3DSLayerNode *layer3DS)
+void Q3DSSceneManager::initEyeEffect(Q3DSEffectInstance *eff3DS, Q3DSLayerNode *layer3DS, Q3DSEyeData *eyeData)
{
Q3DSLayerAttached *layerData = static_cast<Q3DSLayerAttached *>(layer3DS->attached());
Q3DSEffectAttached *effData = new Q3DSEffectAttached;
effData->entity = layerData->entity;
effData->layer3DS = layer3DS;
eff3DS->setAttached(effData);
- layerData->effectData.effects.append(eff3DS);
+ eyeData->effectData.effects.append(eff3DS);
- if (!layerData->effLayerTexture) {
+ if (!eyeData->effLayerTexture) {
// The effect's output texture is never multisampled. If the layer
// (i.e. the effect's input) uses MSAA or SSAA then an extra resolve
// step will be applied via BlitFramebuffer. From that point on
// everything behaves like non-MSAA.
const QSize sz = safeLayerPixelSize(layerData);
- layerData->effLayerTexture = newColorBuffer(sz, 1);
- layerData->effLayerTexture->setParent(layerData->entity);
- m_profiler->trackNewObject(layerData->effLayerTexture, Q3DSProfiler::Texture2DObject,
+ eyeData->effLayerTexture = newColorBuffer(sz, 1);
+ eyeData->effLayerTexture->setParent(layerData->entity);
+ m_profiler->trackNewObject(eyeData->effLayerTexture, Q3DSProfiler::Texture2DObject,
"Effect buffer for layer %s", layer3DS->id().constData());
- layerData->sizeManagedTextures.append(layerData->effLayerTexture);
+ layerData->sizeManagedTextures.append(eyeData->effLayerTexture);
}
effData->propertyChangeObserverIndex = eff3DS->addPropertyChangeObserver(
@@ -5942,6 +6258,18 @@ void Q3DSSceneManager::initEffect(Q3DSEffectInstance *eff3DS, Q3DSLayerNode *lay
effData->eventObserverIndex = eff3DS->addEventHandler(QString(), std::bind(&Q3DSSceneManager::handleEvent, this, std::placeholders::_1));
}
+void Q3DSSceneManager::initEffect(Q3DSEffectInstance *eff3DS, Q3DSLayerNode *layer3DS)
+{
+ Q3DSLayerAttached *layerData = static_cast<Q3DSLayerAttached *>(layer3DS->attached());
+ initEyeEffect(eff3DS, layer3DS, layerData->eyeMono);
+#if 0
+ // Note: Effects currently disabled for stereoscopic views
+ // TODO: Should we here duplicate eff3DS to make this work?
+ initEyeEffect(eff3DS, layer3DS, layerData->eyeLeft);
+ initEyeEffect(eff3DS, layer3DS, layerData->eyeRight);
+#endif
+}
+
static inline void setTextureInfoUniform(Qt3DRender::QParameter *param, Qt3DRender::QAbstractTexture *texture)
{
const QSize size = Q3DSImageManager::instance().size(texture);
@@ -6070,10 +6398,9 @@ static inline void setupStencilTest(Qt3DRender::QStencilTest *stencilTest, const
// The main entry point for activating/deactivating effects on a layer. Called
// upon scene building and every time an effect gets hidden/shown (eyeball).
-void Q3DSSceneManager::updateEffectStatus(Q3DSLayerNode *layer3DS, bool force)
+void Q3DSSceneManager::updateEyeEffectStatus(Q3DSLayerNode *layer3DS, Q3DSEyeData *eyeData, bool force)
{
- Q3DSLayerAttached *layerData = static_cast<Q3DSLayerAttached *>(layer3DS->attached());
- const int count = layerData->effectData.effects.count();
+ const int count = eyeData->effectData.effects.count();
int activeEffectCount = 0;
int firstActiveIndex = 0;
int lastActiveIndex = 0;
@@ -6084,7 +6411,7 @@ void Q3DSSceneManager::updateEffectStatus(Q3DSLayerNode *layer3DS, bool force)
// by nature. So reverse the iteration in order to match the 3DS1
// results.
for (int i = count - 1; i >= 0; --i) {
- Q3DSEffectInstance *eff3DS = layerData->effectData.effects[i];
+ Q3DSEffectInstance *eff3DS = eyeData->effectData.effects[i];
Q3DSEffectAttached *effData = static_cast<Q3DSEffectAttached *>(eff3DS->attached());
if (eff3DS->eyeballEnabled() && effData->visibilityTag == Q3DSGraphObjectAttached::Visible) {
++activeEffectCount;
@@ -6099,7 +6426,7 @@ void Q3DSSceneManager::updateEffectStatus(Q3DSLayerNode *layer3DS, bool force)
}
}
- layerData->effectData.activeEffectCount = activeEffectCount;
+ eyeData->effectData.activeEffectCount = activeEffectCount;
if (!change && !force)
return; // nothing has changed
@@ -6113,69 +6440,88 @@ void Q3DSSceneManager::updateEffectStatus(Q3DSLayerNode *layer3DS, bool force)
activeEffectCount, count, layer3DS->id().constData());
for (int i = 0; i < count; ++i) {
- Q3DSEffectInstance *eff3DS = layerData->effectData.effects[i];
+ Q3DSEffectInstance *eff3DS = eyeData->effectData.effects[i];
deactivateEffect(eff3DS, layer3DS);
}
- layerData->effectData.combinedEffectFlags = 0;
+ eyeData->effectData.combinedEffectFlags = 0;
- cleanupEffectSource(layer3DS);
+ cleanupEffectSource(layer3DS, eyeData);
if (activeEffectCount) {
- ensureEffectSource(layer3DS);
+ ensureEffectSource(layer3DS, eyeData);
Qt3DRender::QAbstractTexture *prevOutput = nullptr;
for (int i = count - 1; i >= 0; --i) {
- Q3DSEffectInstance *eff3DS = layerData->effectData.effects[i];
+ Q3DSEffectInstance *eff3DS = eyeData->effectData.effects[i];
if (eff3DS->eyeballEnabled() && eff3DS->attached()->visibilityTag == Q3DSGraphObjectAttached::Visible) {
Q3DSSceneManager::EffectActivationFlags flags = 0;
if (i == firstActiveIndex)
flags |= Q3DSSceneManager::EffIsFirst;
if (i == lastActiveIndex)
flags |= Q3DSSceneManager::EffIsLast;
- activateEffect(eff3DS, layer3DS, flags, prevOutput);
- layerData->effectData.combinedEffectFlags |= eff3DS->effect()->flags();
+ activateEffect(eff3DS, layer3DS, flags, prevOutput, eyeData);
+ eyeData->effectData.combinedEffectFlags |= eff3DS->effect()->flags();
prevOutput = eff3DS->attached<Q3DSEffectAttached>()->outputTexture;
}
}
}
+ if (activeEffectCount) {
+ // The layer compositor must use the output of the effect passes from now on.
+ eyeData->compositorSourceParam->setValue(QVariant::fromValue(eyeData->effLayerTexture));
+ } else {
+ eyeData->compositorSourceParam->setValue(QVariant::fromValue(eyeData->layerTexture));
+ }
+}
+
+void Q3DSSceneManager::updateEffectStatus(Q3DSLayerNode *layer3DS, bool force)
+{
+ Q3DSLayerAttached *layerData = static_cast<Q3DSLayerAttached *>(layer3DS->attached());
+ updateEyeEffectStatus(layer3DS, layerData->eyeMono, force);
+#if 0
+ // Note: Effects currently disabled for stereoscopic views
+ updateEyeEffectStatus(layer3DS, layerData->eyeLeft, force);
+ updateEyeEffectStatus(layer3DS, layerData->eyeRight, force);
+#endif
+
const bool wasActive = layerData->effectActive;
+ int activeEffectCount = layerData->eyeMono->effectData.activeEffectCount;
+
if (activeEffectCount) {
// The layer compositor must use the output of the effect passes from now on.
- layerData->compositorSourceParam->setValue(QVariant::fromValue(layerData->effLayerTexture));
- layerData->effectActive = true;
+ // TODO: Effects are disabled for stereoscopic views as msaa+effect currently doesn't work for stereo
+ layerData->effectActive = m_engine->isStereoscopic() ? false : true;
if (!wasActive && layerData->msaaSampleCount > 1)
updateLayerCompositorProgram(layer3DS);
} else {
- layerData->compositorSourceParam->setValue(QVariant::fromValue(layerData->layerTexture));
layerData->effectActive = false;
if (wasActive && layerData->msaaSampleCount > 1)
updateLayerCompositorProgram(layer3DS);
}
}
-void Q3DSSceneManager::ensureEffectSource(Q3DSLayerNode *layer3DS)
+void Q3DSSceneManager::ensureEffectSource(Q3DSLayerNode *layer3DS, Q3DSEyeData *eyeData)
{
Q3DSLayerAttached *layerData = static_cast<Q3DSLayerAttached *>(layer3DS->attached());
// MSAA/SSAA layers need an additional resolve step since effects can only
// work with non-MSAA (and 1:1 sized) textures as input.
const bool needsResolve = layerData->msaaSampleCount > 1 || layerData->ssaaScaleFactor > 1;
if (needsResolve) {
- layerData->effectData.sourceTexture = new Qt3DRender::QTexture2D(m_rootEntity);
- m_profiler->trackNewObject(layerData->effectData.sourceTexture, Q3DSProfiler::Texture2DObject, layer3DS->id(),
+ eyeData->effectData.sourceTexture = new Qt3DRender::QTexture2D(m_rootEntity);
+ m_profiler->trackNewObject(eyeData->effectData.sourceTexture, Q3DSProfiler::Texture2DObject, layer3DS->id(),
"Resolve buffer for effects");
- layerData->effectData.sourceTexture->setFormat(Qt3DRender::QAbstractTexture::RGBA8_UNorm);
- layerData->effectData.sourceTexture->setMinificationFilter(Qt3DRender::QAbstractTexture::Linear);
- layerData->effectData.sourceTexture->setMagnificationFilter(Qt3DRender::QAbstractTexture::Linear);
- layerData->effectData.ownsSourceTexture = true;
+ eyeData->effectData.sourceTexture->setFormat(Qt3DRender::QAbstractTexture::RGBA8_UNorm);
+ eyeData->effectData.sourceTexture->setMinificationFilter(Qt3DRender::QAbstractTexture::Linear);
+ eyeData->effectData.sourceTexture->setMagnificationFilter(Qt3DRender::QAbstractTexture::Linear);
+ eyeData->effectData.ownsSourceTexture = true;
Qt3DRender::QRenderTarget *rtSrc = new Qt3DRender::QRenderTarget;
m_profiler->trackNewObject(rtSrc, Q3DSProfiler::RenderTargetObject, layer3DS->id(),
"Src resolve RT for effects");
Qt3DRender::QRenderTargetOutput *rtSrcOutput = new Qt3DRender::QRenderTargetOutput;
rtSrcOutput->setAttachmentPoint(Qt3DRender::QRenderTargetOutput::Color0);
- rtSrcOutput->setTexture(layerData->layerTexture);
+ rtSrcOutput->setTexture(eyeData->layerTexture);
rtSrc->addOutput(rtSrcOutput);
Qt3DRender::QRenderTarget *rtDst = new Qt3DRender::QRenderTarget;
@@ -6183,11 +6529,11 @@ void Q3DSSceneManager::ensureEffectSource(Q3DSLayerNode *layer3DS)
"Dst resolve RT for effects");
Qt3DRender::QRenderTargetOutput *rtDstOutput = new Qt3DRender::QRenderTargetOutput;
rtDstOutput->setAttachmentPoint(Qt3DRender::QRenderTargetOutput::Color0);
- rtDstOutput->setTexture(layerData->effectData.sourceTexture);
+ rtDstOutput->setTexture(eyeData->effectData.sourceTexture);
rtDst->addOutput(rtDstOutput);
- Qt3DRender::QBlitFramebuffer *resolve = new Qt3DRender::QBlitFramebuffer(layerData->effectData.effectRoot);
- layerData->effectData.resolve = resolve;
+ Qt3DRender::QBlitFramebuffer *resolve = new Qt3DRender::QBlitFramebuffer(eyeData->effectData.effectRoot);
+ eyeData->effectData.resolve = resolve;
new Qt3DRender::QNoDraw(resolve);
resolve->setSource(rtSrc);
resolve->setDestination(rtDst);
@@ -6198,33 +6544,34 @@ void Q3DSSceneManager::ensureEffectSource(Q3DSLayerNode *layer3DS)
};
// must track layer size, but without the SSAA scale
- prepareSizeDependentTexture(layerData->effectData.sourceTexture, layer3DS, blitResizer,
+ prepareSizeDependentTexture(eyeData->effectData.sourceTexture, layer3DS, blitResizer,
Q3DSLayerAttached::SizeManagedTexture::IgnoreSSAA);
// set initial blit rects
blitResizer(layer3DS);
} else {
- layerData->effectData.sourceTexture = layerData->layerTexture;
- layerData->effectData.ownsSourceTexture = false;
- layerData->effectData.resolve = nullptr;
+ eyeData->effectData.sourceTexture = eyeData->layerTexture;
+ eyeData->effectData.ownsSourceTexture = false;
+ eyeData->effectData.resolve = nullptr;
}
}
-void Q3DSSceneManager::cleanupEffectSource(Q3DSLayerNode *layer3DS)
+void Q3DSSceneManager::cleanupEffectSource(Q3DSLayerNode *layer3DS, Q3DSEyeData *eyeData)
{
Q3DSLayerAttached *layerData = static_cast<Q3DSLayerAttached *>(layer3DS->attached());
- delete layerData->effectData.resolve;
- layerData->effectData.resolve = nullptr;
- if (layerData->effectData.ownsSourceTexture) {
- layerData->effectData.ownsSourceTexture = false;
- layerData->sizeManagedTextures.removeOne(layerData->effectData.sourceTexture);
- delete layerData->effectData.sourceTexture;
+ delete eyeData->effectData.resolve;
+ eyeData->effectData.resolve = nullptr;
+ if (eyeData->effectData.ownsSourceTexture) {
+ eyeData->effectData.ownsSourceTexture = false;
+ layerData->sizeManagedTextures.removeOne(eyeData->effectData.sourceTexture);
+ delete eyeData->effectData.sourceTexture;
}
}
void Q3DSSceneManager::activateEffect(Q3DSEffectInstance *eff3DS,
Q3DSLayerNode *layer3DS,
EffectActivationFlags flags,
- Qt3DRender::QAbstractTexture *prevOutput)
+ Qt3DRender::QAbstractTexture *prevOutput,
+ Q3DSEyeData *eyeData)
{
Q3DSLayerAttached *layerData = static_cast<Q3DSLayerAttached *>(layer3DS->attached());
@@ -6293,15 +6640,15 @@ void Q3DSSceneManager::activateEffect(Q3DSEffectInstance *eff3DS,
// effLayerTexture. Effects in-between have their own output textures while
// the source refers to the output of the previous effect.
if (flags.testFlag(EffIsFirst)) {
- Q_ASSERT(layerData->effectData.sourceTexture);
- effData->sourceTexture = layerData->effectData.sourceTexture;
+ Q_ASSERT(eyeData->effectData.sourceTexture);
+ effData->sourceTexture = eyeData->effectData.sourceTexture;
} else {
Q_ASSERT(prevOutput);
effData->sourceTexture = prevOutput;
}
if (flags.testFlag(EffIsLast)) {
- Q_ASSERT(layerData->effLayerTexture);
- effData->outputTexture = layerData->effLayerTexture;
+ Q_ASSERT(eyeData->effLayerTexture);
+ effData->outputTexture = eyeData->effLayerTexture;
effData->ownsOutputTexture = false;
} else {
effData->outputTexture = new Qt3DRender::QTexture2D(m_rootEntity);
@@ -6404,7 +6751,7 @@ void Q3DSSceneManager::activateEffect(Q3DSEffectInstance *eff3DS,
if (valid) {
Qt3DRender::QParameter *texParam = new Qt3DRender::QParameter;
texParam->setName(samplerName);
- texParam->setValue(QVariant::fromValue(layerData->depthTextureData.depthTexture));
+ texParam->setValue(QVariant::fromValue(eyeData->depthTextureData.depthTexture));
paramList.append(texParam);
// Have the usual Info and flag uniforms.
Qt3DRender::QParameter *texInfoParam = new Qt3DRender::QParameter;
@@ -6624,7 +6971,7 @@ void Q3DSSceneManager::activateEffect(Q3DSEffectInstance *eff3DS,
effData->quadEntity = buildFsQuad(quadInfo);
// framegraph
- Qt3DRender::QRenderTargetSelector *rtSel = new Qt3DRender::QRenderTargetSelector(layerData->effectData.effectRoot);
+ Qt3DRender::QRenderTargetSelector *rtSel = new Qt3DRender::QRenderTargetSelector(eyeData->effectData.effectRoot);
effData->passFgRoots.append(rtSel);
Qt3DRender::QRenderTarget *rt = new Qt3DRender::QRenderTarget;
m_profiler->trackNewObject(rt, Q3DSProfiler::RenderTargetObject, "RT for effect %s pass %d",
@@ -7467,8 +7814,18 @@ void Q3DSSceneManager::prepareNextFrame()
// Post-processing effects have uniforms that need to be updated on every frame.
Q3DSLayerAttached *layerData = static_cast<Q3DSLayerAttached *>(layer3DS->attached());
if (layerData) {
- for (Q3DSEffectInstance *eff3DS : qAsConst(layerData->effectData.effects))
- updateEffectForNextFrame(eff3DS, nextFrameNo);
+ if (!m_engine->isStereoscopic())
+ for (Q3DSEffectInstance *eff3DS : qAsConst(layerData->eyeMono->effectData.effects))
+ updateEffectForNextFrame(eff3DS, nextFrameNo);
+#if 0
+ // Note: Effects currently disabled for stereoscopic views
+ if (m_engine->isStereoscopic()) {
+ for (Q3DSEffectInstance *eff3DS : qAsConst(layerData->eyeLeft->effectData.effects))
+ updateEffectForNextFrame(eff3DS, nextFrameNo);
+ for (Q3DSEffectInstance *eff3DS : qAsConst(layerData->eyeRight->effectData.effects))
+ updateEffectForNextFrame(eff3DS, nextFrameNo);
+ }
+#endif
}
});
@@ -7497,8 +7854,9 @@ void Q3DSSceneManager::prepareNextFrame()
// the AppFrame uniform) cannot be cached since the effect needs
// continuous updates (and in 3DS2 the effect's output is part of the
// layer's final texture that is "cached").
+ // Note: Testing just mono eye should be enough, effects among eyes are same
const bool hasTimeDependentEffect = layerData->effectActive
- && layerData->effectData.combinedEffectFlags.testFlag(Q3DSEffect::ReliesOnTime);
+ && (layerData->eyeMono->effectData.combinedEffectFlags.testFlag(Q3DSEffect::ReliesOnTime));
if (!layerData->wasDirty && !m_layerUncachePending && !subDirty && !hasTimeDependentEffect) {
++layerData->nonDirtyRenderCount;
@@ -7657,8 +8015,19 @@ void Q3DSSceneManager::updateSubTreeRecursive(Q3DSGraphObject *obj)
// (orthographic) shadow maps, ssao texture, effects all rely on camera properties like clip range
updateShadowMapStatus(data->layer3DS);
updateSsaoStatus(data->layer3DS);
- for (Q3DSEffectInstance *eff3DS : data->layer3DS->attached<Q3DSLayerAttached>()->effectData.effects)
- updateEffect(eff3DS);
+ Q3DSLayerAttached *layerData = static_cast<Q3DSLayerAttached *>(data->layer3DS->attached());
+ if (!m_engine->isStereoscopic())
+ for (Q3DSEffectInstance *eff3DS : layerData->eyeMono->effectData.effects)
+ updateEffect(eff3DS);
+#if 0
+ // Note: Effects currently disabled for stereoscopic views
+ if (m_engine->isStereoscopic()) {
+ for (Q3DSEffectInstance *eff3DS : layerData->eyeLeft->effectData.effects)
+ updateEffect(eff3DS);
+ for (Q3DSEffectInstance *eff3DS : layerData->eyeRight->effectData.effects)
+ updateEffect(eff3DS);
+ }
+#endif
m_wasDirty = true;
markLayerForObjectDirty(cam3DS);
}
@@ -7779,6 +8148,7 @@ void Q3DSSceneManager::updateSubTreeRecursive(Q3DSGraphObject *obj)
if (activeFlagChanges || sourceChanges) // active/deactivate effects by rebuilding the chain
updateEffectStatus(data->layer3DS, sourceChanges);
// send changed parameter values to the shader
+ // TODO: Should we here handle & update effect for all eyes?
updateEffect(eff3DS);
m_wasDirty = true;
markLayerForObjectDirty(eff3DS);
@@ -7913,18 +8283,31 @@ void Q3DSSceneManager::setNodeVisibility(Q3DSNode *node, bool visible)
"Attempted to manage visibility of a node with non-dedicated entity by QLayer. This should not happen.");
Q3DSLayerAttached *layerData = static_cast<Q3DSLayerAttached *>(data->layer3DS->attached());
- if (!layerData->opaqueTag || !layerData->transparentTag) // bail out for subpresentation layers
+ if (!layerData->eyeMono->opaqueTag || !layerData->eyeMono->transparentTag ||
+ !layerData->eyeLeft->opaqueTag || !layerData->eyeLeft->transparentTag ||
+ !layerData->eyeRight->opaqueTag || !layerData->eyeRight->transparentTag) {
+ // bail out for subpresentation layers
return;
+ }
if (!visible) {
data->visibilityTag = Q3DSGraphObjectAttached::Hidden;
- data->entity->removeComponent(layerData->opaqueTag);
- data->entity->removeComponent(layerData->transparentTag);
+ data->entity->removeComponent(layerData->eyeMono->opaqueTag);
+ data->entity->removeComponent(layerData->eyeMono->transparentTag);
+ data->entity->removeComponent(layerData->eyeLeft->opaqueTag);
+ data->entity->removeComponent(layerData->eyeLeft->transparentTag);
+ data->entity->removeComponent(layerData->eyeRight->opaqueTag);
+ data->entity->removeComponent(layerData->eyeRight->transparentTag);
} else {
data->visibilityTag = Q3DSGraphObjectAttached::Visible;
- if (node->type() != Q3DSGraphObject::Text)
- data->entity->addComponent(layerData->opaqueTag);
- data->entity->addComponent(layerData->transparentTag);
+ if (node->type() != Q3DSGraphObject::Text) {
+ data->entity->addComponent(layerData->eyeMono->opaqueTag);
+ data->entity->addComponent(layerData->eyeLeft->opaqueTag);
+ data->entity->addComponent(layerData->eyeRight->opaqueTag);
+ }
+ data->entity->addComponent(layerData->eyeMono->transparentTag);
+ data->entity->addComponent(layerData->eyeLeft->transparentTag);
+ data->entity->addComponent(layerData->eyeRight->transparentTag);
}
// For models the model root entity is tagged with both opaque and
@@ -7933,12 +8316,20 @@ void Q3DSSceneManager::setNodeVisibility(Q3DSNode *node, bool visible)
if (node->type() == Q3DSGraphObject::Model) {
Q3DSModelAttached *mdata = static_cast<Q3DSModelAttached *>(node->attached());
for (Q3DSModelAttached::SubMesh &sm : mdata->subMeshes) {
- Qt3DRender::QLayer *tag = sm.hasTransparency ? layerData->transparentTag : layerData->opaqueTag;
+ Qt3DRender::QLayer *tag = sm.hasTransparency ? layerData->eyeMono->transparentTag : layerData->eyeMono->opaqueTag;
+ Qt3DRender::QLayer *tagLeft = sm.hasTransparency ? layerData->eyeLeft->transparentTag : layerData->eyeLeft->opaqueTag;
+ Qt3DRender::QLayer *tagRight = sm.hasTransparency ? layerData->eyeRight->transparentTag : layerData->eyeRight->opaqueTag;
if (!visible) {
- sm.entity->removeComponent(layerData->opaqueTag);
- sm.entity->removeComponent(layerData->transparentTag);
+ sm.entity->removeComponent(layerData->eyeMono->opaqueTag);
+ sm.entity->removeComponent(layerData->eyeMono->transparentTag);
+ sm.entity->removeComponent(layerData->eyeLeft->opaqueTag);
+ sm.entity->removeComponent(layerData->eyeLeft->transparentTag);
+ sm.entity->removeComponent(layerData->eyeRight->opaqueTag);
+ sm.entity->removeComponent(layerData->eyeRight->transparentTag);
} else {
sm.entity->addComponent(tag);
+ sm.entity->addComponent(tagLeft);
+ sm.entity->addComponent(tagRight);
}
}
}
@@ -8503,8 +8894,19 @@ void Q3DSSceneManager::handleNodeGlobalChange(Q3DSNode *node)
// (orthographic) shadow maps, ssao texture, effects all rely on camera properties like clip range
updateShadowMapStatus(data->layer3DS);
updateSsaoStatus(data->layer3DS);
- for (Q3DSEffectInstance *eff3DS : data->layer3DS->attached<Q3DSLayerAttached>()->effectData.effects)
- updateEffect(eff3DS);
+ Q3DSLayerAttached *layerData = static_cast<Q3DSLayerAttached *>(data->layer3DS->attached());
+ if (!m_engine->isStereoscopic())
+ for (Q3DSEffectInstance *eff3DS : layerData->eyeMono->effectData.effects)
+ updateEffect(eff3DS);
+#if 0
+ // Note: Effects currently disabled for stereoscopic views
+ if (m_engine->isStereoscopic()) {
+ for (Q3DSEffectInstance *eff3DS : layerData->eyeLeft->effectData.effects)
+ updateEffect(eff3DS);
+ for (Q3DSEffectInstance *eff3DS : layerData->eyeRight->effectData.effects)
+ updateEffect(eff3DS);
+ }
+#endif
}
} else if (node->type() != Q3DSGraphObject::Layer) {
const bool isVisible = node->attached<Q3DSNodeAttached>()->globalEffectiveVisibility;
@@ -8591,7 +8993,10 @@ void Q3DSSceneManager::handleSceneChange(Q3DSScene *, Q3DSGraphObject::DirtyFlag
Q3DSEffectInstance *eff3DS = static_cast<Q3DSEffectInstance *>(objOrChild);
Q3DSLayerNode *layer3DS = findLayerForObjectInScene(eff3DS);
if (layer3DS) {
- layer3DS->attached<Q3DSLayerAttached>()->effectData.effects.removeOne(eff3DS);
+ Q3DSLayerAttached *layerData = static_cast<Q3DSLayerAttached *>(layer3DS->attached());
+ layerData->eyeMono->effectData.effects.removeOne(eff3DS);
+ layerData->eyeLeft->effectData.effects.removeOne(eff3DS);
+ layerData->eyeRight->effectData.effects.removeOne(eff3DS);
needsEffectUpdate = true;
}
}
diff --git a/src/runtime/q3dsscenemanager_p.h b/src/runtime/q3dsscenemanager_p.h
index 7447489..5746776 100644
--- a/src/runtime/q3dsscenemanager_p.h
+++ b/src/runtime/q3dsscenemanager_p.h
@@ -106,6 +106,78 @@ namespace Qt3DExtras {
class QPlaneMesh;
}
+struct Q3DSEyeData
+{
+ Qt3DRender::QCameraSelector *cameraSelector = nullptr;
+ Qt3DRender::QLayer *opaqueTag = nullptr;
+ Qt3DRender::QLayer *transparentTag = nullptr;
+ Qt3DRender::QRenderTargetSelector *depthRtSelector = nullptr;
+ Qt3DRender::QRenderTargetSelector *ssaoRtSelector = nullptr;
+ Qt3DRender::QFrameGraphNode *shadowRoot = nullptr;
+ Qt3DRender::QFrameGraphNode *effectRoot = nullptr;
+ Qt3DRender::QClearBuffers *clearBuffers = nullptr;
+ Qt3DRender::QAbstractTexture *effLayerTexture = nullptr;
+ Qt3DRender::QRenderTargetSelector *rtSelector = nullptr;
+ Qt3DRender::QAbstractTexture *layerDS = nullptr;
+
+ Qt3DRender::QAbstractTexture *layerTexture = nullptr;
+ Qt3DRender::QParameter *compositorSourceParam = nullptr;
+
+ struct DepthTextureData {
+ bool enabled = false;
+ Qt3DRender::QRenderTargetSelector *rtSelector = nullptr;
+ Qt3DRender::QAbstractTexture *depthTexture = nullptr;
+ Qt3DRender::QClearBuffers *clearBuffers = nullptr;
+ Qt3DRender::QLayerFilter *layerFilterOpaque = nullptr;
+ Qt3DRender::QLayerFilter *layerFilterTransparent = nullptr;
+ } depthTextureData;
+
+ struct ProgAAData {
+ Qt3DRender::QFrameGraphNode *fg = nullptr;
+ Qt3DRender::QRenderTargetSelector *rtSel = nullptr;
+ Qt3DRender::QRenderTarget *rts[2];
+ Qt3DRender::QAbstractTexture *currentAccumulatorTexture = nullptr;
+ Qt3DRender::QAbstractTexture *currentOutputTexture = nullptr;
+ Qt3DRender::QAbstractTexture *stolenColorBuf = nullptr;
+ Qt3DRender::QAbstractTexture *extraColorBuf = nullptr;
+ Qt3DRender::QParameter *accumTexParam = nullptr;
+ Qt3DRender::QParameter *lastTexParam = nullptr;
+ Qt3DRender::QParameter *blendFactorsParam = nullptr;
+ Qt3DRender::QLayerFilter *layerFilter = nullptr;
+ int pass = 0;
+ int curTarget = 0;
+ bool cameraAltered = false;
+ bool enabled = false;
+ } progAA;
+
+ struct TempAAData {
+ int nonDirtyPass = 0;
+ int passIndex = 0; // wraps around
+ Qt3DRender::QFrameGraphNode *fg = nullptr;
+ Qt3DRender::QRenderTargetSelector *rtSel = nullptr;
+ Qt3DRender::QRenderTarget *rts[2];
+ Qt3DRender::QAbstractTexture *currentAccumulatorTexture = nullptr;
+ Qt3DRender::QAbstractTexture *currentOutputTexture = nullptr;
+ Qt3DRender::QAbstractTexture *stolenColorBuf = nullptr;
+ Qt3DRender::QAbstractTexture *extraColorBuf = nullptr;
+ Qt3DRender::QParameter *accumTexParam = nullptr;
+ Qt3DRender::QParameter *lastTexParam = nullptr;
+ Qt3DRender::QParameter *blendFactorsParam = nullptr;
+ Qt3DRender::QLayerFilter *layerFilter = nullptr;
+ } tempAA;
+
+ struct EffectData {
+ Qt3DRender::QFrameGraphNode *effectRoot = nullptr;
+ QVector<Q3DSEffectInstance *> effects;
+ int activeEffectCount = 0;
+ Q3DSEffect::Flags combinedEffectFlags;
+ Qt3DRender::QAbstractTexture *sourceTexture = nullptr;
+ bool ownsSourceTexture = false;
+ Qt3DRender::QFrameGraphNode *resolve = nullptr;
+ } effectData;
+
+};
+
// The Qt 3D scene, once built, still has to react to property changes.
// Therefore some extra bookkeeping is needed, so that the Qt 3D objects to
// update are accessible in a sane manner. This is done via the *Attached
@@ -208,15 +280,17 @@ public:
// layers always have light data
lightsData.reset(new Q3DSNodeAttached::LightsData);
}
+
+ Q3DSEyeData *eyeMono = nullptr;
+ Q3DSEyeData *eyeLeft = nullptr;
+ Q3DSEyeData *eyeRight = nullptr;
+
Qt3DCore::QEntity *layerSceneRootEntity = nullptr;
Qt3DCore::QEntity *compositorEntity = nullptr;
Qt3DRender::QFrameGraphNode *layerFgRoot = nullptr;
Qt3DCore::QNode *layerFgRootParent = nullptr;
Qt3DCore::QNode *layerFgDummyParent = nullptr;
Q3DSCameraNode *cam3DS = nullptr;
- Qt3DRender::QCameraSelector *cameraSelector = nullptr;
- Qt3DRender::QClearBuffers *clearBuffers = nullptr;
- Qt3DRender::QRenderTargetSelector *rtSelector = nullptr;
typedef std::function<void(Q3DSLayerNode *)> SizeChangeCallback;
struct SizeManagedTexture {
enum Flag {
@@ -235,10 +309,6 @@ public:
QVector<SizeManagedTexture> sizeManagedTextures;
QVector<SizeChangeCallback> layerSizeChangeCallbacks;
- Qt3DRender::QAbstractTexture *layerTexture = nullptr;
- Qt3DRender::QAbstractTexture *effLayerTexture = nullptr;
- Qt3DRender::QAbstractTexture *layerDS = nullptr;
- Qt3DRender::QParameter *compositorSourceParam = nullptr;
Qt3DRender::QRenderPass *compositorRenderPass = nullptr;
std::function<void()> updateCompositorCalculations = nullptr;
std::function<void()> updateSubPresentationSize = nullptr;
@@ -253,8 +323,6 @@ public:
bool wasDirty = false;
bool rayCasterBusy = false;
Qt3DRender::QParameter *cameraPropertiesParam = nullptr;
- Qt3DRender::QLayer *opaqueTag = nullptr;
- Qt3DRender::QLayer *transparentTag = nullptr;
Qt3DRender::QRayCaster *layerRayCaster = nullptr;
struct RayCastQueueEntry {
@@ -267,15 +335,6 @@ public:
};
QQueue<RayCastQueueEntry> rayCastQueue;
- struct DepthTextureData {
- bool enabled = false;
- Qt3DRender::QRenderTargetSelector *rtSelector = nullptr;
- Qt3DRender::QAbstractTexture *depthTexture = nullptr;
- Qt3DRender::QClearBuffers *clearBuffers = nullptr;
- Qt3DRender::QLayerFilter *layerFilterOpaque = nullptr;
- Qt3DRender::QLayerFilter *layerFilterTransparent = nullptr;
- } depthTextureData;
-
struct SsaoTextureData {
bool enabled = false;
Qt3DRender::QRenderTargetSelector *rtSelector = nullptr;
@@ -326,55 +385,11 @@ public:
} custMatParams;
} shadowMapData;
- struct ProgAAData {
- Qt3DRender::QFrameGraphNode *fg = nullptr;
- Qt3DRender::QRenderTargetSelector *rtSel = nullptr;
- Qt3DRender::QRenderTarget *rts[2];
- Qt3DRender::QAbstractTexture *currentAccumulatorTexture = nullptr;
- Qt3DRender::QAbstractTexture *currentOutputTexture = nullptr;
- Qt3DRender::QAbstractTexture *stolenColorBuf = nullptr;
- Qt3DRender::QAbstractTexture *extraColorBuf = nullptr;
- Qt3DRender::QParameter *accumTexParam = nullptr;
- Qt3DRender::QParameter *lastTexParam = nullptr;
- Qt3DRender::QParameter *blendFactorsParam = nullptr;
- Qt3DRender::QLayerFilter *layerFilter = nullptr;
- int pass = 0;
- int curTarget = 0;
- bool cameraAltered = false;
- bool enabled = false;
- } progAA;
-
- struct TempAAData {
- int nonDirtyPass = 0;
- int passIndex = 0; // wraps around
- Qt3DRender::QFrameGraphNode *fg = nullptr;
- Qt3DRender::QRenderTargetSelector *rtSel = nullptr;
- Qt3DRender::QRenderTarget *rts[2];
- Qt3DRender::QAbstractTexture *currentAccumulatorTexture = nullptr;
- Qt3DRender::QAbstractTexture *currentOutputTexture = nullptr;
- Qt3DRender::QAbstractTexture *stolenColorBuf = nullptr;
- Qt3DRender::QAbstractTexture *extraColorBuf = nullptr;
- Qt3DRender::QParameter *accumTexParam = nullptr;
- Qt3DRender::QParameter *lastTexParam = nullptr;
- Qt3DRender::QParameter *blendFactorsParam = nullptr;
- Qt3DRender::QLayerFilter *layerFilter = nullptr;
- } tempAA;
-
struct AdvBlendData {
Qt3DRender::QAbstractTexture *tempTexture = nullptr;
Qt3DRender::QRenderTarget *tempRt = nullptr;
} advBlend;
- struct EffectData {
- Qt3DRender::QFrameGraphNode *effectRoot = nullptr;
- QVector<Q3DSEffectInstance *> effects;
- int activeEffectCount = 0;
- Q3DSEffect::Flags combinedEffectFlags;
- Qt3DRender::QAbstractTexture *sourceTexture = nullptr;
- bool ownsSourceTexture = false;
- Qt3DRender::QFrameGraphNode *resolve = nullptr;
- } effectData;
-
struct IBLProbeData {
Qt3DRender::QAbstractTexture *lightProbeTexture = nullptr;
Qt3DRender::QAbstractTexture *lightProbe2Texture = nullptr;
@@ -393,8 +408,8 @@ public:
Q_DECLARE_OPERATORS_FOR_FLAGS(Q3DSLayerAttached::SizeManagedTexture::Flags)
// NB! Q3DSLayerAttached::SizeManagedTexture cannot be Q_MOVABLE_TYPE due to std::function in it
Q_DECLARE_TYPEINFO(Q3DSLayerAttached::PerLightShadowMapData, Q_MOVABLE_TYPE);
-Q_DECLARE_TYPEINFO(Q3DSLayerAttached::ProgAAData, Q_MOVABLE_TYPE);
-Q_DECLARE_TYPEINFO(Q3DSLayerAttached::TempAAData, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(Q3DSEyeData::ProgAAData, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(Q3DSEyeData::TempAAData, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(Q3DSLayerAttached::RayCastQueueEntry, Q_MOVABLE_TYPE);
// ensure a lookup based on a texture hits the entry regardless of the callback or flags
@@ -412,6 +427,8 @@ class Q3DSCameraAttached : public Q3DSNodeAttached
{
public:
Qt3DRender::QCamera *camera = nullptr;
+ Qt3DRender::QCamera *cameraLeft = nullptr;
+ Qt3DRender::QCamera *cameraRight = nullptr;
};
class Q3DSGroupAttached : public Q3DSNodeAttached
@@ -692,6 +709,12 @@ public:
Qt3DLogic::QFrameAction *frameAction = nullptr;
};
+ struct ViewportSet {
+ Qt3DRender::QViewport *viewportMono = nullptr;
+ Qt3DRender::QViewport *viewportLeft = nullptr;
+ Qt3DRender::QViewport *viewportRight = nullptr;
+ };
+
Q3DSSceneManager();
~Q3DSSceneManager();
@@ -761,6 +784,7 @@ public:
Q3DSInputManager *inputManager() { return m_inputManager; }
+ void setEyeDepthTextureEnabled(Q3DSLayerNode *layer3DS, Q3DSEyeData *eyeData, bool enabled);
void setDepthTextureEnabled(Q3DSLayerNode *layer3DS, bool enabled);
void rebuildModelMaterial(Q3DSModelNode *model3DS);
@@ -778,6 +802,7 @@ public:
void goToTimeAction(Q3DSGraphObject *sceneOrComponent, float milliseconds, bool pause);
void queueEvent(const Q3DSGraphObject::Event &e);
+ void updateViewportRects();
private:
Q_DISABLE_COPY(Q3DSSceneManager)
@@ -785,6 +810,8 @@ private:
void updateSubPresentationHosts();
void loadSubUipPresentation(Q3DSSubPresentation *sp);
void initSubTree(Q3DSGraphObject *subTreeRoot);
+ void updateCamerasStatus(Q3DSLayerAttached *layerData);
+ Q3DSEyeData *buildEye(Q3DSLayerNode *layer3DS, Qt3DRender::QViewport *viewport);
void buildLayer(Q3DSLayerNode *layer3DS, Qt3DRender::QFrameGraphNode *parent, const QSize &parentSize);
void buildSubPresentationLayer(Q3DSLayerNode *layer3DS, const QSize &parentSize);
Qt3DRender::QRenderTarget *newLayerRenderTarget(const QSize &layerPixelSize, int msaaSampleCount,
@@ -794,6 +821,8 @@ private:
QSize calculateLayerSize(Q3DSLayerNode *layer3DS, const QSize &parentSize);
QPointF calculateLayerPos(Q3DSLayerNode *layer3DS, const QSize &parentSize);
void updateSizesForLayer(Q3DSLayerNode *layer3DS, const QSize &newParentSize);
+ void setSingleCameraSizeProperties(Q3DSLayerAttached *data, Qt3DRender::QCamera *camera,
+ const QVector2D &offset = QVector2D());
void setLayerCameraSizeProperties(Q3DSLayerNode *layer3DS, const QVector2D &offset = QVector2D());
void setLayerSizeProperties(Q3DSLayerNode *layer3DS);
void setLayerProperties(Q3DSLayerNode *layer3DS);
@@ -810,12 +839,16 @@ private:
void updateOrthoShadowCam(Q3DSLayerAttached::PerLightShadowMapData *d, Q3DSLightNode *light3DS, Q3DSLayerAttached *layerData);
void genOrthoBlurPassFg(Q3DSLayerAttached::PerLightShadowMapData *d, Qt3DRender::QAbstractTexture *inTex,
Qt3DRender::QAbstractTexture *outTex, const QString &passName, Q3DSLightNode *light3DS);
- void stealLayerRenderTarget(Qt3DRender::QAbstractTexture **stolenColorBuf, Q3DSLayerNode *layer3DS);
+ void stealLayerRenderTarget(Qt3DRender::QAbstractTexture **stolenColorBuf, Q3DSLayerNode *layer3DS, Q3DSEyeData *eyeData);
Qt3DRender::QAbstractTexture *createProgressiveTemporalAAExtraBuffer(Q3DSLayerNode *layer3DS);
+ bool updateEyeProgressiveAA(Q3DSLayerNode *layer3DS, Q3DSLayerAttached *data, Q3DSEyeData *eyeData);
bool updateProgressiveAA(Q3DSLayerNode *layer3DS);
+ void updateEyeTemporalAA(Q3DSLayerNode *layer3DS, Q3DSLayerAttached *data, Q3DSEyeData *eyeData);
void updateTemporalAA(Q3DSLayerNode *layer3DS);
- Qt3DRender::QCamera *buildCamera(Q3DSCameraNode *cam3DS, Q3DSLayerNode *layer3DS, Qt3DCore::QEntity *parent);
+ QVector<Qt3DRender::QCamera *> buildCameras(Q3DSCameraNode *cam3DS, Q3DSLayerNode *layer3DS,
+ Qt3DCore::QEntity *parent);
+ void setEyeCameraProperties(Q3DSCameraNode *camNode, Qt3DRender::QCamera *camera);
void setCameraProperties(Q3DSCameraNode *camNode, int changeFlags);
bool setActiveLayerCamera(Q3DSCameraNode *cam3DS, Q3DSLayerNode *layer3DS);
Q3DSCameraNode *findFirstCamera(Q3DSLayerNode *layer3DS);
@@ -847,10 +880,11 @@ private:
void updateTextureParameters(Q3DSTextureParameters &textureParameters, Q3DSImage *image);
void updateDefaultMaterial(Q3DSDefaultMaterial *m, Q3DSReferencedMaterial *rm, Q3DSModelNode *model3DS);
void updateCustomMaterial(Q3DSCustomMaterialInstance *m, Q3DSReferencedMaterial *rm, Q3DSModelNode *model3DS);
+ void updateEyeEffectStatus(Q3DSLayerNode *layer3DS, Q3DSEyeData *eyeData, bool force = false);
void updateEffectStatus(Q3DSLayerNode *layer3DS, bool force = false);
- void ensureEffectSource(Q3DSLayerNode *layer3DS);
- void cleanupEffectSource(Q3DSLayerNode *layer3DS);
- void activateEffect(Q3DSEffectInstance *eff3DS, Q3DSLayerNode *layer3DS, EffectActivationFlags flags, Qt3DRender::QAbstractTexture *prevOutput);
+ void ensureEffectSource(Q3DSLayerNode *layer3DS, Q3DSEyeData *eyeData);
+ void cleanupEffectSource(Q3DSLayerNode *layer3DS, Q3DSEyeData *eyeData);
+ void activateEffect(Q3DSEffectInstance *eff3DS, Q3DSLayerNode *layer3DS, EffectActivationFlags flags, Qt3DRender::QAbstractTexture *prevOutput, Q3DSEyeData *eyeData);
void deactivateEffect(Q3DSEffectInstance *eff3DS, Q3DSLayerNode *layer3DS);
void setupEffectTextureBuffer(Q3DSEffectAttached::TextureBuffer *tb, const Q3DSMaterial::PassBuffer &bufDesc, Q3DSLayerNode *layer3DS);
void createEffectBuffers(Q3DSEffectInstance *eff3DS);
@@ -863,6 +897,7 @@ private:
QVector<Q3DSNodeAttached::LightsData *> getLightsDataForNode(Q3DSGraphObject *object);
QVector<Qt3DRender::QParameter *> prepareSeparateLightUniforms(const QVector<Q3DSLightSource> &allLights, const QString &lightsUniformName);
+ void initEyeEffect(Q3DSEffectInstance *eff3DS, Q3DSLayerNode *layer3DS, Q3DSEyeData *eyeData);
void initEffect(Q3DSEffectInstance *eff3DS, Q3DSLayerNode *layer3DS);
void initBehaviorInstance(Q3DSBehaviorInstance *behaviorInstance);
void initImage(Q3DSImage *image);
@@ -964,7 +999,8 @@ private:
Qt3DCore::QEntity *m_compositorParentEntity = nullptr;
QVector<Qt3DCore::QEntity *> m_compositorEntities;
bool m_compositorEnabled = true;
-
+ QVector<ViewportSet> m_viewports;
+ Qt3DRender::QParameter *m_stereoMode;
friend class Q3DSFrameUpdater;
friend class Q3DSProfiler;
friend class Q3DSSlidePlayer;
diff --git a/src/runtime/q3dsviewportsettings.cpp b/src/runtime/q3dsviewportsettings.cpp
index 3f45448..cdd67c3 100644
--- a/src/runtime/q3dsviewportsettings.cpp
+++ b/src/runtime/q3dsviewportsettings.cpp
@@ -56,6 +56,16 @@ Q3DSViewportSettings::ScaleMode Q3DSViewportSettings::scaleMode() const
return m_scaleMode;
}
+Q3DSViewportSettings::StereoMode Q3DSViewportSettings::stereoMode() const
+{
+ return m_stereoMode;
+}
+
+float Q3DSViewportSettings::stereoEyeSeparation() const
+{
+ return m_stereoEyeSeparation;
+}
+
void Q3DSViewportSettings::setMatteEnabled(bool isEnabled)
{
if (m_matteEnabled != isEnabled) {
@@ -88,4 +98,20 @@ void Q3DSViewportSettings::setScaleMode(Q3DSViewportSettings::ScaleMode mode)
}
}
+void Q3DSViewportSettings::setStereoMode(Q3DSViewportSettings::StereoMode mode)
+{
+ if (m_stereoMode != mode) {
+ m_stereoMode = mode;
+ emit stereoModeChanged();
+ }
+}
+
+void Q3DSViewportSettings::setStereoEyeSeparation(float value)
+{
+ if (m_stereoEyeSeparation != value) {
+ m_stereoEyeSeparation = value;
+ emit stereoEyeSeparationChanged();
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/runtime/q3dsviewportsettings_p.h b/src/runtime/q3dsviewportsettings_p.h
index 93d3e33..067b43f 100644
--- a/src/runtime/q3dsviewportsettings_p.h
+++ b/src/runtime/q3dsviewportsettings_p.h
@@ -54,6 +54,8 @@ class Q3DSV_PRIVATE_EXPORT Q3DSViewportSettings : public QObject
Q_PROPERTY(QColor matteColor READ matteColor WRITE setMatteColor NOTIFY matteColorChanged)
Q_PROPERTY(bool showRenderStats READ isShowingRenderStats WRITE setShowRenderStats NOTIFY showRenderStatsChanged)
Q_PROPERTY(ScaleMode scaleMode READ scaleMode WRITE setScaleMode NOTIFY scaleModeChanged)
+ Q_PROPERTY(StereoMode stereoMode READ stereoMode WRITE setStereoMode NOTIFY stereoModeChanged)
+ Q_PROPERTY(float stereoEyeSeparation READ stereoEyeSeparation WRITE setStereoEyeSeparation NOTIFY stereoEyeSeparationChanged)
public:
enum ScaleMode {
@@ -63,24 +65,39 @@ public:
};
Q_ENUM(ScaleMode)
+ enum StereoMode {
+ StereoModeMono,
+ StereoModeTopBottom,
+ StereoModeLeftRight,
+ StereoModeAnaglyphRedCyan,
+ StereoModeAnaglyphGreenMagenta
+ };
+ Q_ENUM(StereoMode)
+
explicit Q3DSViewportSettings(QObject *parent = nullptr);
bool matteEnabled() const;
QColor matteColor() const;
bool isShowingRenderStats() const;
ScaleMode scaleMode() const;
+ StereoMode stereoMode() const;
+ float stereoEyeSeparation() const;
public Q_SLOTS:
void setMatteEnabled(bool isEnabled);
void setMatteColor(const QColor &color);
void setShowRenderStats(bool show);
void setScaleMode(ScaleMode mode);
+ void setStereoMode(StereoMode mode);
+ void setStereoEyeSeparation(float value);
Q_SIGNALS:
void matteEnabledChanged();
void matteColorChanged();
void showRenderStatsChanged();
void scaleModeChanged();
+ void stereoModeChanged();
+ void stereoEyeSeparationChanged();
private:
Q_DISABLE_COPY(Q3DSViewportSettings)
@@ -89,6 +106,8 @@ private:
QColor m_matteColor = QColor(51, 51, 51);
bool m_showRenderStats = false;
Q3DSViewportSettings::ScaleMode m_scaleMode = ScaleModeFill;
+ Q3DSViewportSettings::StereoMode m_stereoMode = StereoModeMono;
+ float m_stereoEyeSeparation = 0.4f;
};
QT_END_NAMESPACE
diff --git a/src/runtime/shaders/compositor_ms2_stereoscopic.frag b/src/runtime/shaders/compositor_ms2_stereoscopic.frag
new file mode 100644
index 0000000..aa197a5
--- /dev/null
+++ b/src/runtime/shaders/compositor_ms2_stereoscopic.frag
@@ -0,0 +1,49 @@
+#version 310 es
+precision highp float;
+
+in vec2 texCoord;
+
+uniform highp sampler2DMS texLeft;
+uniform highp sampler2DMS texRight;
+uniform highp int stereoMode;
+
+out vec4 fragColor;
+
+void main()
+{
+ ivec2 tc = ivec2(floor(vec2(textureSize(texLeft)) * texCoord));
+ vec4 cLeft = vec4(0.0);
+ vec4 cRight = vec4(0.0);
+ // Fetch from correct texture
+ if (stereoMode == 1) {
+ if (texCoord.y > 0.5)
+ cLeft = texelFetch(texLeft, tc, 0) + texelFetch(texLeft, tc, 1);
+ else
+ cRight = texelFetch(texRight, tc, 0) + texelFetch(texRight, tc, 1);
+ } else if (stereoMode == 2) {
+ if (texCoord.x < 0.5)
+ cLeft = texelFetch(texLeft, tc, 0) + texelFetch(texLeft, tc, 1);
+ else
+ cRight = texelFetch(texRight, tc, 0) + texelFetch(texRight, tc, 1);
+ } else {
+ cLeft = texelFetch(texLeft, tc, 0) + texelFetch(texLeft, tc, 1);
+ cRight = texelFetch(texRight, tc, 0) + texelFetch(texRight, tc, 1);
+ }
+
+ cLeft /= 2.0;
+ cRight /= 2.0;
+ // This discard, while not necessarily ideal for some GPUs, is necessary to
+ // get correct results with certain layer blend modes for example.
+ if (cLeft.a == 0.0 && cRight.a == 0.0)
+ discard;
+ if (stereoMode == 3) {
+ cLeft.g = 0.0;
+ cLeft.b = 0.0;
+ cRight.r = 0.0;
+ } else if (stereoMode == 4) {
+ cLeft.r = 0.0;
+ cLeft.b = 0.0;
+ cRight.g = 0.0;
+ }
+ fragColor = cLeft + cRight;
+}
diff --git a/src/runtime/shaders/compositor_ms2_stereoscopic_core.frag b/src/runtime/shaders/compositor_ms2_stereoscopic_core.frag
new file mode 100644
index 0000000..3ce4722
--- /dev/null
+++ b/src/runtime/shaders/compositor_ms2_stereoscopic_core.frag
@@ -0,0 +1,48 @@
+#version 330 core
+
+in vec2 texCoord;
+
+uniform sampler2DMS texLeft;
+uniform sampler2DMS texRight;
+uniform int stereoMode;
+
+out vec4 fragColor;
+
+void main()
+{
+ ivec2 tc = ivec2(floor(textureSize(texLeft) * texCoord));
+ vec4 cLeft = vec4(0.0);
+ vec4 cRight = vec4(0.0);
+ // Fetch from correct texture
+ if (stereoMode == 1) {
+ if (texCoord.y > 0.5)
+ cLeft = texelFetch(texLeft, tc, 0) + texelFetch(texLeft, tc, 1);
+ else
+ cRight = texelFetch(texRight, tc, 0) + texelFetch(texRight, tc, 1);
+ } else if (stereoMode == 2) {
+ if (texCoord.x < 0.5)
+ cLeft = texelFetch(texLeft, tc, 0) + texelFetch(texLeft, tc, 1);
+ else
+ cRight = texelFetch(texRight, tc, 0) + texelFetch(texRight, tc, 1);
+ } else {
+ cLeft = texelFetch(texLeft, tc, 0) + texelFetch(texLeft, tc, 1);
+ cRight = texelFetch(texRight, tc, 0) + texelFetch(texRight, tc, 1);
+ }
+
+ cLeft /= 2.0;
+ cRight /= 2.0;
+ // This discard, while not necessarily ideal for some GPUs, is necessary to
+ // get correct results with certain layer blend modes for example.
+ if (cLeft.a == 0.0 && cRight.a == 0.0)
+ discard;
+ if (stereoMode == 3) {
+ cLeft.g = 0.0;
+ cLeft.b = 0.0;
+ cRight.r = 0.0;
+ } else if (stereoMode == 4) {
+ cLeft.r = 0.0;
+ cLeft.b = 0.0;
+ cRight.g = 0.0;
+ }
+ fragColor = cLeft + cRight;
+}
diff --git a/src/runtime/shaders/compositor_ms4_stereoscopic.frag b/src/runtime/shaders/compositor_ms4_stereoscopic.frag
new file mode 100644
index 0000000..0ac9984
--- /dev/null
+++ b/src/runtime/shaders/compositor_ms4_stereoscopic.frag
@@ -0,0 +1,49 @@
+#version 310 es
+precision highp float;
+
+in vec2 texCoord;
+
+uniform highp sampler2DMS texLeft;
+uniform highp sampler2DMS texRight;
+uniform highp int stereoMode;
+
+out vec4 fragColor;
+
+void main()
+{
+ ivec2 tc = ivec2(floor(vec2(textureSize(texLeft)) * texCoord));
+ vec4 cLeft = vec4(0.0);
+ vec4 cRight = vec4(0.0);
+ // Fetch from correct texture
+ if (stereoMode == 1) {
+ if (texCoord.y > 0.5)
+ cLeft = texelFetch(texLeft, tc, 0) + texelFetch(texLeft, tc, 1) + texelFetch(texLeft, tc, 2) + texelFetch(texLeft, tc, 3);
+ else
+ cRight = texelFetch(texRight, tc, 0) + texelFetch(texRight, tc, 1) + texelFetch(texRight, tc, 2) + texelFetch(texRight, tc, 3);
+ } else if (stereoMode == 2) {
+ if (texCoord.x < 0.5)
+ cLeft = texelFetch(texLeft, tc, 0) + texelFetch(texLeft, tc, 1) + texelFetch(texLeft, tc, 2) + texelFetch(texLeft, tc, 3);
+ else
+ cRight = texelFetch(texRight, tc, 0) + texelFetch(texRight, tc, 1) + texelFetch(texRight, tc, 2) + texelFetch(texRight, tc, 3);
+ } else {
+ cLeft = texelFetch(texLeft, tc, 0) + texelFetch(texLeft, tc, 1) + texelFetch(texLeft, tc, 2) + texelFetch(texLeft, tc, 3);
+ cRight = texelFetch(texRight, tc, 0) + texelFetch(texRight, tc, 1) + texelFetch(texRight, tc, 2) + texelFetch(texRight, tc, 3);
+ }
+
+ cLeft /= 4.0;
+ cRight /= 4.0;
+ // This discard, while not necessarily ideal for some GPUs, is necessary to
+ // get correct results with certain layer blend modes for example.
+ if (cLeft.a == 0.0 && cRight.a == 0.0)
+ discard;
+ if (stereoMode == 3) {
+ cLeft.g = 0.0;
+ cLeft.b = 0.0;
+ cRight.r = 0.0;
+ } else if (stereoMode == 4) {
+ cLeft.r = 0.0;
+ cLeft.b = 0.0;
+ cRight.g = 0.0;
+ }
+ fragColor = cLeft + cRight;
+}
diff --git a/src/runtime/shaders/compositor_ms4_stereoscopic_core.frag b/src/runtime/shaders/compositor_ms4_stereoscopic_core.frag
new file mode 100644
index 0000000..571ec89
--- /dev/null
+++ b/src/runtime/shaders/compositor_ms4_stereoscopic_core.frag
@@ -0,0 +1,48 @@
+#version 330 core
+
+in vec2 texCoord;
+
+uniform sampler2DMS texLeft;
+uniform sampler2DMS texRight;
+uniform int stereoMode;
+
+out vec4 fragColor;
+
+void main()
+{
+ ivec2 tc = ivec2(floor(textureSize(texLeft) * texCoord));
+ vec4 cLeft = vec4(0.0);
+ vec4 cRight = vec4(0.0);
+ // Fetch from correct texture
+ if (stereoMode == 1) {
+ if (texCoord.y > 0.5)
+ cLeft = texelFetch(texLeft, tc, 0) + texelFetch(texLeft, tc, 1) + texelFetch(texLeft, tc, 2) + texelFetch(texLeft, tc, 3);
+ else
+ cRight = texelFetch(texRight, tc, 0) + texelFetch(texRight, tc, 1) + texelFetch(texRight, tc, 2) + texelFetch(texRight, tc, 3);
+ } else if (stereoMode == 2) {
+ if (texCoord.x < 0.5)
+ cLeft = texelFetch(texLeft, tc, 0) + texelFetch(texLeft, tc, 1) + texelFetch(texLeft, tc, 2) + texelFetch(texLeft, tc, 3);
+ else
+ cRight = texelFetch(texRight, tc, 0) + texelFetch(texRight, tc, 1) + texelFetch(texRight, tc, 2) + texelFetch(texRight, tc, 3);
+ } else {
+ cLeft = texelFetch(texLeft, tc, 0) + texelFetch(texLeft, tc, 1) + texelFetch(texLeft, tc, 2) + texelFetch(texLeft, tc, 3);
+ cRight = texelFetch(texRight, tc, 0) + texelFetch(texRight, tc, 1) + texelFetch(texRight, tc, 2) + texelFetch(texRight, tc, 3);
+ }
+
+ cLeft /= 4.0;
+ cRight /= 4.0;
+ // This discard, while not necessarily ideal for some GPUs, is necessary to
+ // get correct results with certain layer blend modes for example.
+ if (cLeft.a == 0.0 && cRight.a == 0.0)
+ discard;
+ if (stereoMode == 3) {
+ cLeft.g = 0.0;
+ cLeft.b = 0.0;
+ cRight.r = 0.0;
+ } else if (stereoMode == 4) {
+ cLeft.r = 0.0;
+ cLeft.b = 0.0;
+ cRight.g = 0.0;
+ }
+ fragColor = cLeft + cRight;
+}
diff --git a/src/runtime/shaders/compositor_stereoscopic.frag b/src/runtime/shaders/compositor_stereoscopic.frag
new file mode 100644
index 0000000..ab3aca5
--- /dev/null
+++ b/src/runtime/shaders/compositor_stereoscopic.frag
@@ -0,0 +1,43 @@
+precision highp float;
+
+varying vec2 texCoord;
+
+uniform sampler2D texLeft;
+uniform sampler2D texRight;
+uniform int stereoMode;
+
+void main()
+{
+ vec4 cLeft = vec4(0.0);
+ vec4 cRight = vec4(0.0);
+ // Fetch from correct texture
+ if (stereoMode == 1) {
+ if (texCoord.y > 0.5)
+ cLeft = texture2D(texLeft, texCoord);
+ else
+ cRight = texture2D(texRight, texCoord);
+ } else if (stereoMode == 2) {
+ if (texCoord.x < 0.5)
+ cLeft = texture2D(texLeft, texCoord);
+ else
+ cRight = texture2D(texRight, texCoord);
+ } else {
+ cLeft = texture2D(texLeft, texCoord);
+ cRight = texture2D(texRight, texCoord);
+ }
+
+ // This discard, while not necessarily ideal for some GPUs, is necessary to
+ // get correct results with certain layer blend modes for example.
+ if (cLeft.a == 0.0 && cRight.a == 0.0)
+ discard;
+ if (stereoMode == 3) {
+ cLeft.g = 0.0;
+ cLeft.b = 0.0;
+ cRight.r = 0.0;
+ } else if (stereoMode == 4) {
+ cLeft.r = 0.0;
+ cLeft.b = 0.0;
+ cRight.g = 0.0;
+ }
+ gl_FragColor = cLeft + cRight;
+}
diff --git a/src/runtime/shaders/compositor_stereoscopic_core.frag b/src/runtime/shaders/compositor_stereoscopic_core.frag
new file mode 100644
index 0000000..1cce56c
--- /dev/null
+++ b/src/runtime/shaders/compositor_stereoscopic_core.frag
@@ -0,0 +1,45 @@
+#version 330 core
+
+in vec2 texCoord;
+
+uniform sampler2D texLeft;
+uniform sampler2D texRight;
+uniform int stereoMode;
+
+out vec4 fragColor;
+
+void main()
+{
+ vec4 cLeft = vec4(0.0);
+ vec4 cRight = vec4(0.0);
+ // Fetch from correct texture
+ if (stereoMode == 1) {
+ if (texCoord.y > 0.5)
+ cLeft = texture(texLeft, texCoord);
+ else
+ cRight = texture(texRight, texCoord);
+ } else if (stereoMode == 2) {
+ if (texCoord.x < 0.5)
+ cLeft = texture(texLeft, texCoord);
+ else
+ cRight = texture(texRight, texCoord);
+ } else {
+ cLeft = texture(texLeft, texCoord);
+ cRight = texture(texRight, texCoord);
+ }
+
+ // This discard, while not necessarily ideal for some GPUs, is necessary to
+ // get correct results with certain layer blend modes for example.
+ if (cLeft.a == 0.0 && cRight.a == 0.0)
+ discard;
+ if (stereoMode == 3) {
+ cLeft.g = 0.0;
+ cLeft.b = 0.0;
+ cRight.r = 0.0;
+ } else if (stereoMode == 4) {
+ cLeft.r = 0.0;
+ cLeft.b = 0.0;
+ cRight.g = 0.0;
+ }
+ fragColor = cLeft + cRight;
+}
diff --git a/tests/auto/slides/tst_q3dsslides.cpp b/tests/auto/slides/tst_q3dsslides.cpp
index 5863b8e..59d8809 100644
--- a/tests/auto/slides/tst_q3dsslides.cpp
+++ b/tests/auto/slides/tst_q3dsslides.cpp
@@ -814,11 +814,11 @@ bool tst_Q3DSSlides::isNodeVisible(Q3DSNode *node)
return false;
auto layerAttached = nodeAttached->layer3DS->attached<Q3DSLayerAttached>();
- Q_ASSERT(layerAttached->opaqueTag || layerAttached->transparentTag);
+ Q_ASSERT(layerAttached->eyeMono->opaqueTag || layerAttached->eyeMono->transparentTag);
const bool visible = (nodeAttached->visibilityTag == Q3DSGraphObjectAttached::Visible);
// These should be in sync, or we're in trouble.
- Q_ASSERT(visible == (entity->components().contains(layerAttached->opaqueTag) || entity->components().contains(layerAttached->transparentTag)));
+ Q_ASSERT(visible == (entity->components().contains(layerAttached->eyeMono->opaqueTag) || entity->components().contains(layerAttached->eyeMono->transparentTag)));
return visible;
}
diff --git a/tools/q3dsviewer/q3dsmainwindow.cpp b/tools/q3dsviewer/q3dsmainwindow.cpp
index bd0f19e..3aed563 100644
--- a/tools/q3dsviewer/q3dsmainwindow.cpp
+++ b/tools/q3dsviewer/q3dsmainwindow.cpp
@@ -45,6 +45,8 @@
QT_BEGIN_NAMESPACE
+static const float STEREO_SEPARATION_STEP = 0.05f;
+
QString Q3DStudioMainWindow::fileFilter()
{
return tr("All Supported Formats (*.uia *.uip);;Studio UI Presentation (*.uip);;Application File (*.uia);;All Files (*)");
@@ -195,6 +197,128 @@ Q3DStudioMainWindow::Q3DStudioMainWindow(Q3DSWindow *view, Q3DSRemoteDeploymentM
});
viewMenu->addMenu(scaleModeMenu);
+
+ // Stereoscopic menu
+ QAction *stereoModeAction = new QAction(tr("Stereo Mode"));
+ addAction(stereoModeAction);
+ stereoModeAction->setShortcut(QKeySequence(tr("Ctrl+Shift+T")));
+ QMenu *stereoModeMenu = new QMenu();
+ stereoModeAction->setMenu(stereoModeMenu);
+
+ QAction *stereoModeMono = new QAction(tr("Mono"));
+ stereoModeMono->setCheckable(true);
+ stereoModeMono->setChecked(view->engine()->viewportSettings()->stereoMode() == Q3DSViewportSettings::StereoModeMono);
+ stereoModeMenu->addAction(stereoModeMono);
+
+ QAction *stereoModeTopBottom = new QAction(tr("Top-Bottom"));
+ stereoModeTopBottom->setCheckable(true);
+ stereoModeTopBottom->setChecked(view->engine()->viewportSettings()->stereoMode() == Q3DSViewportSettings::StereoModeTopBottom);
+ stereoModeMenu->addAction(stereoModeTopBottom);
+
+ QAction *stereoModeLeftRight = new QAction(tr("Left-Right"));
+ stereoModeLeftRight->setCheckable(true);
+ stereoModeLeftRight->setChecked(view->engine()->viewportSettings()->stereoMode() == Q3DSViewportSettings::StereoModeLeftRight);
+ stereoModeMenu->addAction(stereoModeLeftRight);
+
+ QAction *stereoModeAnaglyphRedCyan = new QAction(tr("Anaglyph (Red-Cyan)"));
+ stereoModeAnaglyphRedCyan->setCheckable(true);
+ stereoModeAnaglyphRedCyan->setChecked(view->engine()->viewportSettings()->stereoMode() == Q3DSViewportSettings::StereoModeAnaglyphRedCyan);
+ stereoModeMenu->addAction(stereoModeAnaglyphRedCyan);
+
+ QAction *stereoModeAnaglyphGreenMagenta = new QAction(tr("Anaglyph (Green-Magenta)"));
+ stereoModeAnaglyphGreenMagenta->setCheckable(true);
+ stereoModeAnaglyphGreenMagenta->setChecked(view->engine()->viewportSettings()->stereoMode() == Q3DSViewportSettings::StereoModeAnaglyphGreenMagenta);
+ stereoModeMenu->addAction(stereoModeAnaglyphGreenMagenta);
+
+ QAction *stereoSeparationIncrease = new QAction(tr("Increase Separation"));
+ stereoSeparationIncrease->setShortcut(QKeySequence(tr("Ctrl+Shift++")));
+ stereoModeMenu->addAction(stereoSeparationIncrease);
+
+ QAction *stereoSeparationDecrease = new QAction(tr("Decrease Separation"));
+ stereoSeparationDecrease->setShortcut(QKeySequence(tr("Ctrl+Shift+-")));
+ stereoModeMenu->addAction(stereoSeparationDecrease);
+
+ connect(stereoModeMono, &QAction::triggered, [=]() {
+ view->engine()->viewportSettings()->setStereoMode(Q3DSViewportSettings::StereoModeMono);
+ stereoModeMono->setChecked(true);
+ stereoModeTopBottom->setChecked(false);
+ stereoModeLeftRight->setChecked(false);
+ stereoModeAnaglyphRedCyan->setChecked(false);
+ stereoModeAnaglyphGreenMagenta->setChecked(false);
+ });
+ connect(stereoModeTopBottom, &QAction::triggered, [=]() {
+ view->engine()->viewportSettings()->setStereoMode(Q3DSViewportSettings::StereoModeTopBottom);
+ stereoModeMono->setChecked(false);
+ stereoModeTopBottom->setChecked(true);
+ stereoModeLeftRight->setChecked(false);
+ stereoModeAnaglyphRedCyan->setChecked(false);
+ stereoModeAnaglyphGreenMagenta->setChecked(false);
+ });
+ connect(stereoModeLeftRight, &QAction::triggered, [=]() {
+ view->engine()->viewportSettings()->setStereoMode(Q3DSViewportSettings::StereoModeLeftRight);
+ stereoModeMono->setChecked(false);
+ stereoModeTopBottom->setChecked(false);
+ stereoModeLeftRight->setChecked(true);
+ stereoModeAnaglyphRedCyan->setChecked(false);
+ stereoModeAnaglyphGreenMagenta->setChecked(false);
+ });
+ connect(stereoModeAnaglyphRedCyan, &QAction::triggered, [=]() {
+ view->engine()->viewportSettings()->setStereoMode(Q3DSViewportSettings::StereoModeAnaglyphRedCyan);
+ stereoModeMono->setChecked(false);
+ stereoModeTopBottom->setChecked(false);
+ stereoModeLeftRight->setChecked(false);
+ stereoModeAnaglyphRedCyan->setChecked(true);
+ stereoModeAnaglyphGreenMagenta->setChecked(false);
+ });
+ connect(stereoModeAnaglyphGreenMagenta, &QAction::triggered, [=]() {
+ view->engine()->viewportSettings()->setStereoMode(Q3DSViewportSettings::StereoModeAnaglyphGreenMagenta);
+ stereoModeMono->setChecked(false);
+ stereoModeTopBottom->setChecked(false);
+ stereoModeLeftRight->setChecked(false);
+ stereoModeAnaglyphRedCyan->setChecked(false);
+ stereoModeAnaglyphGreenMagenta->setChecked(true);
+ });
+
+ connect(stereoModeAction, &QAction::triggered, [=]() {
+ // toggle between the stereo modes
+ if (stereoModeMono->isChecked()) {
+ stereoModeMono->setChecked(false);
+ stereoModeTopBottom->setChecked(true);
+ view->engine()->viewportSettings()->setStereoMode(Q3DSViewportSettings::StereoModeTopBottom);
+ } else if (stereoModeTopBottom->isChecked()) {
+ stereoModeTopBottom->setChecked(false);
+ stereoModeLeftRight->setChecked(true);
+ view->engine()->viewportSettings()->setStereoMode(Q3DSViewportSettings::StereoModeLeftRight);
+ } else if (stereoModeLeftRight->isChecked()) {
+ stereoModeLeftRight->setChecked(false);
+ stereoModeAnaglyphRedCyan->setChecked(true);
+ view->engine()->viewportSettings()->setStereoMode(Q3DSViewportSettings::StereoModeAnaglyphRedCyan);
+ } else if (stereoModeAnaglyphRedCyan->isChecked()) {
+ stereoModeAnaglyphRedCyan->setChecked(false);
+ stereoModeAnaglyphGreenMagenta->setChecked(true);
+ view->engine()->viewportSettings()->setStereoMode(Q3DSViewportSettings::StereoModeAnaglyphGreenMagenta);
+ } else {
+ stereoModeAnaglyphGreenMagenta->setChecked(false);
+ stereoModeMono->setChecked(true);
+ view->engine()->viewportSettings()->setStereoMode(Q3DSViewportSettings::StereoModeMono);
+ }
+ });
+
+ connect(stereoSeparationIncrease, &QAction::triggered, [=]() {
+ float separation = view->engine()->viewportSettings()->stereoEyeSeparation();
+ separation += STEREO_SEPARATION_STEP;
+ separation = qMin(separation, 100.0f);
+ view->engine()->viewportSettings()->setStereoEyeSeparation(separation);
+ });
+ connect(stereoSeparationDecrease, &QAction::triggered, [=]() {
+ float separation = view->engine()->viewportSettings()->stereoEyeSeparation();
+ separation -= STEREO_SEPARATION_STEP;
+ separation = qMax(separation, 0.0f);
+ view->engine()->viewportSettings()->setStereoEyeSeparation(separation);
+ });
+
+ viewMenu->addMenu(stereoModeMenu);
+
QAction *fullscreenAction = new QAction(tr("Full Scree&n"), this);
connect(fullscreenAction, &QAction::triggered, [this]() {
if (!windowState().testFlag(Qt::WindowFullScreen)) {