QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsshadowrenderingframegraph.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsshadowrenderingframegraph.cpp
3  --------------------------------------
4  Date : August 2020
5  Copyright : (C) 2020 by Belgacem Nedjima
6  Email : gb underscore nedjima at esi dot dz
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 
17 
19 #include "qgscameracontroller.h"
20 #include "qgsrectangle.h"
22 #include "qgspreviewquad.h"
23 #include "qgs3dutils.h"
24 
25 #include <Qt3DRender/QAttribute>
26 #include <Qt3DRender/QBuffer>
27 #include <Qt3DRender/QTechnique>
28 #include <Qt3DRender/QGraphicsApiFilter>
29 #include <Qt3DRender/QBlendEquation>
30 #include <Qt3DRender/QSortPolicy>
31 #include <Qt3DRender/QNoDepthMask>
32 #include <Qt3DRender/QBlendEquationArguments>
33 
34 Qt3DRender::QFrameGraphNode *QgsShadowRenderingFrameGraph::constructTexturesPreviewPass()
35 {
36  mPreviewLayerFilter = new Qt3DRender::QLayerFilter;
37  mPreviewLayerFilter->addLayer( mPreviewLayer );
38 
39  mPreviewRenderStateSet = new Qt3DRender::QRenderStateSet( mPreviewLayerFilter );
40  mPreviewDepthTest = new Qt3DRender::QDepthTest;
41  mPreviewDepthTest->setDepthFunction( Qt3DRender::QDepthTest::Always );
42  mPreviewRenderStateSet->addRenderState( mPreviewDepthTest );
43  mPreviewCullFace = new Qt3DRender::QCullFace;
44  mPreviewCullFace->setMode( Qt3DRender::QCullFace::NoCulling );
45  mPreviewRenderStateSet->addRenderState( mPreviewCullFace );
46 
47  return mPreviewLayerFilter;
48 }
49 
50 Qt3DRender::QFrameGraphNode *QgsShadowRenderingFrameGraph::constructForwardRenderPass()
51 {
52  // The branch structure:
53  // mMainCameraSelector
54  // mForwardRenderLayerFilter
55  // mForwardRenderTargetSelector
56  // opaqueObjectsFilter | transparentObjectsLayerFilter
57  // forwaredRenderStateSet | sortPolicy
58  // mFrustumCulling | transparentObjectsRenderStateSet
59  // mForwardClearBuffers |
60  // mDebugOverlay |
61  mMainCameraSelector = new Qt3DRender::QCameraSelector;
62  mMainCameraSelector->setCamera( mMainCamera );
63 
64  mForwardRenderLayerFilter = new Qt3DRender::QLayerFilter( mMainCameraSelector );
65  mForwardRenderLayerFilter->addLayer( mForwardRenderLayer );
66 
67  mForwardColorTexture = new Qt3DRender::QTexture2D;
68  mForwardColorTexture->setWidth( mSize.width() );
69  mForwardColorTexture->setHeight( mSize.height() );
70  mForwardColorTexture->setFormat( Qt3DRender::QAbstractTexture::RGB8_UNorm );
71  mForwardColorTexture->setGenerateMipMaps( false );
72  mForwardColorTexture->setMagnificationFilter( Qt3DRender::QTexture2D::Linear );
73  mForwardColorTexture->setMinificationFilter( Qt3DRender::QTexture2D::Linear );
74  mForwardColorTexture->wrapMode()->setX( Qt3DRender::QTextureWrapMode::ClampToEdge );
75  mForwardColorTexture->wrapMode()->setY( Qt3DRender::QTextureWrapMode::ClampToEdge );
76 
77  mForwardDepthTexture = new Qt3DRender::QTexture2D;
78  mForwardDepthTexture->setWidth( mSize.width() );
79  mForwardDepthTexture->setHeight( mSize.height() );
80  mForwardDepthTexture->setFormat( Qt3DRender::QTexture2D::TextureFormat::DepthFormat );
81  mForwardDepthTexture->setGenerateMipMaps( false );
82  mForwardDepthTexture->setMagnificationFilter( Qt3DRender::QTexture2D::Linear );
83  mForwardDepthTexture->setMinificationFilter( Qt3DRender::QTexture2D::Linear );
84  mForwardDepthTexture->wrapMode()->setX( Qt3DRender::QTextureWrapMode::ClampToEdge );
85  mForwardDepthTexture->wrapMode()->setY( Qt3DRender::QTextureWrapMode::ClampToEdge );
86 
87  Qt3DRender::QRenderTarget *forwardRenderTarget = new Qt3DRender::QRenderTarget;
88  Qt3DRender::QRenderTargetOutput *forwardRenderTargetDepthOutput = new Qt3DRender::QRenderTargetOutput;
89  forwardRenderTargetDepthOutput->setAttachmentPoint( Qt3DRender::QRenderTargetOutput::Depth );
90  forwardRenderTargetDepthOutput->setTexture( mForwardDepthTexture );
91  forwardRenderTarget->addOutput( forwardRenderTargetDepthOutput );
92  Qt3DRender::QRenderTargetOutput *forwardRenderTargetColorOutput = new Qt3DRender::QRenderTargetOutput;
93  forwardRenderTargetColorOutput->setAttachmentPoint( Qt3DRender::QRenderTargetOutput::Color0 );
94  forwardRenderTargetColorOutput->setTexture( mForwardColorTexture );
95  forwardRenderTarget->addOutput( forwardRenderTargetColorOutput );
96 
97  mForwardRenderTargetSelector = new Qt3DRender::QRenderTargetSelector( mForwardRenderLayerFilter );
98  mForwardRenderTargetSelector->setTarget( forwardRenderTarget );
99 
100  Qt3DRender::QLayerFilter *opaqueObjectsFilter = new Qt3DRender::QLayerFilter( mForwardRenderTargetSelector );
101  opaqueObjectsFilter->addLayer( mTransparentObjectsPassLayer );
102  opaqueObjectsFilter->setFilterMode( Qt3DRender::QLayerFilter::DiscardAnyMatchingLayers );
103 
104  Qt3DRender::QRenderStateSet *forwaredRenderStateSet = new Qt3DRender::QRenderStateSet( opaqueObjectsFilter );
105 
106  Qt3DRender::QDepthTest *depthTest = new Qt3DRender::QDepthTest;
107  depthTest->setDepthFunction( Qt3DRender::QDepthTest::Less );
108  forwaredRenderStateSet->addRenderState( depthTest );
109 
110  Qt3DRender::QCullFace *cullFace = new Qt3DRender::QCullFace;
111  cullFace->setMode( Qt3DRender::QCullFace::CullingMode::Back );
112  forwaredRenderStateSet->addRenderState( cullFace );
113 
114  mFrustumCulling = new Qt3DRender::QFrustumCulling( forwaredRenderStateSet );
115 
116  mForwardClearBuffers = new Qt3DRender::QClearBuffers( mFrustumCulling );
117  mForwardClearBuffers->setClearColor( QColor::fromRgbF( 0.0, 0.0, 1.0, 1.0 ) );
118  mForwardClearBuffers->setBuffers( Qt3DRender::QClearBuffers::ColorDepthBuffer );
119  mForwardClearBuffers->setClearDepthValue( 1.0f );
120 
121  Qt3DRender::QLayerFilter *transparentObjectsLayerFilter = new Qt3DRender::QLayerFilter( mForwardRenderTargetSelector );
122  transparentObjectsLayerFilter->addLayer( mTransparentObjectsPassLayer );
123  transparentObjectsLayerFilter->setFilterMode( Qt3DRender::QLayerFilter::AcceptAnyMatchingLayers );
124 
125  Qt3DRender::QSortPolicy *sortPolicy = new Qt3DRender::QSortPolicy( transparentObjectsLayerFilter );
126  QVector<Qt3DRender::QSortPolicy::SortType> sortTypes;
127  sortTypes.push_back( Qt3DRender::QSortPolicy::BackToFront );
128  sortPolicy->setSortTypes( sortTypes );
129 
130  Qt3DRender::QRenderStateSet *transparentObjectsRenderStateSet = new Qt3DRender::QRenderStateSet( sortPolicy );
131  {
132  Qt3DRender::QDepthTest *depthTest = new Qt3DRender::QDepthTest;
133  depthTest->setDepthFunction( Qt3DRender::QDepthTest::Less );
134  transparentObjectsRenderStateSet->addRenderState( depthTest );
135 
136  Qt3DRender::QNoDepthMask *noDepthMask = new Qt3DRender::QNoDepthMask;
137  transparentObjectsRenderStateSet->addRenderState( noDepthMask );
138 
139  Qt3DRender::QCullFace *cullFace = new Qt3DRender::QCullFace;
140  cullFace->setMode( Qt3DRender::QCullFace::CullingMode::NoCulling );
141  transparentObjectsRenderStateSet->addRenderState( cullFace );
142 
143  Qt3DRender::QBlendEquation *blendEquation = new Qt3DRender::QBlendEquation;
144  blendEquation->setBlendFunction( Qt3DRender::QBlendEquation::Add );
145  transparentObjectsRenderStateSet->addRenderState( blendEquation );
146 
147  Qt3DRender::QBlendEquationArguments *blenEquationArgs = new Qt3DRender::QBlendEquationArguments;
148  blenEquationArgs->setSourceRgb( Qt3DRender::QBlendEquationArguments::Blending::One );
149  blenEquationArgs->setDestinationRgb( Qt3DRender::QBlendEquationArguments::Blending::OneMinusSource1Alpha );
150  blenEquationArgs->setSourceAlpha( Qt3DRender::QBlendEquationArguments::Blending::One );
151  blenEquationArgs->setDestinationAlpha( Qt3DRender::QBlendEquationArguments::Blending::OneMinusSource1Alpha );
152  transparentObjectsRenderStateSet->addRenderState( blenEquationArgs );
153  }
154 
155 #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
156  mDebugOverlay = new Qt3DRender::QDebugOverlay( mForwardClearBuffers );
157  mDebugOverlay->setEnabled( false );
158 #endif
159 
160  // cppcheck wrongly believes transparentObjectsRenderStateSet will leak
161  // cppcheck-suppress memleak
162  return mMainCameraSelector;
163 }
164 
165 Qt3DRender::QFrameGraphNode *QgsShadowRenderingFrameGraph::constructShadowRenderPass()
166 {
167  mLightCameraSelectorShadowPass = new Qt3DRender::QCameraSelector;
168  mLightCameraSelectorShadowPass->setCamera( mLightCamera );
169 
170  mShadowSceneEntitiesFilter = new Qt3DRender::QLayerFilter( mLightCameraSelectorShadowPass );
171  mShadowSceneEntitiesFilter->addLayer( mCastShadowsLayer );
172 
173  mShadowMapTexture = new Qt3DRender::QTexture2D;
174  mShadowMapTexture->setWidth( mShadowMapResolution );
175  mShadowMapTexture->setHeight( mShadowMapResolution );
176  mShadowMapTexture->setFormat( Qt3DRender::QTexture2D::TextureFormat::DepthFormat );
177  mShadowMapTexture->setGenerateMipMaps( false );
178  mShadowMapTexture->setMagnificationFilter( Qt3DRender::QTexture2D::Linear );
179  mShadowMapTexture->setMinificationFilter( Qt3DRender::QTexture2D::Linear );
180  mShadowMapTexture->wrapMode()->setX( Qt3DRender::QTextureWrapMode::ClampToEdge );
181  mShadowMapTexture->wrapMode()->setY( Qt3DRender::QTextureWrapMode::ClampToEdge );
182 
183  Qt3DRender::QRenderTarget *shadowRenderTarget = new Qt3DRender::QRenderTarget;
184  Qt3DRender::QRenderTargetOutput *shadowRenderTargetOutput = new Qt3DRender::QRenderTargetOutput;
185  shadowRenderTargetOutput->setAttachmentPoint( Qt3DRender::QRenderTargetOutput::Depth );
186  shadowRenderTargetOutput->setTexture( mShadowMapTexture );
187  shadowRenderTarget->addOutput( shadowRenderTargetOutput );
188 
189  mShadowRenderTargetSelector = new Qt3DRender::QRenderTargetSelector( mShadowSceneEntitiesFilter );
190  mShadowRenderTargetSelector->setTarget( shadowRenderTarget );
191 
192  mShadowClearBuffers = new Qt3DRender::QClearBuffers( mShadowRenderTargetSelector );
193  mShadowClearBuffers->setBuffers( Qt3DRender::QClearBuffers::BufferType::ColorDepthBuffer );
194  mShadowClearBuffers->setClearColor( QColor::fromRgbF( 0.0f, 1.0f, 0.0f ) );
195 
196  mShadowRenderStateSet = new Qt3DRender::QRenderStateSet( mShadowClearBuffers );
197 
198  Qt3DRender::QDepthTest *shadowDepthTest = new Qt3DRender::QDepthTest;
199  shadowDepthTest->setDepthFunction( Qt3DRender::QDepthTest::Less );
200  mShadowRenderStateSet->addRenderState( shadowDepthTest );
201 
202  Qt3DRender::QCullFace *shadowCullFace = new Qt3DRender::QCullFace;
203  shadowCullFace->setMode( Qt3DRender::QCullFace::CullingMode::Front );
204  mShadowRenderStateSet->addRenderState( shadowCullFace );
205 
206  Qt3DRender::QPolygonOffset *polygonOffset = new Qt3DRender::QPolygonOffset;
207  polygonOffset->setDepthSteps( 4.0 );
208  polygonOffset->setScaleFactor( 1.1 );
209  mShadowRenderStateSet->addRenderState( polygonOffset );
210 
211  return mLightCameraSelectorShadowPass;
212 }
213 
214 Qt3DRender::QFrameGraphNode *QgsShadowRenderingFrameGraph::constructPostprocessingPass()
215 {
216  mPostProcessingCameraSelector = new Qt3DRender::QCameraSelector;
217  mPostProcessingCameraSelector->setCamera( mLightCamera );
218 
219  mPostprocessPassLayerFilter = new Qt3DRender::QLayerFilter( mPostProcessingCameraSelector );
220  mPostprocessPassLayerFilter->addLayer( mPostprocessPassLayer );
221 
222  mPostprocessClearBuffers = new Qt3DRender::QClearBuffers( mPostprocessPassLayerFilter );
223 
224  mRenderCaptureTargetSelector = new Qt3DRender::QRenderTargetSelector( mPostprocessClearBuffers );
225 
226  Qt3DRender::QRenderTarget *renderTarget = new Qt3DRender::QRenderTarget( mRenderCaptureTargetSelector );
227 
228  // The lifetime of the objects created here is managed
229  // automatically, as they become children of this object.
230 
231  // Create a render target output for rendering color.
232  Qt3DRender::QRenderTargetOutput *colorOutput = new Qt3DRender::QRenderTargetOutput( renderTarget );
233  colorOutput->setAttachmentPoint( Qt3DRender::QRenderTargetOutput::Color0 );
234 
235  // Create a texture to render into.
236  mRenderCaptureColorTexture = new Qt3DRender::QTexture2D( colorOutput );
237  mRenderCaptureColorTexture->setSize( mSize.width(), mSize.height() );
238  mRenderCaptureColorTexture->setFormat( Qt3DRender::QAbstractTexture::RGB8_UNorm );
239  mRenderCaptureColorTexture->setMinificationFilter( Qt3DRender::QAbstractTexture::Linear );
240  mRenderCaptureColorTexture->setMagnificationFilter( Qt3DRender::QAbstractTexture::Linear );
241 
242  // Hook the texture up to our output, and the output up to this object.
243  colorOutput->setTexture( mRenderCaptureColorTexture );
244  renderTarget->addOutput( colorOutput );
245 
246  Qt3DRender::QRenderTargetOutput *depthOutput = new Qt3DRender::QRenderTargetOutput( renderTarget );
247 
248  depthOutput->setAttachmentPoint( Qt3DRender::QRenderTargetOutput::Depth );
249  mRenderCaptureDepthTexture = new Qt3DRender::QTexture2D( depthOutput );
250  mRenderCaptureDepthTexture->setSize( mSize.width(), mSize.height() );
251  mRenderCaptureDepthTexture->setFormat( Qt3DRender::QAbstractTexture::DepthFormat );
252  mRenderCaptureDepthTexture->setMinificationFilter( Qt3DRender::QAbstractTexture::Linear );
253  mRenderCaptureDepthTexture->setMagnificationFilter( Qt3DRender::QAbstractTexture::Linear );
254  mRenderCaptureDepthTexture->setComparisonFunction( Qt3DRender::QAbstractTexture::CompareLessEqual );
255  mRenderCaptureDepthTexture->setComparisonMode( Qt3DRender::QAbstractTexture::CompareRefToTexture );
256 
257  depthOutput->setTexture( mRenderCaptureDepthTexture );
258  renderTarget->addOutput( depthOutput );
259 
260  mRenderCaptureTargetSelector->setTarget( renderTarget );
261 
262  mRenderCapture = new Qt3DRender::QRenderCapture( mRenderCaptureTargetSelector );
263 
264  return mPostProcessingCameraSelector;
265 }
266 
267 Qt3DRender::QFrameGraphNode *QgsShadowRenderingFrameGraph::constructDepthRenderPass()
268 {
269  // depth buffer render to copy pass
270 
271  mDepthRenderCameraSelector = new Qt3DRender::QCameraSelector;
272  mDepthRenderCameraSelector->setCamera( mMainCamera );
273 
274  mDepthRenderStateSet = new Qt3DRender::QRenderStateSet( mDepthRenderCameraSelector );
275 
276  Qt3DRender::QDepthTest *depthRenderDepthTest = new Qt3DRender::QDepthTest;
277  depthRenderDepthTest->setDepthFunction( Qt3DRender::QDepthTest::Always );;
278  Qt3DRender::QCullFace *depthRenderCullFace = new Qt3DRender::QCullFace;
279  depthRenderCullFace->setMode( Qt3DRender::QCullFace::NoCulling );
280 
281  mDepthRenderStateSet->addRenderState( depthRenderDepthTest );
282  mDepthRenderStateSet->addRenderState( depthRenderCullFace );
283 
284  mDepthRenderLayerFilter = new Qt3DRender::QLayerFilter( mDepthRenderStateSet );
285  mDepthRenderLayerFilter->addLayer( mDepthRenderPassLayer );
286 
287  mDepthRenderCaptureTargetSelector = new Qt3DRender::QRenderTargetSelector( mDepthRenderLayerFilter );
288  Qt3DRender::QRenderTarget *depthRenderTarget = new Qt3DRender::QRenderTarget( mDepthRenderCaptureTargetSelector );
289 
290  // The lifetime of the objects created here is managed
291  // automatically, as they become children of this object.
292 
293  // Create a render target output for rendering color.
294  Qt3DRender::QRenderTargetOutput *colorOutput = new Qt3DRender::QRenderTargetOutput( depthRenderTarget );
295  colorOutput->setAttachmentPoint( Qt3DRender::QRenderTargetOutput::Color0 );
296 
297  // Create a texture to render into.
298  mDepthRenderCaptureColorTexture = new Qt3DRender::QTexture2D( colorOutput );
299  mDepthRenderCaptureColorTexture->setSize( mSize.width(), mSize.height() );
300  mDepthRenderCaptureColorTexture->setFormat( Qt3DRender::QAbstractTexture::RGB8_UNorm );
301  mDepthRenderCaptureColorTexture->setMinificationFilter( Qt3DRender::QAbstractTexture::Linear );
302  mDepthRenderCaptureColorTexture->setMagnificationFilter( Qt3DRender::QAbstractTexture::Linear );
303 
304  // Hook the texture up to our output, and the output up to this object.
305  colorOutput->setTexture( mDepthRenderCaptureColorTexture );
306  depthRenderTarget->addOutput( colorOutput );
307 
308  Qt3DRender::QRenderTargetOutput *depthOutput = new Qt3DRender::QRenderTargetOutput( depthRenderTarget );
309 
310  depthOutput->setAttachmentPoint( Qt3DRender::QRenderTargetOutput::Depth );
311  mDepthRenderCaptureDepthTexture = new Qt3DRender::QTexture2D( depthOutput );
312  mDepthRenderCaptureDepthTexture->setSize( mSize.width(), mSize.height() );
313  mDepthRenderCaptureDepthTexture->setFormat( Qt3DRender::QAbstractTexture::DepthFormat );
314  mDepthRenderCaptureDepthTexture->setMinificationFilter( Qt3DRender::QAbstractTexture::Linear );
315  mDepthRenderCaptureDepthTexture->setMagnificationFilter( Qt3DRender::QAbstractTexture::Linear );
316  mDepthRenderCaptureDepthTexture->setComparisonFunction( Qt3DRender::QAbstractTexture::CompareLessEqual );
317  mDepthRenderCaptureDepthTexture->setComparisonMode( Qt3DRender::QAbstractTexture::CompareRefToTexture );
318 
319  depthOutput->setTexture( mDepthRenderCaptureDepthTexture );
320  depthRenderTarget->addOutput( depthOutput );
321 
322  mDepthRenderCaptureTargetSelector->setTarget( depthRenderTarget );
323 
324  // Note: We do not a clear buffers node since we are drawing a quad that will override the buffer's content anyway
325  mDepthRenderCapture = new Qt3DRender::QRenderCapture( mDepthRenderCaptureTargetSelector );
326 
327  return mDepthRenderCameraSelector;
328 }
329 
330 Qt3DCore::QEntity *QgsShadowRenderingFrameGraph::constructDepthRenderQuad()
331 {
332  Qt3DCore::QEntity *quad = new Qt3DCore::QEntity;
333  quad->setObjectName( "depthRenderQuad" );
334 
335  Qt3DRender::QGeometry *geom = new Qt3DRender::QGeometry;
336  Qt3DRender::QAttribute *positionAttribute = new Qt3DRender::QAttribute;
337  const QVector<float> vert = { -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
338 
339  const QByteArray vertexArr( ( const char * ) vert.constData(), vert.size() * sizeof( float ) );
340  Qt3DRender::QBuffer *vertexBuffer = nullptr;
341  vertexBuffer = new Qt3DRender::QBuffer( this );
342  vertexBuffer->setData( vertexArr );
343 
344  positionAttribute->setName( Qt3DRender::QAttribute::defaultPositionAttributeName() );
345  positionAttribute->setVertexBaseType( Qt3DRender::QAttribute::Float );
346  positionAttribute->setVertexSize( 3 );
347  positionAttribute->setAttributeType( Qt3DRender::QAttribute::VertexAttribute );
348  positionAttribute->setBuffer( vertexBuffer );
349  positionAttribute->setByteOffset( 0 );
350  positionAttribute->setByteStride( 3 * sizeof( float ) );
351  positionAttribute->setCount( 6 );
352 
353  geom->addAttribute( positionAttribute );
354 
355  Qt3DRender::QGeometryRenderer *renderer = new Qt3DRender::QGeometryRenderer;
356  renderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::PrimitiveType::Triangles );
357  renderer->setGeometry( geom );
358 
359  quad->addComponent( renderer );
360 
361  QMatrix4x4 modelMatrix;
362  modelMatrix.setToIdentity();
363 
364  // construct material
365 
366  Qt3DRender::QMaterial *material = new Qt3DRender::QMaterial;
367  Qt3DRender::QParameter *textureParameter = new Qt3DRender::QParameter( "depthTexture", mForwardDepthTexture );
368  Qt3DRender::QParameter *textureTransformParameter = new Qt3DRender::QParameter( "modelMatrix", QVariant::fromValue( modelMatrix ) );
369  material->addParameter( textureParameter );
370  material->addParameter( textureTransformParameter );
371 
372  Qt3DRender::QEffect *effect = new Qt3DRender::QEffect;
373 
374  Qt3DRender::QTechnique *technique = new Qt3DRender::QTechnique;
375 
376  Qt3DRender::QGraphicsApiFilter *graphicsApiFilter = technique->graphicsApiFilter();
377  graphicsApiFilter->setApi( Qt3DRender::QGraphicsApiFilter::Api::OpenGL );
378  graphicsApiFilter->setProfile( Qt3DRender::QGraphicsApiFilter::OpenGLProfile::CoreProfile );
379  graphicsApiFilter->setMajorVersion( 1 );
380  graphicsApiFilter->setMinorVersion( 5 );
381 
382  Qt3DRender::QRenderPass *renderPass = new Qt3DRender::QRenderPass;
383 
384  Qt3DRender::QShaderProgram *shader = new Qt3DRender::QShaderProgram;
385  shader->setVertexShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( "qrc:/shaders/depth_render.vert" ) ) );
386  shader->setFragmentShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( "qrc:/shaders/depth_render.frag" ) ) );
387  renderPass->setShaderProgram( shader );
388 
389  technique->addRenderPass( renderPass );
390 
391  effect->addTechnique( technique );
392  material->setEffect( effect );
393 
394  quad->addComponent( material );
395 
396  return quad;
397 }
398 
399 QgsShadowRenderingFrameGraph::QgsShadowRenderingFrameGraph( QSurface *surface, QSize s, Qt3DRender::QCamera *mainCamera, Qt3DCore::QEntity *root )
400  : Qt3DCore::QEntity( root )
401  , mSize( s )
402 {
403  mRootEntity = root;
404  mMainCamera = mainCamera;
405  mLightCamera = new Qt3DRender::QCamera;
406 
407  mPostprocessPassLayer = new Qt3DRender::QLayer;
408  mPreviewLayer = new Qt3DRender::QLayer;
409  mCastShadowsLayer = new Qt3DRender::QLayer;
410  mForwardRenderLayer = new Qt3DRender::QLayer;
411  mDepthRenderPassLayer = new Qt3DRender::QLayer;
412  mTransparentObjectsPassLayer = new Qt3DRender::QLayer;
413 
414  mPostprocessPassLayer->setRecursive( true );
415  mPreviewLayer->setRecursive( true );
416  mCastShadowsLayer->setRecursive( true );
417  mForwardRenderLayer->setRecursive( true );
418  mDepthRenderPassLayer->setRecursive( true );
419  mTransparentObjectsPassLayer->setRecursive( true );
420 
421  mRenderSurfaceSelector = new Qt3DRender::QRenderSurfaceSelector;
422 
423  QObject *surfaceObj = dynamic_cast< QObject * >( surface );
424  Q_ASSERT( surfaceObj );
425 
426  mRenderSurfaceSelector->setSurface( surfaceObj );
427  mRenderSurfaceSelector->setExternalRenderTargetSize( mSize );
428 
429  mMainViewPort = new Qt3DRender::QViewport( mRenderSurfaceSelector );
430  mMainViewPort->setNormalizedRect( QRectF( 0.0f, 0.0f, 1.0f, 1.0f ) );
431 
432  // Forward render
433  Qt3DRender::QFrameGraphNode *forwardRenderPass = constructForwardRenderPass();
434  forwardRenderPass->setParent( mMainViewPort );
435 
436  // shadow rendering pass
437 
438  Qt3DRender::QFrameGraphNode *shadowRenderPass = constructShadowRenderPass();
439  shadowRenderPass->setParent( mMainViewPort );
440 
441  // depth buffer processing
442  Qt3DRender::QFrameGraphNode *depthBufferProcessingPass = constructDepthRenderPass();
443  depthBufferProcessingPass->setParent( mMainViewPort );
444 
445  // post process
446  Qt3DRender::QFrameGraphNode *postprocessingPass = constructPostprocessingPass();
447  postprocessingPass->setParent( mMainViewPort );
448 
449  // textures preview pass
450  Qt3DRender::QFrameGraphNode *previewPass = constructTexturesPreviewPass();
451  previewPass->setParent( mMainViewPort );
452 
453  mPostprocessingEntity = new QgsPostprocessingEntity( this, mRootEntity );
454  mPostprocessingEntity->addComponent( mPostprocessPassLayer );
455 
456  Qt3DRender::QParameter *depthMapIsDepthParam = new Qt3DRender::QParameter( "isDepth", true );
457  Qt3DRender::QParameter *shadowMapIsDepthParam = new Qt3DRender::QParameter( "isDepth", true );
458 
459  mDebugDepthMapPreviewQuad = this->addTexturePreviewOverlay( mForwardDepthTexture, QPointF( 0.9f, 0.9f ), QSizeF( 0.1, 0.1 ), QVector<Qt3DRender::QParameter *> { depthMapIsDepthParam } );
460  mDebugShadowMapPreviewQuad = this->addTexturePreviewOverlay( mShadowMapTexture, QPointF( 0.9f, 0.9f ), QSizeF( 0.1, 0.1 ), QVector<Qt3DRender::QParameter *> { shadowMapIsDepthParam } );
461  mDebugDepthMapPreviewQuad->setEnabled( false );
462  mDebugShadowMapPreviewQuad->setEnabled( false );
463 
464  mDepthRenderQuad = constructDepthRenderQuad();
465  mDepthRenderQuad->addComponent( mDepthRenderPassLayer );
466  mDepthRenderQuad->setParent( mRootEntity );
467 }
468 
469 QgsPreviewQuad *QgsShadowRenderingFrameGraph::addTexturePreviewOverlay( Qt3DRender::QTexture2D *texture, const QPointF &centerTexCoords, const QSizeF &sizeTexCoords, QVector<Qt3DRender::QParameter *> additionalShaderParameters )
470 {
471  QgsPreviewQuad *previewQuad = new QgsPreviewQuad( texture, centerTexCoords, sizeTexCoords, additionalShaderParameters );
472  previewQuad->addComponent( mPreviewLayer );
473  previewQuad->setParent( mRootEntity );
474  mPreviewQuads.push_back( previewQuad );
475  return previewQuad;
476 }
477 
478 // computes the portion of the Y=y plane the camera is looking at
479 void calculateViewExtent( Qt3DRender::QCamera *camera, float shadowRenderingDistance, float y, float &minX, float &maxX, float &minY, float &maxY, float &minZ, float &maxZ )
480 {
481  const QVector3D cameraPos = camera->position();
482  const QMatrix4x4 projectionMatrix = camera->projectionMatrix();
483  const QMatrix4x4 viewMatrix = camera->viewMatrix();
484  float depth = 1.0f;
485  QVector4D viewCenter = viewMatrix * QVector4D( camera->viewCenter(), 1.0f );
486  viewCenter /= viewCenter.w();
487  viewCenter = projectionMatrix * viewCenter;
488  viewCenter /= viewCenter.w();
489  depth = viewCenter.z();
490  QVector<QVector3D> viewFrustumPoints =
491  {
492  QVector3D( 0.0f, 0.0f, depth ),
493  QVector3D( 0.0f, 1.0f, depth ),
494  QVector3D( 1.0f, 0.0f, depth ),
495  QVector3D( 1.0f, 1.0f, depth ),
496  QVector3D( 0.0f, 0.0f, 0 ),
497  QVector3D( 0.0f, 1.0f, 0 ),
498  QVector3D( 1.0f, 0.0f, 0 ),
499  QVector3D( 1.0f, 1.0f, 0 )
500  };
501  maxX = std::numeric_limits<float>::lowest();
502  maxY = std::numeric_limits<float>::lowest();
503  maxZ = std::numeric_limits<float>::lowest();
504  minX = std::numeric_limits<float>::max();
505  minY = std::numeric_limits<float>::max();
506  minZ = std::numeric_limits<float>::max();
507  for ( int i = 0; i < viewFrustumPoints.size(); ++i )
508  {
509  // convert from view port space to world space
510  viewFrustumPoints[i] = viewFrustumPoints[i].unproject( viewMatrix, projectionMatrix, QRect( 0, 0, 1, 1 ) );
511  minX = std::min( minX, viewFrustumPoints[i].x() );
512  maxX = std::max( maxX, viewFrustumPoints[i].x() );
513  minY = std::min( minY, viewFrustumPoints[i].y() );
514  maxY = std::max( maxY, viewFrustumPoints[i].y() );
515  minZ = std::min( minZ, viewFrustumPoints[i].z() );
516  maxZ = std::max( maxZ, viewFrustumPoints[i].z() );
517  // find the intersection between the line going from cameraPos to the frustum quad point
518  // and the horizontal plane Y=y
519  // if the intersection is on the back side of the viewing panel we get a point that is
520  // shadowRenderingDistance units in front of the camera
521  const QVector3D pt = cameraPos;
522  const QVector3D vect = ( viewFrustumPoints[i] - pt ).normalized();
523  float t = ( y - pt.y() ) / vect.y();
524  if ( t < 0 )
525  t = shadowRenderingDistance;
526  else
527  t = std::min( t, shadowRenderingDistance );
528  viewFrustumPoints[i] = pt + t * vect;
529  minX = std::min( minX, viewFrustumPoints[i].x() );
530  maxX = std::max( maxX, viewFrustumPoints[i].x() );
531  minY = std::min( minY, viewFrustumPoints[i].y() );
532  maxY = std::max( maxY, viewFrustumPoints[i].y() );
533  minZ = std::min( minZ, viewFrustumPoints[i].z() );
534  maxZ = std::max( maxZ, viewFrustumPoints[i].z() );
535  }
536 }
537 
538 void QgsShadowRenderingFrameGraph::setupDirectionalLight( const QgsDirectionalLightSettings &light, float maximumShadowRenderingDistance )
539 {
540  float minX, maxX, minY, maxY, minZ, maxZ;
541  QVector3D lookingAt = mMainCamera->viewCenter();
542  const float d = 2 * ( mMainCamera->position() - mMainCamera->viewCenter() ).length();
543 
544  const QVector3D vertical = QVector3D( 0.0f, d, 0.0f );
545  const QVector3D lightDirection = QVector3D( light.direction().x(), light.direction().y(), light.direction().z() ).normalized();
546  calculateViewExtent( mMainCamera, maximumShadowRenderingDistance, lookingAt.y(), minX, maxX, minY, maxY, minZ, maxZ );
547 
548  lookingAt = QVector3D( 0.5 * ( minX + maxX ), mMainCamera->viewCenter().y(), 0.5 * ( minZ + maxZ ) );
549  const QVector3D lightPosition = lookingAt + vertical;
550  mLightCamera->setPosition( lightPosition );
551  mLightCamera->setViewCenter( lookingAt );
552  mLightCamera->setUpVector( QVector3D( 0.0f, 1.0f, 0.0f ) );
553  mLightCamera->rotateAboutViewCenter( QQuaternion::rotationTo( vertical.normalized(), -lightDirection.normalized() ) );
554 
555  mLightCamera->setProjectionType( Qt3DRender::QCameraLens::ProjectionType::OrthographicProjection );
556  mLightCamera->lens()->setOrthographicProjection(
557  - 0.7 * ( maxX - minX ), 0.7 * ( maxX - minX ),
558  - 0.7 * ( maxZ - minZ ), 0.7 * ( maxZ - minZ ),
559  1.0f, 2 * ( lookingAt - lightPosition ).length() );
560 
561  mPostprocessingEntity->setupShadowRenderingExtent( minX, maxX, minZ, maxZ );
562  mPostprocessingEntity->setupDirectionalLight( lightPosition, lightDirection );
563 }
564 
565 void QgsShadowRenderingFrameGraph::setClearColor( const QColor &clearColor )
566 {
567  mForwardClearBuffers->setClearColor( clearColor );
568 }
569 
571 {
572  mShadowRenderingEnabled = enabled;
573  mPostprocessingEntity->setShadowRenderingEnabled( mShadowRenderingEnabled );
574  if ( mShadowRenderingEnabled )
575  mShadowSceneEntitiesFilter->setEnabled( true );
576  else
577  mShadowSceneEntitiesFilter->setEnabled( false );
578 }
579 
581 {
582  mShadowBias = shadowBias;
583  mPostprocessingEntity->setShadowBias( mShadowBias );
584 }
585 
587 {
588  mShadowMapResolution = resolution;
589  mShadowMapTexture->setWidth( mShadowMapResolution );
590  mShadowMapTexture->setHeight( mShadowMapResolution );
591 }
592 
594 {
595  if ( enabled == mFrustumCullingEnabled )
596  return;
597  mFrustumCullingEnabled = enabled;
598  if ( mFrustumCullingEnabled )
599  mFrustumCulling->setParent( mForwardClearBuffers );
600  else
601  mFrustumCulling->setParent( ( Qt3DCore::QNode * )nullptr );
602 }
603 
604 void QgsShadowRenderingFrameGraph::setupEyeDomeLighting( bool enabled, double strength, int distance )
605 {
606  mEyeDomeLightingEnabled = enabled;
607  mEyeDomeLightingStrength = strength;
608  mEyeDomeLightingDistance = distance;
609  mPostprocessingEntity->setEyeDomeLightingEnabled( enabled );
610  mPostprocessingEntity->setEyeDomeLightingStrength( strength );
611  mPostprocessingEntity->setEyeDomeLightingDistance( distance );
612 }
613 
614 void QgsShadowRenderingFrameGraph::setupShadowMapDebugging( bool enabled, Qt::Corner corner, double size )
615 {
616  mDebugShadowMapPreviewQuad->setEnabled( enabled );
617  if ( enabled )
618  {
619  switch ( corner )
620  {
621  case Qt::Corner::TopRightCorner:
622  mDebugShadowMapPreviewQuad->setViewPort( QPointF( 1.0f - size / 2, 0.0f + size / 2 ), 0.5 * QSizeF( size, size ) );
623  break;
624  case Qt::Corner::TopLeftCorner:
625  mDebugShadowMapPreviewQuad->setViewPort( QPointF( 0.0f + size / 2, 0.0f + size / 2 ), 0.5 * QSizeF( size, size ) );
626  break;
627  case Qt::Corner::BottomRightCorner:
628  mDebugShadowMapPreviewQuad->setViewPort( QPointF( 1.0f - size / 2, 1.0f - size / 2 ), 0.5 * QSizeF( size, size ) );
629  break;
630  case Qt::Corner::BottomLeftCorner:
631  mDebugShadowMapPreviewQuad->setViewPort( QPointF( 0.0f + size / 2, 1.0f - size / 2 ), 0.5 * QSizeF( size, size ) );
632  break;
633  }
634  }
635 }
636 
637 void QgsShadowRenderingFrameGraph::setupDepthMapDebugging( bool enabled, Qt::Corner corner, double size )
638 {
639  mDebugDepthMapPreviewQuad->setEnabled( enabled );
640 
641  if ( enabled )
642  {
643  switch ( corner )
644  {
645  case Qt::Corner::TopRightCorner:
646  mDebugDepthMapPreviewQuad->setViewPort( QPointF( 1.0f - size / 2, 0.0f + size / 2 ), 0.5 * QSizeF( size, size ) );
647  break;
648  case Qt::Corner::TopLeftCorner:
649  mDebugDepthMapPreviewQuad->setViewPort( QPointF( 0.0f + size / 2, 0.0f + size / 2 ), 0.5 * QSizeF( size, size ) );
650  break;
651  case Qt::Corner::BottomRightCorner:
652  mDebugDepthMapPreviewQuad->setViewPort( QPointF( 1.0f - size / 2, 1.0f - size / 2 ), 0.5 * QSizeF( size, size ) );
653  break;
654  case Qt::Corner::BottomLeftCorner:
655  mDebugDepthMapPreviewQuad->setViewPort( QPointF( 0.0f + size / 2, 1.0f - size / 2 ), 0.5 * QSizeF( size, size ) );
656  break;
657  }
658  }
659 }
660 
662 {
663  mSize = s;
664  mForwardColorTexture->setSize( mSize.width(), mSize.height() );
665  mForwardDepthTexture->setSize( mSize.width(), mSize.height() );
666  mRenderCaptureColorTexture->setSize( mSize.width(), mSize.height() );
667  mRenderCaptureDepthTexture->setSize( mSize.width(), mSize.height() );
668  mDepthRenderCaptureDepthTexture->setSize( mSize.width(), mSize.height() );
669  mDepthRenderCaptureColorTexture->setSize( mSize.width(), mSize.height() );
670  mRenderSurfaceSelector->setExternalRenderTargetSize( mSize );
671 }
672 
674 {
675  if ( enabled == mRenderCaptureEnabled )
676  return;
677  mRenderCaptureEnabled = enabled;
678  mRenderCaptureTargetSelector->setEnabled( mRenderCaptureEnabled );
679 }
680 
682 {
683 #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
684  mDebugOverlay->setEnabled( enabled );
685 #else
686  Q_UNUSED( enabled )
687  qDebug() << "Cannot display debug overlay. Qt version 5.15 or above is needed.";
688 #endif
689 }
QgsShadowRenderingFrameGraph::setShadowBias
void setShadowBias(float shadowBias)
Sets the shadow bias value.
Definition: qgsshadowrenderingframegraph.cpp:580
qgspreviewquad.h
QgsShadowRenderingFrameGraph::setSize
void setSize(QSize s)
Sets the size of the buffers used for rendering.
Definition: qgsshadowrenderingframegraph.cpp:661
qgsrectangle.h
QgsVector3D::y
double y() const
Returns Y coordinate.
Definition: qgsvector3d.h:64
QgsPostprocessingEntity::setEyeDomeLightingStrength
void setEyeDomeLightingStrength(double strength)
Sets the eye dome lighting strength.
Definition: qgspostprocessingentity.cpp:195
QgsShadowRenderingFrameGraph::setupEyeDomeLighting
void setupEyeDomeLighting(bool enabled, double strength, int distance)
Sets eye dome lighting shading related settings.
Definition: qgsshadowrenderingframegraph.cpp:604
calculateViewExtent
void calculateViewExtent(Qt3DRender::QCamera *camera, float shadowRenderingDistance, float y, float &minX, float &maxX, float &minY, float &maxY, float &minZ, float &maxZ)
Definition: qgsshadowrenderingframegraph.cpp:479
QgsPostprocessingEntity::setupDirectionalLight
void setupDirectionalLight(QVector3D position, QVector3D direction)
Sets up a directional light that is used to render shadows.
Definition: qgspostprocessingentity.cpp:174
QgsShadowRenderingFrameGraph::addTexturePreviewOverlay
QgsPreviewQuad * addTexturePreviewOverlay(Qt3DRender::QTexture2D *texture, const QPointF &centerNDC, const QSizeF &size, QVector< Qt3DRender::QParameter * > additionalShaderParameters=QVector< Qt3DRender::QParameter * >())
Adds an preview entity that shows a texture in real time for debugging purposes.
Definition: qgsshadowrenderingframegraph.cpp:469
QgsShadowRenderingFrameGraph::shadowBias
float shadowBias() const
Returns the shadow bias value.
Definition: qgsshadowrenderingframegraph.h:119
QgsPostprocessingEntity::setEyeDomeLightingEnabled
void setEyeDomeLightingEnabled(bool enabled)
Sets whether eye dome lighting is enabled.
Definition: qgspostprocessingentity.cpp:190
QgsShadowRenderingFrameGraph::setDebugOverlayEnabled
void setDebugOverlayEnabled(bool enabled)
Sets whether debug overlay is enabled.
Definition: qgsshadowrenderingframegraph.cpp:681
QgsShadowRenderingFrameGraph::QgsShadowRenderingFrameGraph
QgsShadowRenderingFrameGraph(QSurface *surface, QSize s, Qt3DRender::QCamera *mainCamera, Qt3DCore::QEntity *root)
Constructor.
Definition: qgsshadowrenderingframegraph.cpp:399
QgsShadowRenderingFrameGraph::mainCamera
Qt3DRender::QCamera * mainCamera()
Returns the main camera.
Definition: qgsshadowrenderingframegraph.h:93
qgsshadowrenderingframegraph.h
QgsShadowRenderingFrameGraph::setupShadowMapDebugging
void setupShadowMapDebugging(bool enabled, Qt::Corner corner, double size)
Sets the shadow map debugging view port.
Definition: qgsshadowrenderingframegraph.cpp:614
QgsPostprocessingEntity::setupShadowRenderingExtent
void setupShadowRenderingExtent(float minX, float maxX, float minZ, float maxZ)
Sets the parts of the scene where objects cast shadows.
Definition: qgspostprocessingentity.cpp:166
QgsShadowRenderingFrameGraph::setupDepthMapDebugging
void setupDepthMapDebugging(bool enabled, Qt::Corner corner, double size)
Sets the depth map debugging view port.
Definition: qgsshadowrenderingframegraph.cpp:637
QgsVector3D::z
double z() const
Returns Z coordinate.
Definition: qgsvector3d.h:66
qgs3dutils.h
Qt3DCore
Definition: qgsabstract3drenderer.h:30
qgscameracontroller.h
QgsShadowRenderingFrameGraph::setFrustumCullingEnabled
void setFrustumCullingEnabled(bool enabled)
Sets whether frustum culling is enabled.
Definition: qgsshadowrenderingframegraph.cpp:593
QgsShadowRenderingFrameGraph::setRenderCaptureEnabled
void setRenderCaptureEnabled(bool enabled)
Sets whether it will be possible to render to an image.
Definition: qgsshadowrenderingframegraph.cpp:673
QgsPreviewQuad::setViewPort
void setViewPort(const QPointF &centerNDC, const QSizeF &size)
Sets where the quad will be located on the scene.
Definition: qgspreviewquad.cpp:69
QgsDirectionalLightSettings::direction
QgsVector3D direction() const
Returns the direction of the light in degrees.
Definition: qgsdirectionallightsettings.h:46
QgsPostprocessingEntity::setShadowBias
void setShadowBias(float shadowBias)
Sets the shadow bias value.
Definition: qgspostprocessingentity.cpp:185
QgsPostprocessingEntity::setShadowRenderingEnabled
void setShadowRenderingEnabled(bool enabled)
Sets whether shadow rendering is enabled.
Definition: qgspostprocessingentity.cpp:180
QgsShadowRenderingFrameGraph::setupDirectionalLight
void setupDirectionalLight(const QgsDirectionalLightSettings &light, float maximumShadowRenderingDistance)
Sets shadow rendering to use a directional light.
Definition: qgsshadowrenderingframegraph.cpp:538
qgspostprocessingentity.h
QgsShadowRenderingFrameGraph::setClearColor
void setClearColor(const QColor &clearColor)
Sets the clear color of the scene (background color)
Definition: qgsshadowrenderingframegraph.cpp:565
QgsPostprocessingEntity
An entity that is responsible for applying post processing effect.
Definition: qgspostprocessingentity.h:39
QgsShadowRenderingFrameGraph::setShadowRenderingEnabled
void setShadowRenderingEnabled(bool enabled)
Sets whether the shadow rendering is enabled.
Definition: qgsshadowrenderingframegraph.cpp:570
QgsVector3D::x
double x() const
Returns X coordinate.
Definition: qgsvector3d.h:62
QgsPostprocessingEntity::setEyeDomeLightingDistance
void setEyeDomeLightingDistance(int distance)
Sets the eye dome lighting distance (contributes to the contrast of the image)
Definition: qgspostprocessingentity.cpp:200
qgsdirectionallightsettings.h
QgsPreviewQuad
Rectangular quad entity used for debugging depth maps.
Definition: qgspreviewquad.h:58
QgsShadowRenderingFrameGraph::setShadowMapResolution
void setShadowMapResolution(int resolution)
Sets the resolution of the shadow map.
Definition: qgsshadowrenderingframegraph.cpp:586
QgsDirectionalLightSettings
Definition of a directional light in a 3D map scene.
Definition: qgsdirectionallightsettings.h:33