QGIS API Documentation 3.40.0-Bratislava (b56115d8743)
Loading...
Searching...
No Matches
qgs3dmapscene.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgs3dmapscene.cpp
3 --------------------------------------
4 Date : July 2017
5 Copyright : (C) 2017 by Martin Dobias
6 Email : wonder dot sk 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 "qgs3dmapscene.h"
17
18#include <Qt3DRender/QCamera>
19#include <Qt3DRender/QMesh>
20#include <Qt3DRender/QRenderSettings>
21#include <Qt3DRender/QSceneLoader>
22#include <Qt3DExtras/QForwardRenderer>
23#include <Qt3DExtras/QPhongMaterial>
24#include <Qt3DExtras/QPhongAlphaMaterial>
25#include <Qt3DExtras/QDiffuseSpecularMaterial>
26#include <Qt3DExtras/QSphereMesh>
27#include <Qt3DLogic/QFrameAction>
28#include <Qt3DRender/QEffect>
29#include <Qt3DRender/QTechnique>
30#include <Qt3DRender/QRenderPass>
31#include <Qt3DRender/QRenderState>
32#include <Qt3DRender/QCullFace>
33#include <Qt3DRender/QDepthTest>
34#include <QSurface>
35#include <QUrl>
36#include <QtMath>
37
38#include <QOpenGLContext>
39#include <QOpenGLFunctions>
40#include <QTimer>
41
42#include "qgs3daxis.h"
43#include "qgslogger.h"
44#include "qgsapplication.h"
45#include "qgsaabb.h"
46#include "qgsabstract3dengine.h"
47#include "qgs3dmapsettings.h"
48#include "qgs3dutils.h"
50#include "qgscameracontroller.h"
51#include "qgschunkedentity.h"
52#include "qgschunknode.h"
53#include "qgseventtracing.h"
54#include "qgsmaterial.h"
55#include "qgsmeshlayer.h"
57#include "qgspoint3dsymbol.h"
59#include "qgspointcloudlayer.h"
61#include "qgssourcecache.h"
62#include "qgsterrainentity.h"
63#include "qgsterraingenerator.h"
64#include "qgstiledscenelayer.h"
67#include "qgsvectorlayer.h"
72#include "qgslinematerial_p.h"
73#include "qgs3dsceneexporter.h"
75#include "qgsmessageoutput.h"
76#include "qgsframegraph.h"
77
78#include "qgsskyboxentity.h"
79#include "qgsskyboxsettings.h"
80
81#include "qgswindow3dengine.h"
82#include "qgspointcloudlayer.h"
83
84std::function< QMap< QString, Qgs3DMapScene * >() > Qgs3DMapScene::sOpenScenesFunction = [] { return QMap< QString, Qgs3DMapScene * >(); };
85
87 : mMap( map )
88 , mEngine( engine )
89{
90
91 connect( &map, &Qgs3DMapSettings::backgroundColorChanged, this, &Qgs3DMapScene::onBackgroundColorChanged );
92 onBackgroundColorChanged();
93
94 // The default render policy in Qt3D is "Always" - i.e. the 3D map scene gets refreshed up to 60 fps
95 // even if there's no change. Switching to "on demand" should only re-render when something has changed
96 // and we save quite a lot of resources
97 mEngine->renderSettings()->setRenderPolicy( Qt3DRender::QRenderSettings::OnDemand );
98
99 QRect viewportRect( QPoint( 0, 0 ), mEngine->size() );
100
101 // Camera
102 float aspectRatio = ( float )viewportRect.width() / viewportRect.height();
103 mEngine->camera()->lens()->setPerspectiveProjection( mMap.fieldOfView(), aspectRatio, 10.f, 10000.0f );
104
105 mFrameAction = new Qt3DLogic::QFrameAction();
106 connect( mFrameAction, &Qt3DLogic::QFrameAction::triggered,
107 this, &Qgs3DMapScene::onFrameTriggered );
108 addComponent( mFrameAction ); // takes ownership
109
110 // Camera controlling
111 mCameraController = new QgsCameraController( this ); // attaches to the scene
112 mCameraController->resetView( 1000 );
113
114 addCameraViewCenterEntity( mEngine->camera() );
115 addCameraRotationCenterEntity( mCameraController );
116 updateLights();
117
118 // create terrain entity
119
120 createTerrainDeferred();
121 connect( &map, &Qgs3DMapSettings::extentChanged, this, &Qgs3DMapScene::createTerrain );
122 connect( &map, &Qgs3DMapSettings::terrainGeneratorChanged, this, &Qgs3DMapScene::createTerrain );
123 connect( &map, &Qgs3DMapSettings::terrainVerticalScaleChanged, this, &Qgs3DMapScene::createTerrain );
124 connect( &map, &Qgs3DMapSettings::mapTileResolutionChanged, this, &Qgs3DMapScene::createTerrain );
125 connect( &map, &Qgs3DMapSettings::maxTerrainScreenErrorChanged, this, &Qgs3DMapScene::createTerrain );
126 connect( &map, &Qgs3DMapSettings::maxTerrainGroundErrorChanged, this, &Qgs3DMapScene::createTerrain );
127 connect( &map, &Qgs3DMapSettings::terrainShadingChanged, this, &Qgs3DMapScene::createTerrain );
128 connect( &map, &Qgs3DMapSettings::lightSourcesChanged, this, &Qgs3DMapScene::updateLights );
129 connect( &map, &Qgs3DMapSettings::showLightSourceOriginsChanged, this, &Qgs3DMapScene::updateLights );
130 connect( &map, &Qgs3DMapSettings::fieldOfViewChanged, this, &Qgs3DMapScene::updateCameraLens );
131 connect( &map, &Qgs3DMapSettings::projectionTypeChanged, this, &Qgs3DMapScene::updateCameraLens );
132 connect( &map, &Qgs3DMapSettings::skyboxSettingsChanged, this, &Qgs3DMapScene::onSkyboxSettingsChanged );
133 connect( &map, &Qgs3DMapSettings::shadowSettingsChanged, this, &Qgs3DMapScene::onShadowSettingsChanged );
134 connect( &map, &Qgs3DMapSettings::ambientOcclusionSettingsChanged, this, &Qgs3DMapScene::onAmbientOcclusionSettingsChanged );
135 connect( &map, &Qgs3DMapSettings::eyeDomeLightingEnabledChanged, this, &Qgs3DMapScene::onEyeDomeShadingSettingsChanged );
136 connect( &map, &Qgs3DMapSettings::eyeDomeLightingStrengthChanged, this, &Qgs3DMapScene::onEyeDomeShadingSettingsChanged );
137 connect( &map, &Qgs3DMapSettings::eyeDomeLightingDistanceChanged, this, &Qgs3DMapScene::onEyeDomeShadingSettingsChanged );
138 connect( &map, &Qgs3DMapSettings::debugShadowMapSettingsChanged, this, &Qgs3DMapScene::onDebugShadowMapSettingsChanged );
139 connect( &map, &Qgs3DMapSettings::debugDepthMapSettingsChanged, this, &Qgs3DMapScene::onDebugDepthMapSettingsChanged );
141 connect( &map, &Qgs3DMapSettings::cameraMovementSpeedChanged, this, &Qgs3DMapScene::onCameraMovementSpeedChanged );
142 connect( &map, &Qgs3DMapSettings::cameraNavigationModeChanged, this, &Qgs3DMapScene::onCameraNavigationModeChanged );
143 connect( &map, &Qgs3DMapSettings::debugOverlayEnabledChanged, this, &Qgs3DMapScene::onDebugOverlayEnabledChanged );
144
145 connect( &map, &Qgs3DMapSettings::axisSettingsChanged, this, &Qgs3DMapScene::on3DAxisSettingsChanged );
146
147 connect( QgsApplication::sourceCache(), &QgsSourceCache::remoteSourceFetched, this, [ = ]( const QString & url )
148 {
149 const QList<QgsMapLayer *> modelVectorLayers = mModelVectorLayers;
150 for ( QgsMapLayer *layer : modelVectorLayers )
151 {
152 QgsAbstract3DRenderer *renderer = layer->renderer3D();
153 if ( renderer )
154 {
155 if ( renderer->type() == QLatin1String( "vector" ) )
156 {
157 const QgsPoint3DSymbol *pointSymbol = static_cast< const QgsPoint3DSymbol * >( static_cast< QgsVectorLayer3DRenderer *>( renderer )->symbol() );
158 if ( pointSymbol->shapeProperty( QStringLiteral( "model" ) ).toString() == url )
159 {
160 removeLayerEntity( layer );
161 addLayerEntity( layer );
162 }
163 }
164 else if ( renderer->type() == QLatin1String( "rulebased" ) )
165 {
166 const QgsRuleBased3DRenderer::RuleList rules = static_cast< QgsRuleBased3DRenderer *>( renderer )->rootRule()->descendants();
167 for ( auto rule : rules )
168 {
169 const QgsPoint3DSymbol *pointSymbol = dynamic_cast< const QgsPoint3DSymbol * >( rule->symbol() );
170 if ( pointSymbol->shapeProperty( QStringLiteral( "model" ) ).toString() == url )
171 {
172 removeLayerEntity( layer );
173 addLayerEntity( layer );
174 break;
175 }
176 }
177 }
178 }
179 }
180 } );
181
182 // listen to changes of layers in order to add/remove 3D renderer entities
183 connect( &map, &Qgs3DMapSettings::layersChanged, this, &Qgs3DMapScene::onLayersChanged );
184
185 connect( mCameraController, &QgsCameraController::cameraChanged, this, &Qgs3DMapScene::onCameraChanged );
186 connect( mEngine, &QgsAbstract3DEngine::sizeChanged, this, &Qgs3DMapScene::onCameraChanged );
187
188 onSkyboxSettingsChanged();
189
190 // force initial update of chunked entities
191 onCameraChanged();
192 // force initial update of eye dome shading
193 onEyeDomeShadingSettingsChanged();
194 // force initial update of debugging setting of preview quads
195 onDebugShadowMapSettingsChanged();
196 onDebugDepthMapSettingsChanged();
197 // force initial update of ambient occlusion settings
198 onAmbientOcclusionSettingsChanged();
199
200 mCameraController->setCameraNavigationMode( mMap.cameraNavigationMode() );
201 onCameraMovementSpeedChanged();
202
203 on3DAxisSettingsChanged();
204}
205
207{
208 const QgsDoubleRange yRange = elevationRange();
209 const QgsRectangle extent = sceneExtent();
210 const double side = std::max( extent.width(), extent.height() );
211 double d = side / 2 / std::tan( cameraController()->camera()->fieldOfView() / 2 * M_PI / 180 );
212 d += yRange.isInfinite() ? 0. : yRange.upper();
213 mCameraController->resetView( static_cast< float >( d ) );
214 return;
215}
216
218{
219 QgsPointXY center = extent.center();
220 QgsVector3D centerWorld = mMap.mapToWorldCoordinates( QVector3D( center.x(), center.y(), 0 ) );
221 QgsVector3D p1 = mMap.mapToWorldCoordinates( QVector3D( extent.xMinimum(), extent.yMinimum(), 0 ) );
222 QgsVector3D p2 = mMap.mapToWorldCoordinates( QVector3D( extent.xMaximum(), extent.yMaximum(), 0 ) );
223
224 float xSide = std::abs( p1.x() - p2.x() );
225 float ySide = std::abs( p1.z() - p2.z() );
226 if ( xSide < ySide )
227 {
228 float fov = 2 * std::atan( std::tan( qDegreesToRadians( cameraController()->camera()->fieldOfView() ) / 2 ) * cameraController()->camera()->aspectRatio() );
229 float r = xSide / 2.0f / std::tan( fov / 2.0f );
230 mCameraController->setViewFromTop( centerWorld.x(), centerWorld.z(), r );
231 }
232 else
233 {
234 float fov = qDegreesToRadians( cameraController()->camera()->fieldOfView() );
235 float r = ySide / 2.0f / std::tan( fov / 2.0f );
236 mCameraController->setViewFromTop( centerWorld.x(), centerWorld.z(), r );
237 }
238}
239
240QVector<QgsPointXY> Qgs3DMapScene::viewFrustum2DExtent() const
241{
242 Qt3DRender::QCamera *camera = mCameraController->camera();
243 QVector<QgsPointXY> extent;
244 QVector<int> pointsOrder = { 0, 1, 3, 2 };
245 for ( int i : pointsOrder )
246 {
247 const QPoint p( ( ( i >> 0 ) & 1 ) ? 0 : mEngine->size().width(), ( ( i >> 1 ) & 1 ) ? 0 : mEngine->size().height() );
248 QgsRay3D ray = Qgs3DUtils::rayFromScreenPoint( p, mEngine->size(), camera );
249 QVector3D dir = ray.direction();
250 if ( dir.y() == 0.0 )
251 dir.setY( 0.000001 );
252 double t = - ray.origin().y() / dir.y();
253 if ( t < 0 )
254 {
255 // If the projected point is on the back of the camera we choose the farthest point in the front
256 t = camera->farPlane();
257 }
258 else
259 {
260 // If the projected point is on the front of the camera we choose the closest between it and farthest point in the front
261 t = std::min<float>( t, camera->farPlane() );
262 }
263 QVector3D planePoint = ray.origin() + t * dir;
264 QgsVector3D pMap = mMap.worldToMapCoordinates( planePoint );
265 extent.push_back( QgsPointXY( pMap.x(), pMap.y() ) );
266 }
267 return extent;
268}
269
271{
272 return mTerrain ? mTerrain->pendingJobsCount() : 0;
273}
274
276{
277 int count = 0;
278 for ( Qgs3DMapSceneEntity *entity : std::as_const( mSceneEntities ) )
279 count += entity->pendingJobsCount();
280 return count;
281}
282
283float Qgs3DMapScene::worldSpaceError( float epsilon, float distance ) const
284{
285 Qt3DRender::QCamera *camera = mCameraController->camera();
286 float fov = camera->fieldOfView();
287 const QSize size = mEngine->size();
288 float screenSizePx = std::max( size.width(), size.height() ); // TODO: is this correct?
289
290 // see Qgs3DUtils::screenSpaceError() for the inverse calculation (world space error to screen space error)
291 // with explanation of the math.
292 float frustumWidthAtDistance = 2 * distance * tan( fov / 2 );
293 float err = frustumWidthAtDistance * epsilon / screenSizePx;
294 return err;
295}
296
297void Qgs3DMapScene::onCameraChanged()
298{
299 if ( mMap.projectionType() == Qt3DRender::QCameraLens::OrthographicProjection )
300 {
301 QRect viewportRect( QPoint( 0, 0 ), mEngine->size() );
302 const float viewWidthFromCenter = mCameraController->distance();
303 const float viewHeightFromCenter = viewportRect.height() * viewWidthFromCenter / viewportRect.width();
304 mEngine->camera()->lens()->setOrthographicProjection( -viewWidthFromCenter, viewWidthFromCenter, -viewHeightFromCenter, viewHeightFromCenter, mEngine->camera()->nearPlane(), mEngine->camera()->farPlane() );
305 }
306
307 updateScene( true );
308 bool changedCameraPlanes = updateCameraNearFarPlanes();
309
310 if ( changedCameraPlanes )
311 {
312 // repeat update of entities - because we have updated camera's near/far planes,
313 // the active nodes may have changed as well
314 updateScene( true );
315 updateCameraNearFarPlanes();
316 }
317
318 onShadowSettingsChanged();
319
320 QVector<QgsPointXY> extent2D = viewFrustum2DExtent();
321 emit viewed2DExtentFrom3DChanged( extent2D );
322}
323
324void Qgs3DMapScene::updateScene( bool forceUpdate )
325{
326 if ( !mSceneUpdatesEnabled )
327 {
328 QgsDebugMsgLevel( "Scene update skipped", 2 );
329 return;
330 }
331
332 if ( forceUpdate )
333 QgsEventTracing::addEvent( QgsEventTracing::Instant, QStringLiteral( "3D" ), QStringLiteral( "Update Scene" ) );
334
335 Qgs3DMapSceneEntity::SceneContext sceneContext;
336 Qt3DRender::QCamera *camera = mEngine->camera();
337 sceneContext.cameraFov = camera->fieldOfView();
338 sceneContext.cameraPos = camera->position();
339 const QSize size = mEngine->size();
340 sceneContext.screenSizePx = std::max( size.width(), size.height() ); // TODO: is this correct?
341 sceneContext.viewProjectionMatrix = camera->projectionMatrix() * camera->viewMatrix();
342
343
344 for ( Qgs3DMapSceneEntity *entity : std::as_const( mSceneEntities ) )
345 {
346 if ( forceUpdate || ( entity->isEnabled() && entity->needsUpdate() ) )
347 {
348 entity->handleSceneUpdate( sceneContext );
349 if ( entity->hasReachedGpuMemoryLimit() )
351 }
352 }
353
354 updateSceneState();
355}
356
357bool Qgs3DMapScene::updateCameraNearFarPlanes()
358{
359 // Update near and far plane from the terrain.
360 // this needs to be done with great care as we have kind of circular dependency here:
361 // active nodes are culled based on the current frustum (which involves near + far plane)
362 // and then based on active nodes we set near and far plane.
363 //
364 // All of this is just heuristics assuming that all other stuff is being rendered somewhere
365 // around the area where the terrain is.
366 //
367 // Near/far plane is setup in order to make best use of the depth buffer to avoid:
368 // 1. precision errors - if the range is too great
369 // 2. unwanted clipping of scene - if the range is too small
370
371 Qt3DRender::QCamera *camera = cameraController()->camera();
372 QMatrix4x4 viewMatrix = camera->viewMatrix();
373 float fnear = 1e9;
374 float ffar = 0;
375
376 // Iterate all scene entities to make sure that they will not get
377 // clipped by the near or far plane
378 for ( Qgs3DMapSceneEntity *se : std::as_const( mSceneEntities ) )
379 {
380 const QgsRange<float> depthRange = se->getNearFarPlaneRange( viewMatrix );
381
382 fnear = std::min( fnear, depthRange.lower() );
383 ffar = std::max( ffar, depthRange.upper() );
384 }
385
386 if ( fnear < 1 )
387 fnear = 1; // does not really make sense to use negative far plane (behind camera)
388
389 // the update didn't work out... this can happen if the scene does not contain
390 // any Qgs3DMapSceneEntity. Use the scene extent to compute near and far planes
391 // as a fallback.
392 if ( fnear == 1e9 && ffar == 0 )
393 {
394 QgsDoubleRange sceneYRange = elevationRange();
395 sceneYRange = sceneYRange.isInfinite() ? QgsDoubleRange( 0.0, 0.0 ) : sceneYRange;
396 const QgsAABB sceneBbox = Qgs3DUtils::mapToWorldExtent( mMap.extent(), sceneYRange.lower(), sceneYRange.upper(), mMap.origin() );
397 Qgs3DUtils::computeBoundingBoxNearFarPlanes( sceneBbox, viewMatrix, fnear, ffar );
398 }
399
400 // when zooming in a lot, fnear can become smaller than ffar. This should not happen
401 if ( fnear > ffar )
402 std::swap( fnear, ffar );
403
404 // set near/far plane - with some tolerance in front/behind expected near/far planes
405 float newFar = ffar * 2;
406 float newNear = fnear / 2;
407 if ( !qgsFloatNear( newFar, camera->farPlane() ) || !qgsFloatNear( newNear, camera->nearPlane() ) )
408 {
409 camera->setFarPlane( newFar );
410 camera->setNearPlane( newNear );
411 return true;
412 }
413
414 return false;
415}
416
417void Qgs3DMapScene::onFrameTriggered( float dt )
418{
419 mCameraController->frameTriggered( dt );
420
421 updateScene();
422
423 // lock changing the FPS counter to 5 fps
424 static int frameCount = 0;
425 static float accumulatedTime = 0.0f;
426
427 if ( !mMap.isFpsCounterEnabled() )
428 {
429 frameCount = 0;
430 accumulatedTime = 0;
431 return;
432 }
433
434 frameCount++;
435 accumulatedTime += dt;
436 if ( accumulatedTime >= 0.2f )
437 {
438 float fps = ( float )frameCount / accumulatedTime;
439 frameCount = 0;
440 accumulatedTime = 0.0f;
441 emit fpsCountChanged( fps );
442 }
443}
444
445void Qgs3DMapScene::createTerrain()
446{
447 if ( mTerrain )
448 {
449 mSceneEntities.removeOne( mTerrain );
450
451 delete mTerrain;
452 mTerrain = nullptr;
453 }
454
455 if ( !mTerrainUpdateScheduled )
456 {
457 // defer re-creation of terrain: there may be multiple invocations of this slot, so create the new entity just once
458 QTimer::singleShot( 0, this, &Qgs3DMapScene::createTerrainDeferred );
459 mTerrainUpdateScheduled = true;
460 setSceneState( Updating );
461 }
462 else
463 {
465 }
466}
467
468void Qgs3DMapScene::createTerrainDeferred()
469{
470 if ( mMap.terrainRenderingEnabled() && mMap.terrainGenerator() )
471 {
472 double tile0width = mMap.terrainGenerator()->rootChunkExtent().width();
473 int maxZoomLevel = Qgs3DUtils::maxZoomLevel( tile0width, mMap.mapTileResolution(), mMap.maxTerrainGroundError() );
474 QgsAABB rootBbox = mMap.terrainGenerator()->rootChunkBbox( mMap );
475 float rootError = mMap.terrainGenerator()->rootChunkError( mMap );
476 const QgsAABB clippingBbox = Qgs3DUtils::mapToWorldExtent( mMap.extent(), rootBbox.zMin, rootBbox.zMax, mMap.origin() );
477 mMap.terrainGenerator()->setupQuadtree( rootBbox, rootError, maxZoomLevel, clippingBbox );
478
479 mTerrain = new QgsTerrainEntity( &mMap );
480 mTerrain->setParent( this );
481 mTerrain->setShowBoundingBoxes( mMap.showTerrainBoundingBoxes() );
482
483 mSceneEntities << mTerrain;
484
485 connect( mTerrain, &QgsChunkedEntity::pendingJobsCountChanged, this, &Qgs3DMapScene::totalPendingJobsCountChanged );
486 connect( mTerrain, &QgsTerrainEntity::pendingJobsCountChanged, this, &Qgs3DMapScene::terrainPendingJobsCountChanged );
487 connect( mTerrain, &Qgs3DMapSceneEntity::newEntityCreated, this, [this]( Qt3DCore::QEntity * entity )
488 {
489 // enable clipping on the terrain if necessary
490 handleClippingOnEntity( entity );
491 } );
492 }
493 else
494 {
495 mTerrain = nullptr;
496 }
497
498 // make sure that renderers for layers are re-created as well
499 const QList<QgsMapLayer *> layers = mMap.layers();
500 for ( QgsMapLayer *layer : layers )
501 {
502 // remove old entity - if any
503 removeLayerEntity( layer );
504
505 // add new entity - if any 3D renderer
506 addLayerEntity( layer );
507 }
508
510 onCameraChanged(); // force update of the new terrain
511 mTerrainUpdateScheduled = false;
512}
513
514void Qgs3DMapScene::onBackgroundColorChanged()
515{
516 mEngine->setClearColor( mMap.backgroundColor() );
517}
518
519void Qgs3DMapScene::updateLights()
520{
521 for ( Qt3DCore::QEntity *entity : std::as_const( mLightEntities ) )
522 entity->deleteLater();
523 mLightEntities.clear();
524
525 const QList< QgsLightSource * > newLights = mMap.lightSources();
526 for ( const QgsLightSource *source : newLights )
527 {
528 mLightEntities.append( source->createEntity( mMap, this ) );
529 }
530
531 onShadowSettingsChanged();
532}
533
534void Qgs3DMapScene::updateCameraLens()
535{
536 mEngine->camera()->lens()->setFieldOfView( mMap.fieldOfView() );
537 mEngine->camera()->lens()->setProjectionType( mMap.projectionType() );
538 onCameraChanged();
539}
540
541void Qgs3DMapScene::onLayerRenderer3DChanged()
542{
543 QgsMapLayer *layer = qobject_cast<QgsMapLayer *>( sender() );
544 Q_ASSERT( layer );
545
546 // remove old entity - if any
547 removeLayerEntity( layer );
548
549 // add new entity - if any 3D renderer
550 addLayerEntity( layer );
551}
552
553void Qgs3DMapScene::onLayersChanged()
554{
555 QSet<QgsMapLayer *> layersBefore = qgis::listToSet( mLayerEntities.keys() );
556 QList<QgsMapLayer *> layersAdded;
557 const QList<QgsMapLayer *> layers = mMap.layers();
558 for ( QgsMapLayer *layer : layers )
559 {
560 if ( !layersBefore.contains( layer ) )
561 {
562 layersAdded << layer;
563 }
564 else
565 {
566 layersBefore.remove( layer );
567 }
568 }
569
570 // what is left in layersBefore are layers that have been removed
571 for ( QgsMapLayer *layer : std::as_const( layersBefore ) )
572 {
573 removeLayerEntity( layer );
574 }
575
576 for ( QgsMapLayer *layer : std::as_const( layersAdded ) )
577 {
578 addLayerEntity( layer );
579 }
580}
581
583{
584 const QList<QgsMapLayer * > layers = mLayerEntities.keys();
585 for ( QgsMapLayer *layer : layers )
586 {
587 if ( QgsMapLayerTemporalProperties *temporalProperties = layer->temporalProperties() )
588 {
589 if ( temporalProperties->isActive() )
590 {
591 removeLayerEntity( layer );
592 addLayerEntity( layer );
593 }
594 }
595 }
596}
597
598void Qgs3DMapScene::addLayerEntity( QgsMapLayer *layer )
599{
600 bool needsSceneUpdate = false;
601 QgsAbstract3DRenderer *renderer = layer->renderer3D();
602 if ( renderer )
603 {
604 // Fix vector layer's renderer to make sure the renderer is pointing to its layer.
605 // It has happened before that renderer pointed to a different layer (probably after copying a style).
606 // This is a bit of a hack and it should be handled in QgsMapLayer::setRenderer3D() but in qgis_core
607 // the vector layer 3D renderer classes are not available.
608 if ( layer->type() == Qgis::LayerType::Vector &&
609 ( renderer->type() == QLatin1String( "vector" ) || renderer->type() == QLatin1String( "rulebased" ) ) )
610 {
611 static_cast<QgsAbstractVectorLayer3DRenderer *>( renderer )->setLayer( static_cast<QgsVectorLayer *>( layer ) );
612 if ( renderer->type() == QLatin1String( "vector" ) )
613 {
614 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
615 if ( vlayer->geometryType() == Qgis::GeometryType::Point )
616 {
617 const QgsPoint3DSymbol *pointSymbol = static_cast< const QgsPoint3DSymbol * >( static_cast< QgsVectorLayer3DRenderer *>( renderer )->symbol() );
618 if ( pointSymbol->shape() == Qgis::Point3DShape::Model )
619 {
620 mModelVectorLayers.append( layer );
621 }
622 }
623 }
624 else if ( renderer->type() == QLatin1String( "rulebased" ) )
625 {
626 const QgsRuleBased3DRenderer::RuleList rules = static_cast< QgsRuleBased3DRenderer *>( renderer )->rootRule()->descendants();
627 for ( auto rule : rules )
628 {
629 const QgsPoint3DSymbol *pointSymbol = dynamic_cast< const QgsPoint3DSymbol * >( rule->symbol() );
630 if ( pointSymbol && pointSymbol->shape() == Qgis::Point3DShape::Model )
631 {
632 mModelVectorLayers.append( layer );
633 break;
634 }
635 }
636 }
637 }
638 else if ( layer->type() == Qgis::LayerType::Mesh && renderer->type() == QLatin1String( "mesh" ) )
639 {
640 QgsMeshLayer3DRenderer *meshRenderer = static_cast<QgsMeshLayer3DRenderer *>( renderer );
641 meshRenderer->setLayer( static_cast<QgsMeshLayer *>( layer ) );
642
643 // Before entity creation, set the maximum texture size
644 // Not very clean, but for now, only place found in the workflow to do that simple
645 QgsMesh3DSymbol *sym = meshRenderer->symbol()->clone();
646 sym->setMaximumTextureSize( maximumTextureSize() );
647 meshRenderer->setSymbol( sym );
648 }
649 else if ( layer->type() == Qgis::LayerType::PointCloud && renderer->type() == QLatin1String( "pointcloud" ) )
650 {
651 QgsPointCloudLayer3DRenderer *pointCloudRenderer = static_cast<QgsPointCloudLayer3DRenderer *>( renderer );
652 pointCloudRenderer->setLayer( static_cast<QgsPointCloudLayer *>( layer ) );
653 }
654 else if ( layer->type() == Qgis::LayerType::TiledScene && renderer->type() == QLatin1String( "tiledscene" ) )
655 {
656 QgsTiledSceneLayer3DRenderer *tiledSceneRenderer = static_cast<QgsTiledSceneLayer3DRenderer *>( renderer );
657 tiledSceneRenderer->setLayer( static_cast<QgsTiledSceneLayer *>( layer ) );
658 }
659
660 Qt3DCore::QEntity *newEntity = renderer->createEntity( &mMap );
661 if ( newEntity )
662 {
663 newEntity->setParent( this );
664 mLayerEntities.insert( layer, newEntity );
665
666 finalizeNewEntity( newEntity );
667
668 if ( Qgs3DMapSceneEntity *sceneNewEntity = qobject_cast<Qgs3DMapSceneEntity *>( newEntity ) )
669 {
670 needsSceneUpdate = true;
671 mSceneEntities.append( sceneNewEntity );
672
673 connect( sceneNewEntity, &Qgs3DMapSceneEntity::newEntityCreated, this, [this]( Qt3DCore::QEntity * entity )
674 {
675 finalizeNewEntity( entity );
676 // this ensures to update the near/far planes with the exact bounding box of the new entity.
677 updateCameraNearFarPlanes();
678 } );
679
680 connect( sceneNewEntity, &Qgs3DMapSceneEntity::pendingJobsCountChanged, this, &Qgs3DMapScene::totalPendingJobsCountChanged );
681 }
682 }
683 }
684
685 if ( needsSceneUpdate )
686 onCameraChanged(); // needed for chunked entities
687
688 connect( layer, &QgsMapLayer::request3DUpdate, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
689
690 if ( layer->type() == Qgis::LayerType::Vector )
691 {
692 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
693 connect( vlayer, &QgsVectorLayer::selectionChanged, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
694 connect( vlayer, &QgsVectorLayer::layerModified, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
695 }
696
697 if ( layer->type() == Qgis::LayerType::Mesh )
698 {
699 connect( layer, &QgsMapLayer::rendererChanged, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
700 }
701
702 if ( layer->type() == Qgis::LayerType::PointCloud )
703 {
704 QgsPointCloudLayer *pclayer = qobject_cast<QgsPointCloudLayer *>( layer );
705 connect( pclayer, &QgsPointCloudLayer::renderer3DChanged, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
706 connect( pclayer, &QgsPointCloudLayer::subsetStringChanged, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
707 }
708}
709
710void Qgs3DMapScene::removeLayerEntity( QgsMapLayer *layer )
711{
712 Qt3DCore::QEntity *entity = mLayerEntities.take( layer );
713
714 if ( Qgs3DMapSceneEntity *sceneEntity = qobject_cast<Qgs3DMapSceneEntity *>( entity ) )
715 {
716 mSceneEntities.removeOne( sceneEntity );
717 }
718
719 if ( entity )
720 entity->deleteLater();
721
722 disconnect( layer, &QgsMapLayer::request3DUpdate, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
723
724 if ( layer->type() == Qgis::LayerType::Vector )
725 {
726 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
727 disconnect( vlayer, &QgsVectorLayer::selectionChanged, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
728 disconnect( vlayer, &QgsVectorLayer::layerModified, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
729 mModelVectorLayers.removeAll( layer );
730 }
731
732 if ( layer->type() == Qgis::LayerType::Mesh )
733 {
734 disconnect( layer, &QgsMapLayer::rendererChanged, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
735 }
736
737 if ( layer->type() == Qgis::LayerType::PointCloud )
738 {
739 QgsPointCloudLayer *pclayer = qobject_cast<QgsPointCloudLayer *>( layer );
740 disconnect( pclayer, &QgsPointCloudLayer::renderer3DChanged, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
741 disconnect( pclayer, &QgsPointCloudLayer::subsetStringChanged, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
742 }
743}
744
745void Qgs3DMapScene::finalizeNewEntity( Qt3DCore::QEntity *newEntity )
746{
747 // set clip planes on the new entity if necessary
748 handleClippingOnEntity( newEntity );
749
750 // this is probably not the best place for material-specific configuration,
751 // maybe this could be more generalized when other materials need some specific treatment
752 const QList< QgsLineMaterial *> childLineMaterials = newEntity->findChildren<QgsLineMaterial *>();
753 for ( QgsLineMaterial *lm : childLineMaterials )
754 {
755 connect( mEngine, &QgsAbstract3DEngine::sizeChanged, lm, [lm, this]
756 {
757 lm->setViewportSize( mEngine->size() );
758 } );
759
760 lm->setViewportSize( mEngine->size() );
761 }
762 // configure billboard's viewport when the viewport is changed.
763 const QList< QgsPoint3DBillboardMaterial *> childBillboardMaterials = newEntity->findChildren<QgsPoint3DBillboardMaterial *>();
764 for ( QgsPoint3DBillboardMaterial *bm : childBillboardMaterials )
765 {
766 connect( mEngine, &QgsAbstract3DEngine::sizeChanged, bm, [bm, this]
767 {
768 bm->setViewportSize( mEngine->size() );
769 } );
770
771 bm->setViewportSize( mEngine->size() );
772 }
773
774 // Finalize adding the 3D transparent objects by adding the layer components to the entities
775 QgsFrameGraph *frameGraph = mEngine->frameGraph();
776 Qt3DRender::QLayer *transparentLayer = frameGraph->transparentObjectLayer();
777 const QList< Qt3DRender::QMaterial *> childMaterials = newEntity->findChildren<Qt3DRender::QMaterial *>();
778 for ( Qt3DRender::QMaterial *material : childMaterials )
779 {
780 // This handles the phong material without data defined properties.
781 if ( Qt3DExtras::QDiffuseSpecularMaterial *ph = qobject_cast<Qt3DExtras::QDiffuseSpecularMaterial *>( material ) )
782 {
783 if ( ph->diffuse().value<QColor>().alphaF() != 1.0f )
784 {
785 Qt3DCore::QEntity *entity = qobject_cast<Qt3DCore::QEntity *>( ph->parent() );
786 if ( entity && !entity->components().contains( transparentLayer ) )
787 {
788 entity->addComponent( transparentLayer );
789 }
790 }
791 }
792 else
793 {
794 // This handles the phong material with data defined properties, the textured case and point (instanced) symbols.
795 Qt3DRender::QEffect *effect = material->effect();
796 if ( effect )
797 {
798 const QVector< Qt3DRender::QParameter *> parameters = effect->parameters();
799 for ( const Qt3DRender::QParameter *parameter : parameters )
800 {
801 if ( parameter->name() == "opacity" && parameter->value() != 1.0f )
802 {
803 Qt3DCore::QEntity *entity = qobject_cast<Qt3DCore::QEntity *>( material->parent() );
804 if ( entity && !entity->components().contains( transparentLayer ) )
805 {
806 entity->addComponent( transparentLayer );
807 }
808 break;
809 }
810 }
811 }
812 }
813 }
814}
815
816int Qgs3DMapScene::maximumTextureSize() const
817{
818 QSurface *surface = mEngine->surface();
819 QOpenGLContext context;
820 context.create();
821 bool success = context.makeCurrent( surface );
822
823 if ( success )
824 {
825 QOpenGLFunctions openglFunctions = QOpenGLFunctions( &context );
826
827 GLint size;
828 openglFunctions.initializeOpenGLFunctions();
829 openglFunctions.glGetIntegerv( GL_MAX_TEXTURE_SIZE, &size );
830 return int( size );
831 }
832 else
833 {
834 return 4096; //we can't have a context to defined the max texture size, we use this reasonable value
835 }
836
837}
838
839void Qgs3DMapScene::addCameraViewCenterEntity( Qt3DRender::QCamera *camera )
840{
841 mEntityCameraViewCenter = new Qt3DCore::QEntity;
842
843 Qt3DCore::QTransform *trCameraViewCenter = new Qt3DCore::QTransform;
844 mEntityCameraViewCenter->addComponent( trCameraViewCenter );
845 connect( camera, &Qt3DRender::QCamera::viewCenterChanged, this, [trCameraViewCenter, camera]
846 {
847 trCameraViewCenter->setTranslation( camera->viewCenter() );
848 } );
849
850 Qt3DExtras::QPhongMaterial *materialCameraViewCenter = new Qt3DExtras::QPhongMaterial;
851 materialCameraViewCenter->setAmbient( Qt::red );
852 mEntityCameraViewCenter->addComponent( materialCameraViewCenter );
853
854 Qt3DExtras::QSphereMesh *rendererCameraViewCenter = new Qt3DExtras::QSphereMesh;
855 rendererCameraViewCenter->setRadius( 10 );
856 mEntityCameraViewCenter->addComponent( rendererCameraViewCenter );
857
858 mEntityCameraViewCenter->setEnabled( mMap.showCameraViewCenter() );
859 mEntityCameraViewCenter->setParent( this );
860
861 connect( &mMap, &Qgs3DMapSettings::showCameraViewCenterChanged, this, [this]
862 {
863 mEntityCameraViewCenter->setEnabled( mMap.showCameraViewCenter() );
864 } );
865}
866
867void Qgs3DMapScene::setSceneState( Qgs3DMapScene::SceneState state )
868{
869 if ( mSceneState == state )
870 return;
871 mSceneState = state;
872 emit sceneStateChanged();
873}
874
875void Qgs3DMapScene::updateSceneState()
876{
877 if ( mTerrainUpdateScheduled )
878 {
879 setSceneState( Updating );
880 return;
881 }
882
883 for ( Qgs3DMapSceneEntity *entity : std::as_const( mSceneEntities ) )
884 {
885 if ( entity->isEnabled() && entity->pendingJobsCount() > 0 )
886 {
887 setSceneState( Updating );
888 return;
889 }
890 }
891
892 setSceneState( Ready );
893}
894
895void Qgs3DMapScene::onSkyboxSettingsChanged()
896{
897 QgsSkyboxSettings skyboxSettings = mMap.skyboxSettings();
898 if ( mSkybox )
899 {
900 mSkybox->deleteLater();
901 mSkybox = nullptr;
902 }
903
904 mEngine->setFrustumCullingEnabled( !mMap.isSkyboxEnabled() );
905
906 if ( mMap.isSkyboxEnabled() )
907 {
908 QMap<QString, QString> faces;
909 switch ( skyboxSettings.skyboxType() )
910 {
912 faces = skyboxSettings.cubeMapFacesPaths();
913 mSkybox = new QgsCubeFacesSkyboxEntity(
914 faces[QStringLiteral( "posX" )], faces[QStringLiteral( "posY" )], faces[QStringLiteral( "posZ" )],
915 faces[QStringLiteral( "negX" )], faces[QStringLiteral( "negY" )], faces[QStringLiteral( "negZ" )],
916 this
917 );
918 break;
920 mSkybox = new QgsPanoramicSkyboxEntity( skyboxSettings.panoramicTexturePath(), this );
921 break;
922 }
923 }
924}
925
926void Qgs3DMapScene::onShadowSettingsChanged()
927{
928 QgsFrameGraph *frameGraph = mEngine->frameGraph();
929
930 const QList< QgsLightSource * > lightSources = mMap.lightSources();
931 QList< QgsDirectionalLightSettings * > directionalLightSources;
932 for ( QgsLightSource *source : lightSources )
933 {
934 if ( source->type() == Qgis::LightSourceType::Directional )
935 {
936 directionalLightSources << qgis::down_cast< QgsDirectionalLightSettings * >( source );
937 }
938 }
939
940 QgsShadowSettings shadowSettings = mMap.shadowSettings();
941 int selectedLight = shadowSettings.selectedDirectionalLight();
942 if ( shadowSettings.renderShadows() && selectedLight >= 0 && selectedLight < directionalLightSources.count() )
943 {
944 frameGraph->setShadowRenderingEnabled( true );
945 frameGraph->setShadowBias( shadowSettings.shadowBias() );
946 frameGraph->setShadowMapResolution( shadowSettings.shadowMapResolution() );
947 QgsDirectionalLightSettings light = *directionalLightSources.at( selectedLight );
948 frameGraph->setupDirectionalLight( light, shadowSettings.maximumShadowRenderingDistance() );
949 }
950 else
951 frameGraph->setShadowRenderingEnabled( false );
952}
953
954void Qgs3DMapScene::onAmbientOcclusionSettingsChanged()
955{
956 QgsFrameGraph *frameGraph = mEngine->frameGraph();
957 QgsAmbientOcclusionSettings ambientOcclusionSettings = mMap.ambientOcclusionSettings();
958 frameGraph->setAmbientOcclusionEnabled( ambientOcclusionSettings.isEnabled() );
959 frameGraph->setAmbientOcclusionRadius( ambientOcclusionSettings.radius() );
960 frameGraph->setAmbientOcclusionIntensity( ambientOcclusionSettings.intensity() );
961 frameGraph->setAmbientOcclusionThreshold( ambientOcclusionSettings.threshold() );
962}
963
964void Qgs3DMapScene::onDebugShadowMapSettingsChanged()
965{
967}
968
969void Qgs3DMapScene::onDebugDepthMapSettingsChanged()
970{
972}
973
974void Qgs3DMapScene::onDebugOverlayEnabledChanged()
975{
977 mEngine->renderSettings()->setRenderPolicy( mMap.isDebugOverlayEnabled() ? Qt3DRender::QRenderSettings::Always : Qt3DRender::QRenderSettings::OnDemand );
978}
979
980void Qgs3DMapScene::onEyeDomeShadingSettingsChanged()
981{
982 bool edlEnabled = mMap.eyeDomeLightingEnabled();
983 double edlStrength = mMap.eyeDomeLightingStrength();
984 double edlDistance = mMap.eyeDomeLightingDistance();
985 mEngine->frameGraph()->setupEyeDomeLighting( edlEnabled, edlStrength, edlDistance );
986}
987
988void Qgs3DMapScene::onCameraMovementSpeedChanged()
989{
990 mCameraController->setCameraMovementSpeed( mMap.cameraMovementSpeed() );
991}
992
993void Qgs3DMapScene::onCameraNavigationModeChanged()
994{
995 mCameraController->setCameraNavigationMode( mMap.cameraNavigationMode() );
996}
997
999{
1000 QVector<QString> notParsedLayers;
1001 Qgs3DSceneExporter exporter;
1002
1003 exporter.setTerrainResolution( exportSettings.terrrainResolution() );
1004 exporter.setSmoothEdges( exportSettings.smoothEdges() );
1005 exporter.setExportNormals( exportSettings.exportNormals() );
1006 exporter.setExportTextures( exportSettings.exportTextures() );
1007 exporter.setTerrainTextureResolution( exportSettings.terrainTextureResolution() );
1008 exporter.setScale( exportSettings.scale() );
1009
1010 for ( auto it = mLayerEntities.constBegin(); it != mLayerEntities.constEnd(); ++it )
1011 {
1012 QgsMapLayer *layer = it.key();
1013 Qt3DCore::QEntity *rootEntity = it.value();
1014 Qgis::LayerType layerType = layer->type();
1015 switch ( layerType )
1016 {
1018 if ( !exporter.parseVectorLayerEntity( rootEntity, qobject_cast<QgsVectorLayer *>( layer ) ) )
1019 notParsedLayers.push_back( layer->name() );
1020 break;
1029 notParsedLayers.push_back( layer->name() );
1030 break;
1031 }
1032 }
1033
1034 if ( mTerrain )
1035 exporter.parseTerrain( mTerrain, "Terrain" );
1036
1037 exporter.save( exportSettings.sceneName(), exportSettings.sceneFolderPath() );
1038
1039 if ( !notParsedLayers.empty() )
1040 {
1041 QString message = tr( "The following layers were not exported:" ) + "\n";
1042 for ( const QString &layerName : notParsedLayers )
1043 message += layerName + "\n";
1044 QgsMessageOutput::showMessage( tr( "3D exporter warning" ), message, QgsMessageOutput::MessageText );
1045 }
1046}
1047
1048QVector<const QgsChunkNode *> Qgs3DMapScene::getLayerActiveChunkNodes( QgsMapLayer *layer )
1049{
1050 QVector<const QgsChunkNode *> chunks;
1051 if ( !mLayerEntities.contains( layer ) ) return chunks;
1052 if ( QgsChunkedEntity *c = qobject_cast<QgsChunkedEntity *>( mLayerEntities[ layer ] ) )
1053 {
1054 const QList< QgsChunkNode * > activeNodes = c->activeNodes();
1055 for ( QgsChunkNode *n : activeNodes )
1056 chunks.push_back( n );
1057 }
1058 return chunks;
1059}
1060
1062{
1063 return mMap.extent();
1064}
1065
1067{
1068 double yMin = std::numeric_limits< double >::max();
1069 double yMax = std::numeric_limits< double >::lowest();
1070 if ( mMap.terrainRenderingEnabled() && mTerrain )
1071 {
1072 const QgsAABB bbox = mTerrain->rootNode()->bbox();
1073 yMin = std::min( yMin, static_cast< double >( bbox.yMin ) );
1074 yMax = std::max( yMax, static_cast< double >( bbox.yMax ) );
1075 }
1076
1077 for ( auto it = mLayerEntities.constBegin(); it != mLayerEntities.constEnd(); it++ )
1078 {
1079 QgsMapLayer *layer = it.key();
1080 switch ( layer->type() )
1081 {
1083 {
1084 QgsPointCloudLayer *pcl = qobject_cast< QgsPointCloudLayer *>( layer );
1085 QgsDoubleRange zRange = pcl->elevationProperties()->calculateZRange( pcl );
1086 yMin = std::min( yMin, zRange.lower() );
1087 yMax = std::max( yMax, zRange.upper() );
1088 break;
1089 }
1091 {
1092 QgsMeshLayer *meshLayer = qobject_cast< QgsMeshLayer *>( layer );
1093 QgsAbstract3DRenderer *renderer3D = meshLayer->renderer3D();
1094 if ( renderer3D )
1095 {
1096 QgsMeshLayer3DRenderer *meshLayerRenderer = static_cast<QgsMeshLayer3DRenderer *>( renderer3D );
1097 const int verticalGroupDatasetIndex = meshLayerRenderer->symbol()->verticalDatasetGroupIndex();
1098 const QgsMeshDatasetGroupMetadata verticalGroupMetadata = meshLayer->datasetGroupMetadata( verticalGroupDatasetIndex );
1099 const double verticalScale = meshLayerRenderer->symbol()->verticalScale();
1100 yMin = std::min( yMin, verticalGroupMetadata.minimum() * verticalScale );
1101 yMax = std::max( yMax, verticalGroupMetadata.maximum() * verticalScale );
1102 }
1103 break;
1104 }
1106 {
1107 QgsTiledSceneLayer *sceneLayer = qobject_cast< QgsTiledSceneLayer *>( layer );
1108 const QgsDoubleRange zRange = sceneLayer->elevationProperties()->calculateZRange( sceneLayer );
1109 if ( !zRange.isInfinite() && !zRange.isEmpty() )
1110 {
1111 yMin = std::min( yMin, zRange.lower() );
1112 yMax = std::max( yMax, zRange.upper() );
1113 }
1114 break;
1115 }
1122 break;
1123 }
1124 }
1125 const QgsDoubleRange yRange( std::min( yMin, std::numeric_limits<double>::max() ),
1126 std::max( yMax, std::numeric_limits<double>::lowest() ) );
1127 return yRange.isEmpty() ? QgsDoubleRange() : yRange;
1128}
1129
1130QMap< QString, Qgs3DMapScene * > Qgs3DMapScene::openScenes()
1131{
1132 return sOpenScenesFunction();
1133}
1134
1135void Qgs3DMapScene::addCameraRotationCenterEntity( QgsCameraController *controller )
1136{
1137 mEntityRotationCenter = new Qt3DCore::QEntity;
1138
1139 Qt3DCore::QTransform *trRotationCenter = new Qt3DCore::QTransform;
1140 mEntityRotationCenter->addComponent( trRotationCenter );
1141 Qt3DExtras::QPhongMaterial *materialRotationCenter = new Qt3DExtras::QPhongMaterial;
1142 materialRotationCenter->setAmbient( Qt::blue );
1143 mEntityRotationCenter->addComponent( materialRotationCenter );
1144 Qt3DExtras::QSphereMesh *rendererRotationCenter = new Qt3DExtras::QSphereMesh;
1145 rendererRotationCenter->setRadius( 10 );
1146 mEntityRotationCenter->addComponent( rendererRotationCenter );
1147 mEntityRotationCenter->setEnabled( false );
1148 mEntityRotationCenter->setParent( this );
1149
1150 connect( controller, &QgsCameraController::cameraRotationCenterChanged, this, [trRotationCenter]( QVector3D center )
1151 {
1152 trRotationCenter->setTranslation( center );
1153 } );
1154
1155 connect( &mMap, &Qgs3DMapSettings::showCameraRotationCenterChanged, this, [this]
1156 {
1157 mEntityRotationCenter->setEnabled( mMap.showCameraRotationCenter() );
1158 } );
1159}
1160
1161void Qgs3DMapScene::on3DAxisSettingsChanged()
1162{
1163 if ( m3DAxis )
1164 {
1165 m3DAxis->onAxisSettingsChanged();
1166 }
1167 else
1168 {
1169 if ( QgsWindow3DEngine *engine = dynamic_cast<QgsWindow3DEngine *>( mEngine ) )
1170 {
1171 m3DAxis = new Qgs3DAxis( static_cast<Qgs3DMapCanvas *>( engine->window() ),
1172 engine->root(),
1173 this,
1174 mCameraController,
1175 &mMap );
1176 }
1177 }
1178}
1179
1180void Qgs3DMapScene::handleClippingOnEntity( QEntity *entity ) const
1181{
1182 if ( mClipPlanesEquations.isEmpty() ) // no clip plane equations, disable clipping
1183 {
1184 for ( QgsMaterial *material : entity->componentsOfType<QgsMaterial>() )
1185 {
1186 material->disableClipping();
1187 }
1188 }
1189 else // enable clipping
1190 {
1191 for ( QgsMaterial *material : entity->componentsOfType<QgsMaterial>() )
1192 {
1193 material->enableClipping( mClipPlanesEquations );
1194 }
1195 }
1196
1197 // recursive call
1198 // enable or disable clipping on the children accordingly
1199 for ( QObject *child : entity->children() )
1200 {
1201 Qt3DCore::QEntity *childEntity = qobject_cast<Qt3DCore::QEntity *>( child );
1202 if ( childEntity )
1203 {
1204 handleClippingOnEntity( childEntity );
1205 }
1206 }
1207}
1208
1209void Qgs3DMapScene::handleClippingOnAllEntities() const
1210{
1211 // Need to loop mLayerEntities instead of mSceneEntities to handle entities
1212 // which do no inherit from Qgs3DMapSceneEntity. For example, mesh entities.
1213 for ( auto it = mLayerEntities.constBegin(); it != mLayerEntities.constEnd(); ++it )
1214 {
1215 handleClippingOnEntity( it.value() );
1216 }
1217 if ( mTerrain )
1218 {
1219 handleClippingOnEntity( mTerrain );
1220 }
1221}
1222
1223void Qgs3DMapScene::enableClipping( const QList<QVector4D> &clipPlaneEquations )
1224{
1225 if ( clipPlaneEquations.size() > 8 )
1226 {
1227 QgsDebugMsgLevel( QStringLiteral( "Qgs3DMapScene::enableClipping: it is not possible to use more than 8 clipping planes." ), 2 );
1228 }
1229 mClipPlanesEquations = clipPlaneEquations.mid( 0, 8 );
1230
1231 // enable the clip planes on the framegraph
1232 QgsFrameGraph *frameGraph = mEngine->frameGraph();
1233 frameGraph->addClipPlanes( clipPlaneEquations.size() );
1234
1235 // Enable the clip planes for the material of each entity.
1236 handleClippingOnAllEntities();
1237}
1238
1240{
1241 mClipPlanesEquations.clear();
1242
1243 // disable the clip planes on the framegraph
1244 QgsFrameGraph *frameGraph = mEngine->frameGraph();
1245 frameGraph->removeClipPlanes();
1246
1247 // Disable the clip planes for the material of each entity.
1248 handleClippingOnAllEntities();
1249}
LayerType
Types of layers that can be added to a map.
Definition qgis.h:169
@ Group
Composite group layer. Added in QGIS 3.24.
@ Plugin
Plugin based layer.
@ TiledScene
Tiled scene layer. Added in QGIS 3.34.
@ Annotation
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
@ Vector
Vector layer.
@ VectorTile
Vector tile layer. Added in QGIS 3.14.
@ Mesh
Mesh layer. Added in QGIS 3.2.
@ Raster
Raster layer.
@ PointCloud
Point cloud layer. Added in QGIS 3.18.
@ Directional
Directional light source.
void onAxisSettingsChanged()
Force update of the axis and the viewport when a setting has changed.
Manages the various settings the user can choose from when exporting a 3D scene 3.
bool exportNormals() const
Returns whether normals will be exported.
int terrrainResolution() const
Returns the terrain resolution.
QString sceneFolderPath() const
Returns the scene folder path.
float scale() const
Returns the scale of the exported model.
int terrainTextureResolution() const
Returns the terrain texture resolution.
QString sceneName() const
Returns the scene name.
bool smoothEdges() const
Returns whether triangles edges will look smooth.
bool exportTextures() const
Returns whether textures will be exported.
QVector< const QgsChunkNode * > getLayerActiveChunkNodes(QgsMapLayer *layer)
Returns the active chunk nodes of layer.
void exportScene(const Qgs3DMapExportSettings &exportSettings)
Exports the scene according to the scene export settings.
void terrainPendingJobsCountChanged()
Emitted when the number of terrain's pending jobs changes.
void viewed2DExtentFrom3DChanged(QVector< QgsPointXY > extent)
Emitted when the viewed 2D extent seen by the 3D camera has changed.
void fpsCountChanged(float fpsCount)
Emitted when the FPS count changes.
void setViewFrom2DExtent(const QgsRectangle &extent)
Resets camera view to show the extent extent (top view)
void disableClipping()
Disables OpenGL clipping.
Qgs3DMapScene(Qgs3DMapSettings &map, QgsAbstract3DEngine *engine)
Constructs a 3D scene based on map settings and Qt 3D renderer configuration.
QgsAbstract3DEngine * engine() const
Returns the abstract 3D engine.
void gpuMemoryLimitReached()
Emitted when one of the entities reaches its GPU memory limit and it is not possible to lower the GPU...
QgsDoubleRange elevationRange() const
Returns the scene's elevation range.
QgsCameraController * cameraController() const
Returns camera controller.
SceneState
Enumeration of possible states of the 3D scene.
@ Ready
The scene is fully loaded/updated.
@ Updating
The scene is still being loaded/updated.
int totalPendingJobsCount() const
Returns number of pending jobs for all chunked entities.
void updateTemporal()
Updates the temporale entities.
static Q_DECL_DEPRECATED QMap< QString, Qgs3DMapScene * > openScenes()
Returns a map of 3D map scenes (by name) open in the QGIS application.
void totalPendingJobsCountChanged()
Emitted when the total number of pending jobs changes.
void fpsCounterEnabledChanged(bool fpsCounterEnabled)
Emitted when the FPS counter is activated or deactivated.
QgsRectangle sceneExtent() const
Returns the scene extent in the map's CRS.
void sceneStateChanged()
Emitted when the scene's state has changed.
int terrainPendingJobsCount() const
Returns number of pending jobs of the terrain entity.
QList< QgsMapLayer * > layers() const
Returns the layers that contain chunked entities.
QVector< QgsPointXY > viewFrustum2DExtent() const
Calculates the 2D extent viewed by the 3D camera as the vertices of the viewed trapezoid.
void enableClipping(const QList< QVector4D > &clipPlaneEquations)
Enables OpenGL clipping based on the planes equations defined in clipPlaneEquations.
float worldSpaceError(float epsilon, float distance) const
Given screen error (in pixels) and distance from camera (in 3D world coordinates),...
void terrainEntityChanged()
Emitted when the current terrain entity is replaced by a new one.
static std::function< QMap< QString, Qgs3DMapScene * >() > sOpenScenesFunction
Static function for returning open 3D map scenes.
void viewZoomFull()
Resets camera view to show the whole scene (top view)
void extentChanged()
Emitted when the 3d view's 2d extent has changed.
void mapTileResolutionChanged()
Emitted when the map tile resoulution has changed.
void terrainVerticalScaleChanged()
Emitted when the vertical scale of the terrain has changed.
bool isDebugOverlayEnabled() const
Returns whether debug overlay is enabled.
Qt::Corner debugDepthMapCorner() const
Returns the corner where the shadow map preview is displayed.
void eyeDomeLightingDistanceChanged()
Emitted when the eye dome lighting distance has changed.
void terrainShadingChanged()
Emitted when terrain shading enabled flag or terrain shading material has changed.
QgsVector3D mapToWorldCoordinates(const QgsVector3D &mapCoords) const
Converts map coordinates to 3D world coordinates (applies offset and turns (x,y,z) into (x,...
double cameraMovementSpeed() const
Returns the camera movement speed.
Qt3DRender::QCameraLens::ProjectionType projectionType() const
Returns the camera lens' projection type.
bool debugDepthMapEnabled() const
Returns whether the shadow map debugging is enabled.
bool isSkyboxEnabled() const
Returns whether the skybox is enabled.
void debugDepthMapSettingsChanged()
Emitted when depth map debugging has changed.
Qgis::NavigationMode cameraNavigationMode() const
Returns the navigation mode used by the camera.
double eyeDomeLightingStrength() const
Returns the eye dome lighting strength value.
void backgroundColorChanged()
Emitted when the background color has changed.
Qt::Corner debugShadowMapCorner() const
Returns the corner where the shadow map preview is displayed.
bool showCameraViewCenter() const
Returns whether to show camera's view center as a sphere (for debugging)
void showCameraRotationCenterChanged()
Emitted when the flag whether camera's rotation center is shown has changed.
void cameraNavigationModeChanged()
Emitted when the camera navigation mode was changed.
void shadowSettingsChanged()
Emitted when shadow rendering settings are changed.
float maxTerrainGroundError() const
Returns maximum ground error of terrain tiles in world units.
void eyeDomeLightingEnabledChanged()
Emitted when the flag whether eye dome lighting is used has changed.
void debugOverlayEnabledChanged(bool debugOverlayEnabled)
Emitted when the debug overaly is enabled or disabled.
void skyboxSettingsChanged()
Emitted when skybox settings are changed.
QgsShadowSettings shadowSettings() const
Returns the current configuration of shadows.
QList< QgsLightSource * > lightSources() const
Returns list of directional light sources defined in the scene.
double debugDepthMapSize() const
Returns the size of the shadow map preview.
void projectionTypeChanged()
Emitted when the camera lens projection type changes.
float fieldOfView() const
Returns the camera lens' field of view.
QgsAmbientOcclusionSettings ambientOcclusionSettings() const
Returns the current configuration of screen space ambient occlusion.
QgsRectangle extent() const
Returns the 3D scene's 2D extent in the 3D scene's CRS.
int eyeDomeLightingDistance() const
Returns the eye dome lighting distance value (contributes to the contrast of the image)
void lightSourcesChanged()
Emitted when any of the light source settings in the map changes.
void showLightSourceOriginsChanged()
Emitted when the flag whether light source origins are shown has changed.
QgsTerrainGenerator * terrainGenerator() const
Returns the terrain generator.
QColor backgroundColor() const
Returns background color of the 3D map view.
double debugShadowMapSize() const
Returns the size of the shadow map preview.
QgsVector3D worldToMapCoordinates(const QgsVector3D &worldCoords) const
Converts 3D world coordinates to map coordinates (applies offset and turns (x,y,z) into (x,...
bool showTerrainBoundingBoxes() const
Returns whether to display bounding boxes of terrain tiles (for debugging)
void maxTerrainScreenErrorChanged()
Emitted when the maximum terrain screen error has changed.
int mapTileResolution() const
Returns resolution (in pixels) of the texture of a terrain tile.
bool debugShadowMapEnabled() const
Returns whether the shadow map debugging is enabled.
bool terrainRenderingEnabled() const
Returns whether the 2D terrain surface will be rendered.
void fpsCounterEnabledChanged(bool fpsCounterEnabled)
Emitted when the FPS counter is enabled or disabled.
void axisSettingsChanged()
Emitted when 3d axis rendering settings are changed.
void ambientOcclusionSettingsChanged()
Emitted when ambient occlusion rendering settings are changed.
void layersChanged()
Emitted when the list of map layers for 3d rendering has changed.
void eyeDomeLightingStrengthChanged()
Emitted when the eye dome lighting strength has changed.
QgsSkyboxSettings skyboxSettings() const
Returns the current configuration of the skybox.
void cameraMovementSpeedChanged()
Emitted when the camera movement speed was changed.
bool eyeDomeLightingEnabled() const
Returns whether eye dome lighting is used.
bool isFpsCounterEnabled() const
Returns whether FPS counter label is enabled.
void fieldOfViewChanged()
Emitted when the camera lens field of view changes.
QList< QgsMapLayer * > layers() const
Returns the list of 3D map layers to be rendered in the scene.
void terrainGeneratorChanged()
Emitted when the terrain generator has changed.
void debugShadowMapSettingsChanged()
Emitted when shadow map debugging has changed.
void showCameraViewCenterChanged()
Emitted when the flag whether camera's view center is shown has changed.
void maxTerrainGroundErrorChanged()
Emitted when the maximum terrain ground error has changed.
QgsVector3D origin() const
Returns coordinates in map CRS at which 3D scene has origin (0,0,0).
bool showCameraRotationCenter() const
Returns whether to show camera's rotation center as a sphere (for debugging)
Entity that handles the exporting of 3D scene.
void save(const QString &sceneName, const QString &sceneFolderPath, int precision=6)
Saves the scene to a .obj file.
void setExportTextures(bool exportTextures)
Sets whether the textures will be exported.
void parseTerrain(QgsTerrainEntity *terrain, const QString &layer)
Creates terrain export objects from the terrain entity.
void setTerrainResolution(int resolution)
Sets the terrain resolution.
void setTerrainTextureResolution(int resolution)
Sets the terrain texture resolution.
bool parseVectorLayerEntity(Qt3DCore::QEntity *entity, QgsVectorLayer *layer)
Creates necessary export objects from entity if it represents valid vector layer entity Returns false...
void setScale(float scale)
Sets the scale of the exported 3D model.
void setExportNormals(bool exportNormals)
Sets whether the normals will be exported.
void setSmoothEdges(bool smoothEdges)
Sets whether the triangles will look smooth.
static int maxZoomLevel(double tile0width, double tileResolution, double maxError)
Calculates the highest needed zoom level for tiles in quad-tree given width of the base tile (zoom le...
static QgsAABB mapToWorldExtent(const QgsRectangle &extent, double zMin, double zMax, const QgsVector3D &mapOrigin)
Converts map extent to axis aligned bounding box in 3D world coordinates.
static void computeBoundingBoxNearFarPlanes(const QgsAABB &bbox, const QMatrix4x4 &viewMatrix, float &fnear, float &ffar)
This routine computes nearPlane farPlane from the closest and farthest corners point of bounding box ...
static QgsRay3D rayFromScreenPoint(const QPoint &point, const QSize &windowSize, Qt3DRender::QCamera *camera)
Convert from clicked point on the screen to a ray in world coordinates.
float yMax
Definition qgsaabb.h:90
float zMax
Definition qgsaabb.h:91
float yMin
Definition qgsaabb.h:87
float zMin
Definition qgsaabb.h:88
void sizeChanged()
Emitted after a call to setSize()
virtual QSurface * surface() const =0
Returns the surface of the engine.
virtual Qt3DRender::QCamera * camera()=0
Returns pointer to the engine's camera entity.
virtual void setClearColor(const QColor &color)=0
Sets background color of the scene.
virtual void setFrustumCullingEnabled(bool enabled)=0
Sets whether frustum culling is enabled (this should make rendering faster by not rendering entities ...
QgsFrameGraph * frameGraph()
Returns the shadow rendering frame graph object used to render the scene.
virtual QSize size() const =0
Returns size of the engine's rendering area in pixels.
virtual Qt3DRender::QRenderSettings * renderSettings()=0
Returns access to the engine's render settings (the frame graph can be accessed from here)
Base class for all renderers that may to participate in 3D view.
virtual QString type() const =0
Returns unique identifier of the renderer class (used to identify subclass)
virtual Qt3DCore::QEntity * createEntity(Qgs3DMapSettings *map) const =0
Returns a 3D entity that will be used to show renderer's data in 3D scene.
class containing the configuration of ambient occlusion rendering 3
float radius() const
Returns the radius parameter of the ambient occlusion effect.
bool isEnabled() const
Returns whether ambient occlusion effect is enabled.
float intensity() const
Returns the shading factor of the ambient occlusion effect.
float threshold() const
Returns at what amount of occlusion the effect will kick in.
static QgsSourceCache * sourceCache()
Returns the application's source cache, used for caching embedded and remote source strings as local ...
Qt3DRender::QCamera * camera() const
Returns camera that is being controlled.
float distance() const
Returns distance of the camera from the point it is looking at.
void setCameraNavigationMode(Qgis::NavigationMode navigationMode)
Sets the navigation mode used by the camera controller.
void cameraChanged()
Emitted when camera has been updated.
void frameTriggered(float dt)
Called internally from 3D scene when a new frame is generated. Updates camera according to keyboard/m...
void resetView(float distance)
Move camera back to the initial position (looking down towards origin of world's coordinates)
void setViewFromTop(float worldX, float worldY, float distance, float yaw=0)
Sets camera to look down towards given point in world coordinate, in given distance from plane with z...
void setCameraMovementSpeed(double movementSpeed)
Sets the camera movement speed.
void cameraRotationCenterChanged(QVector3D position)
Emitted when the camera rotation center changes.
A skybox constructed from a 6 cube faces.
QgsRange which stores a range of double values.
Definition qgsrange.h:231
bool isInfinite() const
Returns true if the range consists of all possible values.
Definition qgsrange.h:285
void addClipPlanes(int nrClipPlanes)
Setups nrClipPlanes clip planes in the forward pass to enable OpenGL clipping.
void removeClipPlanes()
Disables OpenGL clipping.
void setShadowBias(float shadowBias)
Sets the shadow bias value.
void setupShadowMapDebugging(bool enabled, Qt::Corner corner, double size)
Sets the shadow map debugging view port.
void setShadowMapResolution(int resolution)
Sets the resolution of the shadow map.
void setAmbientOcclusionIntensity(float intensity)
Sets the ambient occlusion intensity.
Qt3DRender::QLayer * transparentObjectLayer()
Returns a layer object used to indicate that the object is transparent.
void setDebugOverlayEnabled(bool enabled)
Sets whether debug overlay is enabled.
void setShadowRenderingEnabled(bool enabled)
Sets whether the shadow rendering is enabled.
void setupDepthMapDebugging(bool enabled, Qt::Corner corner, double size)
Sets the depth map debugging view port.
void setupDirectionalLight(const QgsDirectionalLightSettings &light, float maximumShadowRenderingDistance)
Sets shadow rendering to use a directional light.
void setAmbientOcclusionThreshold(float threshold)
Sets the ambient occlusion threshold.
void setupEyeDomeLighting(bool enabled, double strength, int distance)
Sets eye dome lighting shading related settings.
void setAmbientOcclusionEnabled(bool enabled)
Sets whether Screen Space Ambient Occlusion will be enabled.
void setAmbientOcclusionRadius(float radius)
Sets the ambient occlusion radius.
virtual QgsDoubleRange calculateZRange(QgsMapLayer *layer) const
Attempts to calculate the overall elevation or z range for the specified layer, using the settings de...
Base class for storage of map layer temporal properties.
Base class for all map layer types.
Definition qgsmaplayer.h:76
QString name
Definition qgsmaplayer.h:80
QgsAbstract3DRenderer * renderer3D() const
Returns 3D renderer associated with the layer.
void request3DUpdate()
Signal emitted when a layer requires an update in any 3D maps.
void renderer3DChanged()
Signal emitted when 3D renderer associated with the layer has changed.
Qgis::LayerType type
Definition qgsmaplayer.h:86
void rendererChanged()
Signal emitted when renderer is changed.
virtual QgsMapLayerTemporalProperties * temporalProperties()
Returns the layer's temporal properties.
void layerModified()
Emitted when modifications has been done on layer.
double verticalScale() const
Returns mesh vertical scale.
int verticalDatasetGroupIndex() const
Returns the index of the dataset group that will be used to render the vertical component of the 3D m...
void setMaximumTextureSize(int maximumTextureSize)
Sets the maximum texture size supported by the hardware Used to store the GL_MAX_TEXTURE_SIZE value t...
QgsMesh3DSymbol * clone() const override SIP_FACTORY
Returns a new instance of the symbol with the same settings.
QgsMeshDatasetGroupMetadata is a collection of dataset group metadata such as whether the data is vec...
double minimum() const
Returns minimum scalar value/vector magnitude present for whole dataset group.
double maximum() const
Returns maximum scalar value/vector magnitude present for whole dataset group.
3D renderer that renders all mesh triangles of a mesh layer.
void setSymbol(QgsMesh3DSymbol *symbol)
Sets 3D symbol associated with the renderer.
const QgsMesh3DSymbol * symbol() const
Returns 3D symbol associated with the renderer.
void setLayer(QgsMeshLayer *layer)
Sets vector layer associated with the renderer.
Represents a mesh layer supporting display of data on structured or unstructured meshes.
QgsMeshDatasetGroupMetadata datasetGroupMetadata(const QgsMeshDatasetIndex &index) const
Returns the dataset groups metadata.
virtual void showMessage(bool blocking=true)=0
display the message to the user and deletes itself
A skybox constructed from a panoramic image.
void setViewportSize(const QSizeF size)
Set the size of the view port.
Qgis::Point3DShape shape() const
Returns 3D shape for points.
QVariant shapeProperty(const QString &property) const
Returns the value for a specific shape property.
3D renderer that renders all points from a point cloud layer
void setLayer(QgsPointCloudLayer *layer)
Sets point cloud layer associated with the renderer.
Represents a map layer supporting display of point clouds.
QgsMapLayerElevationProperties * elevationProperties() override
Returns the layer's elevation properties.
void subsetStringChanged()
Emitted when the layer's subset string has changed.
A class to represent a 2D point.
Definition qgspointxy.h:60
double y
Definition qgspointxy.h:64
double x
Definition qgspointxy.h:63
A template based class for storing ranges (lower to upper values).
Definition qgsrange.h:46
T lower() const
Returns the lower bound of the range.
Definition qgsrange.h:78
T upper() const
Returns the upper bound of the range.
Definition qgsrange.h:85
bool isEmpty() const
Returns true if the range is empty, ie the lower bound equals (or exceeds) the upper bound and either...
Definition qgsrange.h:125
A representation of a ray in 3D.
Definition qgsray3d.h:31
A rectangle specified with double values.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
double width() const
Returns the width of the rectangle.
double xMaximum() const
Returns the x maximum value (right side of rectangle).
double yMaximum() const
Returns the y maximum value (top side of rectangle).
QgsPointXY center() const
Returns the center point of the rectangle.
double height() const
Returns the height of the rectangle.
QList< QgsRuleBased3DRenderer::Rule * > RuleList
class containing the configuration of shadows rendering 3
int selectedDirectionalLight() const
Returns the selected direcctional light used to cast shadows.
bool renderShadows() const
Returns whether shadow rendering is enabled.
int shadowMapResolution() const
Returns the resolution of the shadow map texture used to generate the shadows.
double maximumShadowRenderingDistance() const
Returns the maximum shadow rendering distance accounted for when rendering shadows Objects further aw...
double shadowBias() const
Returns the shadow bias used to correct the numerical imprecision of shadows (for the depth test) Thi...
Contains the configuration of a skybox entity.
QMap< QString, QString > cubeMapFacesPaths() const
Returns a map containing the path of each texture specified by the user.
QgsSkyboxEntity::SkyboxType skyboxType() const
Returns the type of the skybox.
QString panoramicTexturePath() const
Returns the panoramic texture path of a skybox of type "Panormaic skybox".
void remoteSourceFetched(const QString &url)
Emitted when the cache has finished retrieving a 3D model from a remote url.
virtual float rootChunkError(const Qgs3DMapSettings &map) const
Returns error of the root chunk in world coordinates.
virtual QgsAABB rootChunkBbox(const Qgs3DMapSettings &map) const
Returns bounding box of the root chunk.
virtual QgsRectangle rootChunkExtent() const =0
extent of the terrain's root chunk in terrain's CRS
void setLayer(QgsTiledSceneLayer *layer)
Sets tiled scene layer associated with the renderer.
Represents a map layer supporting display of tiled scene objects.
QgsMapLayerElevationProperties * elevationProperties() override
Returns the layer's elevation properties.
Class for storage of 3D vectors similar to QVector3D, with the difference that it uses double precisi...
Definition qgsvector3d.h:31
double y() const
Returns Y coordinate.
Definition qgsvector3d.h:50
double z() const
Returns Z coordinate.
Definition qgsvector3d.h:52
double x() const
Returns X coordinate.
Definition qgsvector3d.h:48
3D renderer that renders all features of a vector layer with the same 3D symbol.
Represents a vector layer which manages a vector based data sets.
Q_INVOKABLE Qgis::GeometryType geometryType() const
Returns point, line or polygon.
void selectionChanged(const QgsFeatureIds &selected, const QgsFeatureIds &deselected, bool clearAndSelect)
Emitted when selection was changed.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
bool qgsFloatNear(float a, float b, float epsilon=4 *FLT_EPSILON)
Compare two floats (but allow some difference)
Definition qgis.h:5928
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:39