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