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