diff --git a/src/core/framegraphes/forwardrenderer.cpp b/src/core/framegraphes/forwardrenderer.cpp index 2851262dd..0f3fea104 100644 --- a/src/core/framegraphes/forwardrenderer.cpp +++ b/src/core/framegraphes/forwardrenderer.cpp @@ -77,6 +77,9 @@ using namespace Kuesa; * size of the rendering surface, when different from the size reported by the * surface, this can be the case with high DPI screens. * + * The scene can also be rendered into a Qt3D render target by calling + * \fn setRenderTarget. + * * Frustum culling of Entities will be performed by default to only render * entities that are visible within the camera's frustum. This can be disabled * by calling \fn setFrustumCulling. @@ -134,6 +137,9 @@ using namespace Kuesa; * size of the rendering surface, when different from the size reported by the * surface, this can be the case with high DPI screens. * + * The scene can also be rendered into a Qt3D render target by calling + * setting the renderTarget property. + * * Frustum culling of Entities will be performed by default to only render * entities that are visible within the camera's frustum. This can be disabled * by setting the frustumCulling property. @@ -168,13 +174,13 @@ using namespace Kuesa; /*! \property Kuesa::ForwardRenderer::renderSurface - Holds the surface where rendering will occur. + Holds the surface where rendering will occur (if renderTarget is not set). */ /*! \qmlproperty Surface Kuesa::ForwardRenderer::renderSurface - Holds the surface where rendering will occur. + Holds the surface where rendering will occur (if renderTarget is not set). */ /*! @@ -189,6 +195,18 @@ using namespace Kuesa; Holds the size of the external render target. */ +/*! + \property Kuesa::ForwardRenderer::renderTarget + + If set, the scene will be rendered into the Color0 attachment of the given render target +*/ + +/*! + \qmlproperty Qt3DRender::RenderTarget Kuesa::ForwardRenderer::renderTarget + + If set, the scene will be rendered into the Color0 attachment of the given render target +*/ + /*! \property Kuesa::ForwardRenderer::viewportRect @@ -303,6 +321,7 @@ ForwardRenderer::ForwardRenderer(Qt3DCore::QNode *parent) , m_cameraSelector(new Qt3DRender::QCameraSelector()) , m_clearBuffers(new Qt3DRender::QClearBuffers()) , m_surfaceSelector(new Qt3DRender::QRenderSurfaceSelector()) + , m_renderTargetSelector(new Qt3DRender::QRenderTargetSelector()) , m_noDrawClearBuffer(new Qt3DRender::QNoDraw()) , m_frustumCulling(new Qt3DRender::QFrustumCulling()) , m_backToFrontSorting(false) @@ -328,12 +347,13 @@ ForwardRenderer::ForwardRenderer(Qt3DCore::QNode *parent) connect(m_surfaceSelector, &Qt3DRender::QRenderSurfaceSelector::externalRenderTargetSizeChanged, this, &ForwardRenderer::externalRenderTargetSizeChanged); connect(m_surfaceSelector, &Qt3DRender::QRenderSurfaceSelector::surfaceChanged, this, &ForwardRenderer::renderSurfaceChanged); connect(m_surfaceSelector, &Qt3DRender::QRenderSurfaceSelector::surfaceChanged, this, &ForwardRenderer::handleSurfaceChange); + connect(m_renderTargetSelector, &Qt3DRender::QRenderTargetSelector::targetChanged, this, &ForwardRenderer::renderTargetChanged); + connect(m_renderTargetSelector, &Qt3DRender::QRenderTargetSelector::targetChanged, this, &ForwardRenderer::handleSurfaceChange); + connect(m_renderTargetSelector, &Qt3DRender::QRenderTargetSelector::targetChanged, this, &ForwardRenderer::reconfigureFrameGraph); connect(m_frustumCulling, &Qt3DRender::QFrustumCulling::enabledChanged, this, &ForwardRenderer::frustumCullingChanged); // Reconfigure FrameGraph reconfigureFrameGraph(); - // Reconfigure Stages - reconfigureStages(); } ForwardRenderer::~ForwardRenderer() @@ -429,7 +449,6 @@ void ForwardRenderer::addPostProcessingEffect(AbstractPostProcessingEffect *effe // Reconfigure FrameGraph Tree reconfigureFrameGraph(); - reconfigureStages(); } } @@ -452,7 +471,6 @@ void ForwardRenderer::removePostProcessingEffect(AbstractPostProcessingEffect *e // Reconfigure FrameGraph Tree reconfigureFrameGraph(); - reconfigureStages(); } /*! @@ -484,13 +502,21 @@ QSize ForwardRenderer::externalRenderTargetSize() const } /*! - * Returns the surface where rendering will occur. + * Returns the surface where rendering will occur (if renderTarget is not set). */ QObject *ForwardRenderer::renderSurface() const { return m_surfaceSelector->surface(); } +/*! + * Returns the render target that the scene will be rendered into, or NULL, if it's rendered into a surface + */ +Qt3DRender::QRenderTarget *ForwardRenderer::renderTarget() const +{ + return m_renderTargetSelector->target(); +} + /*! * Returns the viewport rectangle in normalized coordinates. */ @@ -589,23 +615,29 @@ void ForwardRenderer::updateTextureSizes() */ void ForwardRenderer::handleSurfaceChange() { - auto surface = m_surfaceSelector->surface(); - Q_ASSERT(surface); + QObject *surface = m_surfaceSelector->surface(); + Qt3DRender::QAbstractTexture *renderTargetTexture = getRenderTargetColorTexture(); // disconnect any existing connections for (auto connection : qAsConst(m_resizeConnections)) disconnect(connection); m_resizeConnections.clear(); - // surface should only be a QWindow or QOffscreenSurface. Have to downcast since QSurface isn't QObject - if (auto window = qobject_cast(surface)) { - m_resizeConnections.push_back(connect(window, &QWindow::widthChanged, this, &ForwardRenderer::updateTextureSizes)); - m_resizeConnections.push_back(connect(window, &QWindow::heightChanged, this, &ForwardRenderer::updateTextureSizes)); - } else if (qobject_cast(surface)) { - m_resizeConnections.push_back(connect(m_surfaceSelector, &Qt3DRender::QRenderSurfaceSelector::externalRenderTargetSizeChanged, this, &ForwardRenderer::updateTextureSizes)); - } else { - qCWarning(kuesa) << Q_FUNC_INFO << "Unexpected surface type for surface " << surface; + if (renderTargetTexture) { + m_resizeConnections.push_back(connect(renderTargetTexture, &Qt3DRender::QAbstractTexture::widthChanged, this, &ForwardRenderer::updateTextureSizes)); + m_resizeConnections.push_back(connect(renderTargetTexture, &Qt3DRender::QAbstractTexture::heightChanged, this, &ForwardRenderer::updateTextureSizes)); + } else if (surface) { + // surface should only be a QWindow or QOffscreenSurface. Have to downcast since QSurface isn't QObject + if (auto window = qobject_cast(surface)) { + m_resizeConnections.push_back(connect(window, &QWindow::widthChanged, this, &ForwardRenderer::updateTextureSizes)); + m_resizeConnections.push_back(connect(window, &QWindow::heightChanged, this, &ForwardRenderer::updateTextureSizes)); + } else if (qobject_cast(surface)) { + m_resizeConnections.push_back(connect(m_surfaceSelector, &Qt3DRender::QRenderSurfaceSelector::externalRenderTargetSizeChanged, this, &ForwardRenderer::updateTextureSizes)); + } else { + qCWarning(kuesa) << Q_FUNC_INFO << "Unexpected surface type for surface " << surface; + } } + updateTextureSizes(); } @@ -620,9 +652,23 @@ void ForwardRenderer::reconfigureFrameGraph() // e.g We want Bloom to happen after DoF... // We may need to render the scene into a texture first ... + // check if we render into a separete RenderTarget or onto a surface + bool useRenderTarget = (m_renderTargetSelector->target() != nullptr); + if (useRenderTarget && getRenderTargetColorTexture() == nullptr) { + qCWarning(kuesa) << Q_FUNC_INFO << "RenderTarget is missing a Color0 attachment. Rendering onto surface instead."; + useRenderTarget = false; + } + m_techniqueFilter->setParent(this); - m_surfaceSelector->setParent(m_techniqueFilter); - m_viewport->setParent(m_surfaceSelector); + if (useRenderTarget) { + m_renderTargetSelector->setParent(m_techniqueFilter); + m_viewport->setParent(m_renderTargetSelector); + m_surfaceSelector->setParent(static_cast(nullptr)); + } else { + m_surfaceSelector->setParent(m_techniqueFilter); + m_viewport->setParent(m_surfaceSelector); + m_renderTargetSelector->setParent(static_cast(nullptr)); + } m_clearBuffers->setParent(m_viewport); m_noDrawClearBuffer->setParent(m_clearBuffers); m_cameraSelector->setParent(m_viewport); @@ -722,6 +768,9 @@ void ForwardRenderer::reconfigureFrameGraph() const bool blocked = blockNotifications(true); emit frameGraphTreeReconfigured(); blockNotifications(blocked); + + // Always Reconfigure Stages after settup up a new frame-graph + reconfigureStages(); } void ForwardRenderer::reconfigureStages() @@ -843,6 +892,12 @@ Qt3DRender::QAbstractTexture *ForwardRenderer::findRenderTargetTexture(Qt3DRende return attachment == outputs.end() ? nullptr : (*attachment)->texture(); } +Qt3DRender::QAbstractTexture *ForwardRenderer::getRenderTargetColorTexture() const +{ + Qt3DRender::QRenderTarget *target = m_renderTargetSelector->target(); + return target ? findRenderTargetTexture(target, Qt3DRender::QRenderTargetOutput::Color0) : nullptr; +} + QVector ForwardRenderer::renderStages() const { return m_renderStages; @@ -856,14 +911,19 @@ QVector ForwardRenderer::renderStages() const QSize ForwardRenderer::currentSurfaceSize() const { QSize size; - auto surface = m_surfaceSelector->surface(); + QObject *surface = m_surfaceSelector->surface(); + Qt3DRender::QAbstractTexture *renderTargetTexture = getRenderTargetColorTexture(); - if (auto window = qobject_cast(surface)) - size = window->size(); - else if (qobject_cast(surface)) - size = m_surfaceSelector->externalRenderTargetSize(); - else - qCWarning(kuesa) << Q_FUNC_INFO << "Unexpected surface type for surface " << surface; + if (renderTargetTexture) { + size = QSize(renderTargetTexture->width(), renderTargetTexture->height()); + } else { + if (auto window = qobject_cast(surface)) + size = window->size(); + else if (qobject_cast(surface)) + size = m_surfaceSelector->externalRenderTargetSize(); + else + qCWarning(kuesa) << Q_FUNC_INFO << "Unexpected surface type for surface " << surface; + } return size; } @@ -885,6 +945,15 @@ void ForwardRenderer::setRenderSurface(QObject *renderSurface) m_surfaceSelector->setSurface(renderSurface); } +/*! + * Sets the render target that the scene will be rendered into. If set to NULL, + * the scene will be rendered into a surface set by setRenderSurface + */ +void ForwardRenderer::setRenderTarget(Qt3DRender::QRenderTarget *renderTarget) +{ + m_renderTargetSelector->setTarget(renderTarget); +} + /*! * Sets the dimensions of the viewport where rendering will occur. Dimensions are in * normalized coordinates. diff --git a/src/core/framegraphes/forwardrenderer.h b/src/core/framegraphes/forwardrenderer.h index 27e64b41f..3b71d6f49 100644 --- a/src/core/framegraphes/forwardrenderer.h +++ b/src/core/framegraphes/forwardrenderer.h @@ -47,6 +47,7 @@ class QFrustumCulling; class QNoDraw; class QSortPolicy; class QRenderTarget; +class QRenderTargetSelector; } // namespace Qt3DRender namespace Kuesa { @@ -58,6 +59,7 @@ class KUESASHARED_EXPORT ForwardRenderer : public Qt3DRender::QFrameGraphNode { Q_OBJECT Q_PROPERTY(QObject *renderSurface READ renderSurface WRITE setRenderSurface NOTIFY renderSurfaceChanged) + Q_PROPERTY(Qt3DRender::QRenderTarget *renderTarget READ renderTarget WRITE setRenderTarget NOTIFY renderTargetChanged) Q_PROPERTY(QSize externalRenderTargetSize READ externalRenderTargetSize WRITE setExternalRenderTargetSize NOTIFY externalRenderTargetSizeChanged) Q_PROPERTY(QRectF viewportRect READ viewportRect WRITE setViewportRect NOTIFY viewportRectChanged) Q_PROPERTY(Qt3DCore::QEntity *camera READ camera WRITE setCamera NOTIFY cameraChanged) @@ -72,6 +74,7 @@ class KUESASHARED_EXPORT ForwardRenderer : public Qt3DRender::QFrameGraphNode ~ForwardRenderer(); QObject *renderSurface() const; + Qt3DRender::QRenderTarget *renderTarget() const; QSize externalRenderTargetSize() const; QRectF viewportRect() const; Qt3DCore::QEntity *camera() const; @@ -91,6 +94,7 @@ class KUESASHARED_EXPORT ForwardRenderer : public Qt3DRender::QFrameGraphNode public Q_SLOTS: void setRenderSurface(QObject *renderSurface); + void setRenderTarget(Qt3DRender::QRenderTarget *renderTarget); void setExternalRenderTargetSize(const QSize &externalRenderTargetSize); void setViewportRect(const QRectF &viewportRect); void setCamera(Qt3DCore::QEntity *camera); @@ -102,6 +106,7 @@ public Q_SLOTS: Q_SIGNALS: void renderSurfaceChanged(QObject *renderSurface); + void renderTargetChanged(Qt3DRender::QRenderTarget *renderTarget); void externalRenderTargetSizeChanged(const QSize &externalRenderTargetSize); void viewportRectChanged(const QRectF &viewportRect); void cameraChanged(Qt3DCore::QEntity *camera); @@ -112,20 +117,24 @@ public Q_SLOTS: void zFillingChanged(bool zFilling); void frameGraphTreeReconfigured(); +private Q_SLOTS: + void reconfigureFrameGraph(); + private: void updateTextureSizes(); void handleSurfaceChange(); QSize currentSurfaceSize() const; - void reconfigureFrameGraph(); void reconfigureStages(); Qt3DRender::QRenderTarget *createRenderTarget(bool includeDepth); AbstractPostProcessingEffect::FrameGraphNodePtr frameGraphSubtreeForPostProcessingEffect(AbstractPostProcessingEffect *effect) const; + Qt3DRender::QAbstractTexture *getRenderTargetColorTexture() const; Qt3DRender::QTechniqueFilter *m_techniqueFilter; Qt3DRender::QViewport *m_viewport; Qt3DRender::QCameraSelector *m_cameraSelector; Qt3DRender::QClearBuffers *m_clearBuffers; Qt3DRender::QRenderSurfaceSelector *m_surfaceSelector; + Qt3DRender::QRenderTargetSelector *m_renderTargetSelector; Qt3DRender::QNoDraw *m_noDrawClearBuffer; Qt3DRender::QFrustumCulling *m_frustumCulling; bool m_backToFrontSorting;