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