QGIS API Documentation 4.1.0-Master (9af12b5a203)
Loading...
Searching...
No Matches
qgsbloomrenderview.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsbloomrenderview.cpp
3 --------------------------------------
4 Date : May 2026
5 Copyright : (C) 2026 by Nyall Dawson
6 Email : nyall dot dawson at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16#include "qgsbloomrenderview.h"
17
20#include "qgsrenderpassquad.h"
21
22#include <QString>
23#include <Qt3DRender/QBlendEquation>
24#include <Qt3DRender/QBlendEquationArguments>
25#include <Qt3DRender/QClearBuffers>
26#include <Qt3DRender/QDepthTest>
27#include <Qt3DRender/QFrameGraphNode>
28#include <Qt3DRender/QLayer>
29#include <Qt3DRender/QLayerFilter>
30#include <Qt3DRender/QParameter>
31#include <Qt3DRender/QRenderStateSet>
32#include <Qt3DRender/QRenderTarget>
33#include <Qt3DRender/QRenderTargetOutput>
34#include <Qt3DRender/QRenderTargetSelector>
35#include <Qt3DRender/QTexture>
36#include <Qt3DRender/qsubtreeenabler.h>
37
38using namespace Qt::StringLiterals;
39
40QgsBloomRenderView::QgsBloomRenderView( const QString &viewName, Qt3DRender::QTexture2D *sourceColorTexture, const QSize &size, Qt3DCore::QEntity *rootEntity )
41 : QgsAbstractRenderView( viewName )
42 , mBaseSize( size )
43{
44 mFilterRadiusParameter = new Qt3DRender::QParameter( u"filterRadius"_s, 0.005f, rootEntity );
45
46 const float aspectRatio = static_cast<float>( size.width() ) / static_cast<float>( size.height() );
47 mAspectRatioParameter = new Qt3DRender::QParameter( u"aspectRatio"_s, aspectRatio, rootEntity );
48
49 // bloom is disabled by default
51 buildRenderPasses( sourceColorTexture, rootEntity );
52}
53
55
56Qt3DRender::QTexture2D *QgsBloomRenderView::bloomTexture() const
57{
58 return mTextures[0];
59}
60
62{
63 mFilterRadiusParameter->setValue( radius );
64}
65
67{
68 mAspectRatioParameter->setValue( ratio );
69}
70
71void QgsBloomRenderView::buildRenderPasses( Qt3DRender::QTexture2D *sourceTexture, Qt3DCore::QEntity *rootEntity )
72{
73 Qt3DRender::QTexture2D *currentInputTexture = sourceTexture;
74
75 // following CoD: Advanced Warfare approach, from ACM Siggraph 2014
76 // see also https://learnopengl.com/Guest-Articles/2022/Phys.-Based-Bloom by Jorge Jimenez
77 // comments from Jorge's post inline below
78
79 mTextures.reserve( MIP_PASSES );
80
81 Qt3DRender::QRenderStateSet *renderStateSet = new Qt3DRender::QRenderStateSet( mRendererEnabler );
82
83 // downsample
84 for ( int i = 0; i < MIP_PASSES; ++i )
85 {
86 auto passLayer = new Qt3DRender::QLayer( rootEntity );
87 passLayer->setRecursive( true );
88 passLayer->setObjectName( mViewName + u"::Layer(DownsamplePass%1)"_s.arg( i + 1 ) );
89
90 auto renderTarget = new Qt3DRender::QRenderTarget();
91
92 auto colorOutput = new Qt3DRender::QRenderTargetOutput( renderTarget );
93 colorOutput->setAttachmentPoint( Qt3DRender::QRenderTargetOutput::Color0 );
94
95 auto mipTexture = new Qt3DRender::QTexture2D( colorOutput );
96 // "we are downscaling an HDR color buffer, so we need a float texture format" (Jorge Jimenez)
97 mipTexture->setFormat( Qt3DRender::QAbstractTexture::RGBA16F );
98 // minimize VRAM during build -- if the effect is disabled, we don't want to waste resources
99 mipTexture->setSize( 1, 1 );
100 mipTexture->setGenerateMipMaps( false );
101 // "we must enable linear filtering and edge-clamping for all mips" (Jorge Jimenez)
102 mipTexture->setMinificationFilter( Qt3DRender::QTexture2D::Linear );
103 mipTexture->setMagnificationFilter( Qt3DRender::QTexture2D::Linear );
104 mipTexture->wrapMode()->setX( Qt3DRender::QTextureWrapMode::ClampToEdge );
105 mipTexture->wrapMode()->setY( Qt3DRender::QTextureWrapMode::ClampToEdge );
106 mTextures.push_back( mipTexture );
107
108 colorOutput->setTexture( mipTexture );
109 renderTarget->addOutput( colorOutput );
110
111 auto targetSelector = new Qt3DRender::QRenderTargetSelector( renderStateSet );
112 targetSelector->setTarget( renderTarget );
113
114 auto clearBuffers = new Qt3DRender::QClearBuffers( targetSelector );
115 clearBuffers->setBuffers( Qt3DRender::QClearBuffers::ColorBuffer );
116 clearBuffers->setClearColor( QColor::fromRgbF( 0.0, 0.0, 0.0, 1.0 ) );
117
118 auto layerFilter = new Qt3DRender::QLayerFilter( clearBuffers );
119 layerFilter->addLayer( passLayer );
120
121 // owned by rootEntity
122 ( void ) new QgsBloomDownsampleEntity( currentInputTexture, passLayer, rootEntity );
123
124 currentInputTexture = mipTexture;
125 }
126
127 // upsample
128 for ( int i = MIP_PASSES - 2; i >= 0; --i )
129 {
130 auto passLayer = new Qt3DRender::QLayer( rootEntity );
131 passLayer->setRecursive( true );
132 passLayer->setObjectName( mViewName + u"::Layer(UpsamplePass%1)"_s.arg( i + 1 ) );
133
134 Qt3DRender::QRenderTarget *renderTarget = new Qt3DRender::QRenderTarget();
135
136 Qt3DRender::QRenderTargetOutput *colorOutput = new Qt3DRender::QRenderTargetOutput( renderTarget );
137 colorOutput->setAttachmentPoint( Qt3DRender::QRenderTargetOutput::Color0 );
138
139 Qt3DRender::QTexture2D *targetTexture = mTextures[i];
140 colorOutput->setTexture( targetTexture );
141 renderTarget->addOutput( colorOutput );
142
143 auto targetSelector = new Qt3DRender::QRenderTargetSelector( renderStateSet );
144 targetSelector->setTarget( renderTarget );
145
146 // upsample is additive
147 auto blendStateSet = new Qt3DRender::QRenderStateSet( targetSelector );
148
149 auto blendEquation = new Qt3DRender::QBlendEquation( blendStateSet );
150 blendEquation->setBlendFunction( Qt3DRender::QBlendEquation::Add );
151 blendStateSet->addRenderState( blendEquation );
152
153 auto blendEquationArgs = new Qt3DRender::QBlendEquationArguments( blendStateSet );
154 blendEquationArgs->setSourceRgb( Qt3DRender::QBlendEquationArguments::Blending::One );
155 blendEquationArgs->setDestinationRgb( Qt3DRender::QBlendEquationArguments::Blending::One );
156 blendStateSet->addRenderState( blendEquationArgs );
157
158 // owned by rootEntity
159 auto quad = new QgsBloomUpsampleEntity( currentInputTexture, passLayer, rootEntity );
160 quad->addParameters( { mFilterRadiusParameter, mAspectRatioParameter } );
161
162 auto layerFilter = new Qt3DRender::QLayerFilter( blendStateSet );
163 layerFilter->addLayer( passLayer );
164
165 currentInputTexture = targetTexture;
166 }
167}
168
169void QgsBloomRenderView::updateWindowResize( int width, int height )
170{
171 mBaseSize = QSize( width, height );
172
173 const bool enabled = isEnabled();
174
175 int currentWidth = width;
176 int currentHeight = height;
177 for ( int i = 0; i < MIP_PASSES; ++i )
178 {
179 // "If you go too small, make sure that you stop when you reach 1x1 in mip size" (Jorge Jimenez)
180 currentWidth = std::max( 1, currentWidth / 2 );
181 currentHeight = std::max( 1, currentHeight / 2 );
182 if ( enabled )
183 {
184 mTextures[i]->setSize( currentWidth, currentHeight );
185 }
186 else
187 {
188 // minimize VRAM when disabled
189 mTextures[i]->setSize( 1, 1 );
190 }
191 }
192
193 const float aspectRatio = static_cast<float>( width ) / static_cast<float>( height );
194 mAspectRatioParameter->setValue( aspectRatio );
195}
196
198{
200 updateWindowResize( mBaseSize.width(), mBaseSize.height() );
201}
Qt3DRender::QSubtreeEnabler * mRendererEnabler
virtual void setEnabled(bool enable)
Enable or disable via enable the render view sub tree.
virtual bool isEnabled() const
Returns true if render view is enabled.
QgsAbstractRenderView(const QString &viewName)
Constructor for QgsAbstractRenderView with the specified parent object.
An entity responsible for applying a 13-tap downsample filter for physically based bloom.
~QgsBloomRenderView() override
QgsBloomRenderView(const QString &viewName, Qt3DRender::QTexture2D *sourceColorTexture, const QSize &size, Qt3DCore::QEntity *rootSceneEntity)
Default constructor.
void updateWindowResize(int width, int height) override
Called when 3D window is resized.
void setFilterRadius(float radius)
Sets the bloom filter radius.
Qt3DRender::QTexture2D * bloomTexture() const
Returns the texture containing the final bloom effect.
void setAspectRatio(float ratio)
Sets the aspect ratio of the view.
void setEnabled(bool enabled) override
Enable or disable via enable the render view sub tree.