QGIS API Documentation 3.99.0-Master (357b655ed83)
Loading...
Searching...
No Matches
qgshighlightsrenderview.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgshighlightsrenderview.cpp
3 ---------------------
4 begin : December 2025
5 copyright : (C) 2025 by Stefanos Natsis
6 email : uclaros 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
17
18#include <Qt3DRender/QBlendEquation>
19#include <Qt3DRender/QBlendEquationArguments>
20#include <Qt3DRender/QCamera>
21#include <Qt3DRender/QCameraSelector>
22#include <Qt3DRender/QClearBuffers>
23#include <Qt3DRender/QCullFace>
24#include <Qt3DRender/QDepthTest>
25#include <Qt3DRender/QLayer>
26#include <Qt3DRender/QLayerFilter>
27#include <Qt3DRender/QNoDepthMask>
28#include <Qt3DRender/QRenderStateSet>
29#include <Qt3DRender/QRenderTarget>
30#include <Qt3DRender/QRenderTargetSelector>
31#include <Qt3DRender/QStencilMask>
32#include <Qt3DRender/QStencilOperation>
33#include <Qt3DRender/QStencilOperationArguments>
34#include <Qt3DRender/QStencilTest>
35#include <Qt3DRender/QStencilTestArguments>
36#include <Qt3DRender/QViewport>
37#include <Qt3DRender/qsubtreeenabler.h>
38
39QgsHighlightsRenderView::QgsHighlightsRenderView( const QString &viewName, Qt3DRender::QRenderTarget *target, Qt3DRender::QCamera *camera )
40 : QgsAbstractRenderView( viewName )
41 , mRenderTarget( target )
42 , mMainCamera( camera )
43{
44 mHighlightsLayer = new Qt3DRender::QLayer;
45 mHighlightsLayer->setRecursive( true );
46 mHighlightsLayer->setObjectName( mViewName + "::Layer" );
47
48 buildRenderPasses();
49}
50
51void QgsHighlightsRenderView::buildRenderPasses()
52{
53 Qt3DRender::QRenderTargetSelector *highlightsRenderTargetSelector = new Qt3DRender::QRenderTargetSelector( mRendererEnabler );
54 highlightsRenderTargetSelector->setTarget( mRenderTarget );
55
56 // Step 1: draw semi-transparent highlight
57 //
58 // Clear stencil and render all Highlights Layer's entities as semi-transparent, with no depth test,
59 // while writing to the stencil buffer. Depth buffer is not modified.
60 {
61 Qt3DRender::QRenderStateSet *stateSet = new Qt3DRender::QRenderStateSet( highlightsRenderTargetSelector );
62
63 // we need to allow writing to the stencil buffer before clearing it
64 Qt3DRender::QStencilMask *forceWriteMask = new Qt3DRender::QStencilMask( stateSet );
65 forceWriteMask->setFrontOutputMask( 0xFF );
66 forceWriteMask->setBackOutputMask( 0xFF );
67 stateSet->addRenderState( forceWriteMask );
68
69 Qt3DRender::QClearBuffers *clearStencilBuffer = new Qt3DRender::QClearBuffers( stateSet );
70 clearStencilBuffer->setBuffers( Qt3DRender::QClearBuffers::StencilBuffer );
71 clearStencilBuffer->setClearStencilValue( 0 );
72
73 Qt3DRender::QCameraSelector *cameraSelector = new Qt3DRender::QCameraSelector( clearStencilBuffer );
74 cameraSelector->setCamera( mMainCamera );
75
76 Qt3DRender::QLayerFilter *LayerFilter = new Qt3DRender::QLayerFilter( cameraSelector );
77 LayerFilter->addLayer( mHighlightsLayer );
78
79 Qt3DRender::QBlendEquationArguments *blendState = new Qt3DRender::QBlendEquationArguments;
80 blendState->setSourceRgb( Qt3DRender::QBlendEquationArguments::SourceAlpha );
81 blendState->setDestinationRgb( Qt3DRender::QBlendEquationArguments::OneMinusSourceAlpha );
82 stateSet->addRenderState( blendState );
83
84 Qt3DRender::QBlendEquation *blendEquation = new Qt3DRender::QBlendEquation;
85 blendEquation->setBlendFunction( Qt3DRender::QBlendEquation::Add );
86 stateSet->addRenderState( blendEquation );
87
88 Qt3DRender::QNoDepthMask *noDepthMask = new Qt3DRender::QNoDepthMask;
89 stateSet->addRenderState( noDepthMask );
90
91 Qt3DRender::QDepthTest *depthTest = new Qt3DRender::QDepthTest;
92 depthTest->setDepthFunction( Qt3DRender::QDepthTest::Always );
93 stateSet->addRenderState( depthTest );
94
95 Qt3DRender::QCullFace *cullFace = new Qt3DRender::QCullFace;
96 cullFace->setMode( Qt3DRender::QCullFace::NoCulling );
97 stateSet->addRenderState( cullFace );
98
99 Qt3DRender::QStencilOperation *stencilOp = new Qt3DRender::QStencilOperation;
100 stencilOp->front()->setStencilTestFailureOperation( Qt3DRender::QStencilOperationArguments::Keep );
101 stencilOp->front()->setDepthTestFailureOperation( Qt3DRender::QStencilOperationArguments::Keep );
102 stencilOp->front()->setAllTestsPassOperation( Qt3DRender::QStencilOperationArguments::Replace );
103 stencilOp->back()->setStencilTestFailureOperation( Qt3DRender::QStencilOperationArguments::Keep );
104 stencilOp->back()->setDepthTestFailureOperation( Qt3DRender::QStencilOperationArguments::Keep );
105 stencilOp->back()->setAllTestsPassOperation( Qt3DRender::QStencilOperationArguments::Replace );
106 stateSet->addRenderState( stencilOp );
107
108 Qt3DRender::QStencilTest *stencilTest = new Qt3DRender::QStencilTest;
109 stencilTest->front()->setStencilFunction( Qt3DRender::QStencilTestArguments::Always );
110 stencilTest->front()->setComparisonMask( 0xFF );
111 stencilTest->front()->setReferenceValue( 1 );
112 stencilTest->back()->setStencilFunction( Qt3DRender::QStencilTestArguments::Always );
113 stencilTest->back()->setComparisonMask( 0xFF );
114 stencilTest->back()->setReferenceValue( 1 );
115 stateSet->addRenderState( stencilTest );
116 }
117
118 // Step 2: draw silhouette around highlighted entities (solid color, no transparency)
119 //
120 // Render the highlights entities offseted by x pixels on each of 4 directions using stencil test
121 // to only paint around the existing semi-transparent highlight entities.
122 {
123 Qt3DRender::QRenderStateSet *stateSet = new Qt3DRender::QRenderStateSet( highlightsRenderTargetSelector );
124
125 // we need to allow writing to the stencil buffer before clearing it
126 Qt3DRender::QStencilMask *stencilReadMask = new Qt3DRender::QStencilMask( stateSet );
127 stencilReadMask->setFrontOutputMask( 0x00 );
128 stencilReadMask->setBackOutputMask( 0x00 );
129 stateSet->addRenderState( stencilReadMask );
130
131 Qt3DRender::QNoDepthMask *noDepthMask = new Qt3DRender::QNoDepthMask;
132 stateSet->addRenderState( noDepthMask );
133
134 // always pass depth test so we "render on top"
135 Qt3DRender::QDepthTest *depthTest = new Qt3DRender::QDepthTest;
136 depthTest->setDepthFunction( Qt3DRender::QDepthTest::Always );
137 stateSet->addRenderState( depthTest );
138
139 Qt3DRender::QCullFace *cullFace = new Qt3DRender::QCullFace;
140 cullFace->setMode( Qt3DRender::QCullFace::NoCulling );
141 stateSet->addRenderState( cullFace );
142
143 Qt3DRender::QStencilTest *stencilTest = new Qt3DRender::QStencilTest;
144 stencilTest->front()->setStencilFunction( Qt3DRender::QStencilTestArguments::Equal );
145 stencilTest->front()->setComparisonMask( 0xFF );
146 stencilTest->front()->setReferenceValue( 0 );
147 stencilTest->back()->setStencilFunction( Qt3DRender::QStencilTestArguments::Equal );
148 stencilTest->back()->setComparisonMask( 0xFF );
149 stencilTest->back()->setReferenceValue( 0 );
150 stateSet->addRenderState( stencilTest );
151
152 Qt3DRender::QCameraSelector *cameraSelector = new Qt3DRender::QCameraSelector( stateSet );
153 cameraSelector->setObjectName( "Highlights Pass CameraSelector2" );
154 cameraSelector->setCamera( mMainCamera );
155
156 Qt3DRender::QLayerFilter *layerFilter = new Qt3DRender::QLayerFilter( cameraSelector );
157 layerFilter->addLayer( mHighlightsLayer );
158
159 mViewportUp = new Qt3DRender::QViewport( layerFilter );
160 mViewportDown = new Qt3DRender::QViewport( layerFilter );
161 mViewportLeft = new Qt3DRender::QViewport( layerFilter );
162 mViewportRight = new Qt3DRender::QViewport( layerFilter );
163 }
164
165 const QVector<Qt3DRender::QRenderTargetOutput *> outputs = mRenderTarget->outputs();
166 for ( Qt3DRender::QRenderTargetOutput *o : outputs )
167 {
168 Qt3DRender::QAbstractTexture *texture = o->texture();
169 if ( texture )
170 {
171 updateViewportSizes( texture->width(), texture->height() );
172 break;
173 }
174 }
175}
176
177void QgsHighlightsRenderView::updateViewportSizes( int width, int height )
178{
179 const float offsetX = static_cast<float>( silhouetteWidth() ) / static_cast<float>( width );
180 const float offsetY = static_cast<float>( silhouetteWidth() ) / static_cast<float>( height );
181 mViewportUp->setNormalizedRect( QRectF( offsetX, 0.0f, 1.0f + offsetX, 1.0f ) );
182 mViewportDown->setNormalizedRect( QRectF( 0.0f, offsetY, 1.0f, 1.0f + offsetY ) );
183 mViewportLeft->setNormalizedRect( QRectF( -offsetX, 0.0f, 1.0f - offsetX, 1.0f ) );
184 mViewportRight->setNormalizedRect( QRectF( 0.0f, -offsetY, 1.0f, 1.0f - offsetY ) );
185}
186
188{
189 updateViewportSizes( width, height );
190}
Qt3DRender::QSubtreeEnabler * mRendererEnabler
QgsAbstractRenderView(const QString &viewName)
Constructor for QgsAbstractRenderView with the specified parent object.
void updateWindowResize(int width, int height) override
Called when 3D window is resized.
static int silhouetteWidth()
Returns the width of the generated silhouette effect in pixels.
QgsHighlightsRenderView(const QString &viewName, Qt3DRender::QRenderTarget *target, Qt3DRender::QCamera *camera)
Constructor.