QGIS API Documentation 3.30.0-'s-Hertogenbosch (f186b8efe0)
qgs3dmapscene.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgs3dmapscene.cpp
3 --------------------------------------
4 Date : July 2017
5 Copyright : (C) 2017 by Martin Dobias
6 Email : wonder dot sk at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16#include "qgs3dmapscene.h"
17
18#include <Qt3DRender/QCamera>
19#include <Qt3DRender/QMesh>
20#include <Qt3DRender/QObjectPicker>
21#include <Qt3DRender/QPickEvent>
22#include <Qt3DRender/QPickingSettings>
23#include <Qt3DRender/QPickTriangleEvent>
24#include <Qt3DRender/QRenderSettings>
25#include <Qt3DRender/QSceneLoader>
26#include <Qt3DExtras/QForwardRenderer>
27#include <Qt3DExtras/QPhongMaterial>
28#include <Qt3DExtras/QPhongAlphaMaterial>
29#include <Qt3DExtras/QDiffuseSpecularMaterial>
30#include <Qt3DExtras/QSphereMesh>
31#include <Qt3DLogic/QFrameAction>
32#include <Qt3DRender/QEffect>
33#include <Qt3DRender/QTechnique>
34#include <Qt3DRender/QRenderPass>
35#include <Qt3DRender/QRenderState>
36#include <Qt3DRender/QCullFace>
37#include <Qt3DRender/QDepthTest>
38#include <QSurface>
39#include <QUrl>
40#include <QtMath>
41
42#include <QOpenGLContext>
43#include <QOpenGLFunctions>
44#include <QTimer>
45
46#include "qgs3daxis.h"
47#include "qgslogger.h"
48#include "qgsapplication.h"
49#include "qgsaabb.h"
50#include "qgsabstract3dengine.h"
52#include "qgs3dmapsettings.h"
53#include "qgs3dutils.h"
55#include "qgscameracontroller.h"
56#include "qgschunkedentity_p.h"
57#include "qgschunknode_p.h"
58#include "qgseventtracing.h"
59#include "qgsmeshlayer.h"
61#include "qgspoint3dsymbol.h"
63#include "qgspointcloudlayer.h"
65#include "qgssourcecache.h"
66#include "qgsterrainentity_p.h"
67#include "qgsterraingenerator.h"
69#include "qgsvectorlayer.h"
74#include "qgslinematerial_p.h"
75#include "qgs3dsceneexporter.h"
77#include "qgsmessageoutput.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 // we want precise picking of terrain (also bounding volume picking does not seem to work - not sure why)
101 mEngine->renderSettings()->pickingSettings()->setPickMethod( Qt3DRender::QPickingSettings::TrianglePicking );
102
103 QRect viewportRect( QPoint( 0, 0 ), mEngine->size() );
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::renderersChanged, this, &Qgs3DMapScene::onRenderersChanged );
137 connect( &map, &Qgs3DMapSettings::skyboxSettingsChanged, this, &Qgs3DMapScene::onSkyboxSettingsChanged );
138 connect( &map, &Qgs3DMapSettings::shadowSettingsChanged, this, &Qgs3DMapScene::onShadowSettingsChanged );
139 connect( &map, &Qgs3DMapSettings::ambientOcclusionSettingsChanged, this, &Qgs3DMapScene::onAmbientOcclusionSettingsChanged );
140 connect( &map, &Qgs3DMapSettings::eyeDomeLightingEnabledChanged, this, &Qgs3DMapScene::onEyeDomeShadingSettingsChanged );
141 connect( &map, &Qgs3DMapSettings::eyeDomeLightingStrengthChanged, this, &Qgs3DMapScene::onEyeDomeShadingSettingsChanged );
142 connect( &map, &Qgs3DMapSettings::eyeDomeLightingDistanceChanged, this, &Qgs3DMapScene::onEyeDomeShadingSettingsChanged );
143 connect( &map, &Qgs3DMapSettings::debugShadowMapSettingsChanged, this, &Qgs3DMapScene::onDebugShadowMapSettingsChanged );
144 connect( &map, &Qgs3DMapSettings::debugDepthMapSettingsChanged, this, &Qgs3DMapScene::onDebugDepthMapSettingsChanged );
146 connect( &map, &Qgs3DMapSettings::cameraMovementSpeedChanged, this, &Qgs3DMapScene::onCameraMovementSpeedChanged );
147 connect( &map, &Qgs3DMapSettings::cameraNavigationModeChanged, this, &Qgs3DMapScene::onCameraNavigationModeChanged );
148 connect( &map, &Qgs3DMapSettings::debugOverlayEnabledChanged, this, &Qgs3DMapScene::onDebugOverlayEnabledChanged );
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->shapeProperties()[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->shapeProperties()[QStringLiteral( "model" )].toString() == url )
176 {
177 removeLayerEntity( layer );
178 addLayerEntity( layer );
179 break;
180 }
181 }
182 }
183 }
184 }
185 } );
186
187 // create entities of renderers
188
189 onRenderersChanged();
190
191 // listen to changes of layers in order to add/remove 3D renderer entities
192 connect( &map, &Qgs3DMapSettings::layersChanged, this, &Qgs3DMapScene::onLayersChanged );
193
194 connect( mCameraController, &QgsCameraController::cameraChanged, this, &Qgs3DMapScene::onCameraChanged );
195 connect( mEngine, &QgsAbstract3DEngine::sizeChanged, this, &Qgs3DMapScene::onCameraChanged );
196
197 onSkyboxSettingsChanged();
198
199 // force initial update of chunked entities
200 onCameraChanged();
201 // force initial update of eye dome shading
202 onEyeDomeShadingSettingsChanged();
203 // force initial update of debugging setting of preview quads
204 onDebugShadowMapSettingsChanged();
205 onDebugDepthMapSettingsChanged();
206 // force initial update of ambient occlusion settings
207 onAmbientOcclusionSettingsChanged();
208
209 mCameraController->setCameraNavigationMode( mMap.cameraNavigationMode() );
210 onCameraMovementSpeedChanged();
211
212 on3DAxisSettingsChanged();
213}
214
216{
217 const QgsDoubleRange yRange = elevationRange();
218 const QgsRectangle extent = sceneExtent();
219 const double side = std::max( extent.width(), extent.height() );
220 double d = side / 2 / std::tan( cameraController()->camera()->fieldOfView() / 2 * M_PI / 180 );
221 d += yRange.upper();
222 mCameraController->resetView( static_cast< float >( d ) );
223 return;
224}
225
227{
228 QgsPointXY center = extent.center();
229 QgsVector3D centerWorld = mMap.mapToWorldCoordinates( QVector3D( center.x(), center.y(), 0 ) );
230 QgsVector3D p1 = mMap.mapToWorldCoordinates( QVector3D( extent.xMinimum(), extent.yMinimum(), 0 ) );
231 QgsVector3D p2 = mMap.mapToWorldCoordinates( QVector3D( extent.xMaximum(), extent.yMaximum(), 0 ) );
232
233 float xSide = std::abs( p1.x() - p2.x() );
234 float ySide = std::abs( p1.z() - p2.z() );
235 if ( xSide < ySide )
236 {
237 float fov = 2 * std::atan( std::tan( qDegreesToRadians( cameraController()->camera()->fieldOfView() ) / 2 ) * cameraController()->camera()->aspectRatio() );
238 float r = xSide / 2.0f / std::tan( fov / 2.0f );
239 mCameraController->setViewFromTop( centerWorld.x(), centerWorld.z(), r );
240 }
241 else
242 {
243 float fov = qDegreesToRadians( cameraController()->camera()->fieldOfView() );
244 float r = ySide / 2.0f / std::tan( fov / 2.0f );
245 mCameraController->setViewFromTop( centerWorld.x(), centerWorld.z(), r );
246 }
247}
248
250{
251 Qt3DRender::QCamera *camera = mCameraController->camera();
252 QVector<QgsPointXY> extent;
253 QVector<int> pointsOrder = { 0, 1, 3, 2 };
254 for ( int i : pointsOrder )
255 {
256 const QPoint p( ( ( i >> 0 ) & 1 ) ? 0 : mEngine->size().width(), ( ( i >> 1 ) & 1 ) ? 0 : mEngine->size().height() );
257 QgsRay3D ray = Qgs3DUtils::rayFromScreenPoint( p, mEngine->size(), camera );
258 QVector3D dir = ray.direction();
259 if ( dir.y() == 0.0 )
260 dir.setY( 0.000001 );
261 double t = - ray.origin().y() / dir.y();
262 if ( t < 0 )
263 {
264 // If the projected point is on the back of the camera we choose the farthest point in the front
265 t = camera->farPlane();
266 }
267 else
268 {
269 // If the projected point is on the front of the camera we choose the closest between it and farthest point in the front
270 t = std::min<float>( t, camera->farPlane() );
271 }
272 QVector3D planePoint = ray.origin() + t * dir;
273 QgsVector3D pMap = mMap.worldToMapCoordinates( planePoint );
274 extent.push_back( QgsPointXY( pMap.x(), pMap.y() ) );
275 }
276 return extent;
277}
278
280{
281 return mTerrain ? mTerrain->pendingJobsCount() : 0;
282}
283
285{
286 int count = 0;
287 for ( QgsChunkedEntity *entity : std::as_const( mChunkEntities ) )
288 count += entity->pendingJobsCount();
289 return count;
290}
291
293{
294 if ( mPickHandlers.isEmpty() )
295 {
296 // we need to add object pickers
297 for ( Qt3DCore::QEntity *entity : mLayerEntities )
298 {
299 if ( QgsChunkedEntity *chunkedEntity = qobject_cast<QgsChunkedEntity *>( entity ) )
300 chunkedEntity->setPickingEnabled( true );
301 }
302 }
303
304 mPickHandlers.append( pickHandler );
305}
306
308{
309 mPickHandlers.removeOne( pickHandler );
310
311 if ( mPickHandlers.isEmpty() )
312 {
313 // we need to remove pickers
314 for ( Qt3DCore::QEntity *entity : mLayerEntities )
315 {
316 if ( QgsChunkedEntity *chunkedEntity = qobject_cast<QgsChunkedEntity *>( entity ) )
317 chunkedEntity->setPickingEnabled( false );
318 }
319 }
320}
321
322void Qgs3DMapScene::onLayerEntityPickedObject( Qt3DRender::QPickEvent *pickEvent, QgsFeatureId fid )
323{
324 QgsMapLayer *layer = mLayerEntities.key( qobject_cast<QgsChunkedEntity *>( sender() ) );
325 if ( !layer )
326 return;
327
328 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
329 if ( !vlayer )
330 return;
331
332 for ( Qgs3DMapScenePickHandler *pickHandler : std::as_const( mPickHandlers ) )
333 {
334 pickHandler->handlePickOnVectorLayer( vlayer, fid, pickEvent->worldIntersection(), pickEvent );
335 }
336}
337
338float Qgs3DMapScene::worldSpaceError( float epsilon, float distance )
339{
340 Qt3DRender::QCamera *camera = mCameraController->camera();
341 float fov = camera->fieldOfView();
342 const QSize size = mEngine->size();
343 float screenSizePx = std::max( size.width(), size.height() ); // TODO: is this correct?
344
345 // in qgschunkedentity_p.cpp there is inverse calculation (world space error to screen space error)
346 // with explanation of the math.
347 float frustumWidthAtDistance = 2 * distance * tan( fov / 2 );
348 float err = frustumWidthAtDistance * epsilon / screenSizePx;
349 return err;
350}
351
352QgsChunkedEntity::SceneState sceneState_( QgsAbstract3DEngine *engine )
353{
354 Qt3DRender::QCamera *camera = engine->camera();
355 QgsChunkedEntity::SceneState state;
356 state.cameraFov = camera->fieldOfView();
357 state.cameraPos = camera->position();
358 const QSize size = engine->size();
359 state.screenSizePx = std::max( size.width(), size.height() ); // TODO: is this correct?
360 state.viewProjectionMatrix = camera->projectionMatrix() * camera->viewMatrix();
361 return state;
362}
363
364void Qgs3DMapScene::onCameraChanged()
365{
366 if ( mMap.projectionType() == Qt3DRender::QCameraLens::OrthographicProjection )
367 {
368 QRect viewportRect( QPoint( 0, 0 ), mEngine->size() );
369 const float viewWidthFromCenter = mCameraController->distance();
370 const float viewHeightFromCenter = viewportRect.height() * viewWidthFromCenter / viewportRect.width();
371 mEngine->camera()->lens()->setOrthographicProjection( -viewWidthFromCenter, viewWidthFromCenter, -viewHeightFromCenter, viewHeightFromCenter, mEngine->camera()->nearPlane(), mEngine->camera()->farPlane() );
372 }
373
374 updateScene();
375 bool changedCameraPlanes = updateCameraNearFarPlanes();
376
377 if ( changedCameraPlanes )
378 {
379 // repeat update of entities - because we have updated camera's near/far planes,
380 // the active nodes may have changed as well
381 updateScene();
382 updateCameraNearFarPlanes();
383 }
384
385 onShadowSettingsChanged();
386
387 QVector<QgsPointXY> extent2D = viewFrustum2DExtent();
388 emit viewed2DExtentFrom3DChanged( extent2D );
389}
390
391void removeQLayerComponentsFromHierarchy( Qt3DCore::QEntity *entity )
392{
393 QVector<Qt3DCore::QComponent *> toBeRemovedComponents;
394 for ( Qt3DCore::QComponent *component : entity->components() )
395 {
396 Qt3DRender::QLayer *layer = qobject_cast<Qt3DRender::QLayer *>( component );
397 if ( layer != nullptr )
398 toBeRemovedComponents.push_back( layer );
399 }
400 for ( Qt3DCore::QComponent *component : toBeRemovedComponents )
401 entity->removeComponent( component );
402 for ( Qt3DCore::QEntity *obj : entity->findChildren<Qt3DCore::QEntity *>() )
403 {
404 if ( obj != nullptr )
406 }
407}
408
409void addQLayerComponentsToHierarchy( Qt3DCore::QEntity *entity, const QVector<Qt3DRender::QLayer *> &layers )
410{
411 for ( Qt3DRender::QLayer *layer : layers )
412 entity->addComponent( layer );
413 for ( Qt3DCore::QEntity *child : entity->findChildren<Qt3DCore::QEntity *>() )
414 {
415 if ( child != nullptr )
416 addQLayerComponentsToHierarchy( child, layers );
417 }
418}
419
420void Qgs3DMapScene::updateScene()
421{
422 QgsEventTracing::addEvent( QgsEventTracing::Instant, QStringLiteral( "3D" ), QStringLiteral( "Update Scene" ) );
423 for ( QgsChunkedEntity *entity : std::as_const( mChunkEntities ) )
424 {
425 if ( entity->isEnabled() )
426 entity->update( sceneState_( mEngine ) );
427 }
428 updateSceneState();
429}
430
431static void _updateNearFarPlane( const QList<QgsChunkNode *> &activeNodes, const QMatrix4x4 &viewMatrix, float &fnear, float &ffar )
432{
433 for ( QgsChunkNode *node : activeNodes )
434 {
435 // project each corner of bbox to camera coordinates
436 // and determine closest and farthest point.
437 QgsAABB bbox = node->bbox();
438 for ( int i = 0; i < 8; ++i )
439 {
440 QVector4D p( ( ( i >> 0 ) & 1 ) ? bbox.xMin : bbox.xMax,
441 ( ( i >> 1 ) & 1 ) ? bbox.yMin : bbox.yMax,
442 ( ( i >> 2 ) & 1 ) ? bbox.zMin : bbox.zMax, 1 );
443
444 QVector4D pc = viewMatrix * p;
445
446
447 float dst = -pc.z(); // in camera coordinates, x grows right, y grows down, z grows to the back
448 fnear = std::min( fnear, dst );
449 ffar = std::max( ffar, dst );
450 }
451 }
452}
453
454bool Qgs3DMapScene::updateCameraNearFarPlanes()
455{
456 // Update near and far plane from the terrain.
457 // this needs to be done with great care as we have kind of circular dependency here:
458 // active nodes are culled based on the current frustum (which involves near + far plane)
459 // and then based on active nodes we set near and far plane.
460 //
461 // All of this is just heuristics assuming that all other stuff is being rendered somewhere
462 // around the area where the terrain is.
463 //
464 // Near/far plane is setup in order to make best use of the depth buffer to avoid:
465 // 1. precision errors - if the range is too great
466 // 2. unwanted clipping of scene - if the range is too small
467
468 Qt3DRender::QCamera *camera = cameraController()->camera();
469 QMatrix4x4 viewMatrix = camera->viewMatrix();
470 float fnear = 1e9;
471 float ffar = 0;
472 QList<QgsChunkNode *> activeNodes;
473 if ( mTerrain )
474 activeNodes = mTerrain->activeNodes();
475
476 // it could be that there are no active nodes - they could be all culled or because root node
477 // is not yet loaded - we still need at least something to understand bounds of our scene
478 // so lets use the root node
479 if ( mTerrain && activeNodes.isEmpty() )
480 activeNodes << mTerrain->rootNode();
481
482 _updateNearFarPlane( activeNodes, viewMatrix, fnear, ffar );
483
484 // Also involve all the other chunked entities to make sure that they will not get
485 // clipped by the near or far plane
486 for ( QgsChunkedEntity *e : std::as_const( mChunkEntities ) )
487 {
488 if ( e != mTerrain )
489 {
490 QList<QgsChunkNode *> activeEntityNodes = e->activeNodes();
491 if ( activeEntityNodes.empty() )
492 activeEntityNodes << e->rootNode();
493 _updateNearFarPlane( activeEntityNodes, viewMatrix, fnear, ffar );
494 }
495 }
496
497 if ( fnear < 1 )
498 fnear = 1; // does not really make sense to use negative far plane (behind camera)
499
500 // when zooming in a lot, fnear can become smaller than ffar. This should not happen
501 if ( fnear > ffar )
502 std::swap( fnear, ffar );
503
504 if ( fnear == 1e9 && ffar == 0 )
505 {
506 // the update didn't work out... this should not happen
507 // well at least temporarily use some conservative starting values
508 qWarning() << "oops... this should not happen! couldn't determine near/far plane. defaulting to 1...1e9";
509 fnear = 1;
510 ffar = 1e9;
511 }
512
513 // set near/far plane - with some tolerance in front/behind expected near/far planes
514 float newFar = ffar * 2;
515 float newNear = fnear / 2;
516 if ( !qgsFloatNear( newFar, camera->farPlane() ) || !qgsFloatNear( newNear, camera->nearPlane() ) )
517 {
518 camera->setFarPlane( newFar );
519 camera->setNearPlane( newNear );
520 return true;
521 }
522
523 return false;
524}
525
526void Qgs3DMapScene::onFrameTriggered( float dt )
527{
528 mCameraController->frameTriggered( dt );
529
530 for ( QgsChunkedEntity *entity : std::as_const( mChunkEntities ) )
531 {
532 if ( entity->isEnabled() && entity->needsUpdate() )
533 {
534 QgsDebugMsgLevel( QStringLiteral( "need for update" ), 2 );
535 entity->update( sceneState_( mEngine ) );
536 }
537 }
538
539 updateSceneState();
540
541 // lock changing the FPS counter to 5 fps
542 static int frameCount = 0;
543 static float accumulatedTime = 0.0f;
544
545 if ( !mMap.isFpsCounterEnabled() )
546 {
547 frameCount = 0;
548 accumulatedTime = 0;
549 return;
550 }
551
552 frameCount++;
553 accumulatedTime += dt;
554 if ( accumulatedTime >= 0.2f )
555 {
556 float fps = ( float )frameCount / accumulatedTime;
557 frameCount = 0;
558 accumulatedTime = 0.0f;
559 emit fpsCountChanged( fps );
560 }
561}
562
563void Qgs3DMapScene::createTerrain()
564{
565 if ( mTerrain )
566 {
567 mChunkEntities.removeOne( mTerrain );
568
569 mTerrain->deleteLater();
570 mTerrain = nullptr;
571 }
572
573 if ( !mTerrainUpdateScheduled )
574 {
575 // defer re-creation of terrain: there may be multiple invocations of this slot, so create the new entity just once
576 QTimer::singleShot( 0, this, &Qgs3DMapScene::createTerrainDeferred );
577 mTerrainUpdateScheduled = true;
578 setSceneState( Updating );
579 }
580 else
581 {
583 }
584}
585
586void Qgs3DMapScene::createTerrainDeferred()
587{
588 if ( mMap.terrainRenderingEnabled() && mMap.terrainGenerator() )
589 {
590 double tile0width = mMap.terrainGenerator()->rootChunkExtent().width();
591 int maxZoomLevel = Qgs3DUtils::maxZoomLevel( tile0width, mMap.mapTileResolution(), mMap.maxTerrainGroundError() );
592 QgsAABB rootBbox = mMap.terrainGenerator()->rootChunkBbox( mMap );
593 float rootError = mMap.terrainGenerator()->rootChunkError( mMap );
594 const QgsAABB clippingBbox = Qgs3DUtils::mapToWorldExtent( mMap.extent(), rootBbox.zMin, rootBbox.zMax, mMap.origin() );
595 mMap.terrainGenerator()->setupQuadtree( rootBbox, rootError, maxZoomLevel, clippingBbox );
596
597 mTerrain = new QgsTerrainEntity( mMap );
598 mTerrain->setParent( this );
599 mTerrain->setShowBoundingBoxes( mMap.showTerrainBoundingBoxes() );
600
601 mChunkEntities << mTerrain;
602
603 connect( mTerrain, &QgsChunkedEntity::pendingJobsCountChanged, this, &Qgs3DMapScene::totalPendingJobsCountChanged );
604 connect( mTerrain, &QgsTerrainEntity::pendingJobsCountChanged, this, &Qgs3DMapScene::terrainPendingJobsCountChanged );
605 }
606 else
607 {
608 mTerrain = nullptr;
609 }
610
611 // make sure that renderers for layers are re-created as well
612 const QList<QgsMapLayer *> layers = mMap.layers();
613 for ( QgsMapLayer *layer : layers )
614 {
615 // remove old entity - if any
616 removeLayerEntity( layer );
617
618 // add new entity - if any 3D renderer
619 addLayerEntity( layer );
620 }
621
623 onCameraChanged(); // force update of the new terrain
624 mTerrainUpdateScheduled = false;
625}
626
627void Qgs3DMapScene::onBackgroundColorChanged()
628{
629 mEngine->setClearColor( mMap.backgroundColor() );
630}
631
632void Qgs3DMapScene::updateLights()
633{
634 for ( Qt3DCore::QEntity *entity : std::as_const( mLightEntities ) )
635 entity->deleteLater();
636 mLightEntities.clear();
637
638 const QList< QgsLightSource * > newLights = mMap.lightSources();
639 for ( const QgsLightSource *source : newLights )
640 {
641 mLightEntities.append( source->createEntity( mMap, this ) );
642 }
643
644 onShadowSettingsChanged();
645}
646
647void Qgs3DMapScene::updateCameraLens()
648{
649 mEngine->camera()->lens()->setFieldOfView( mMap.fieldOfView() );
650 mEngine->camera()->lens()->setProjectionType( mMap.projectionType() );
651 onCameraChanged();
652}
653
654void Qgs3DMapScene::onRenderersChanged()
655{
656 // remove entities (if any)
657 qDeleteAll( mRenderersEntities );
658 mRenderersEntities.clear();
659
660 // re-add entities from new set of renderers
661 const QList<QgsAbstract3DRenderer *> renderers = mMap.renderers();
662 for ( const QgsAbstract3DRenderer *renderer : renderers )
663 {
664 Qt3DCore::QEntity *newEntity = renderer->createEntity( mMap );
665 if ( newEntity )
666 {
667 newEntity->setParent( this );
668 finalizeNewEntity( newEntity );
669 mRenderersEntities[renderer] = newEntity;
670 }
671 }
672}
673
674void Qgs3DMapScene::onLayerRenderer3DChanged()
675{
676 QgsMapLayer *layer = qobject_cast<QgsMapLayer *>( sender() );
677 Q_ASSERT( layer );
678
679 // remove old entity - if any
680 removeLayerEntity( layer );
681
682 // add new entity - if any 3D renderer
683 addLayerEntity( layer );
684}
685
686void Qgs3DMapScene::onLayersChanged()
687{
688 QSet<QgsMapLayer *> layersBefore = qgis::listToSet( mLayerEntities.keys() );
689 QList<QgsMapLayer *> layersAdded;
690 const QList<QgsMapLayer *> layers = mMap.layers();
691 for ( QgsMapLayer *layer : layers )
692 {
693 if ( !layersBefore.contains( layer ) )
694 {
695 layersAdded << layer;
696 }
697 else
698 {
699 layersBefore.remove( layer );
700 }
701 }
702
703 // what is left in layersBefore are layers that have been removed
704 for ( QgsMapLayer *layer : std::as_const( layersBefore ) )
705 {
706 removeLayerEntity( layer );
707 }
708
709 for ( QgsMapLayer *layer : std::as_const( layersAdded ) )
710 {
711 addLayerEntity( layer );
712 }
713}
714
716{
717 const QList<QgsMapLayer * > layers = mLayerEntities.keys();
718 for ( QgsMapLayer *layer : layers )
719 {
720 if ( layer->temporalProperties()->isActive() )
721 {
722 removeLayerEntity( layer );
723 addLayerEntity( layer );
724 }
725 }
726}
727
728void Qgs3DMapScene::addLayerEntity( QgsMapLayer *layer )
729{
730 bool needsSceneUpdate = false;
731 QgsAbstract3DRenderer *renderer = layer->renderer3D();
732 if ( renderer )
733 {
734 // Fix vector layer's renderer to make sure the renderer is pointing to its layer.
735 // It has happened before that renderer pointed to a different layer (probably after copying a style).
736 // This is a bit of a hack and it should be handled in QgsMapLayer::setRenderer3D() but in qgis_core
737 // the vector layer 3D renderer classes are not available.
738 if ( layer->type() == Qgis::LayerType::Vector &&
739 ( renderer->type() == QLatin1String( "vector" ) || renderer->type() == QLatin1String( "rulebased" ) ) )
740 {
741 static_cast<QgsAbstractVectorLayer3DRenderer *>( renderer )->setLayer( static_cast<QgsVectorLayer *>( layer ) );
742 if ( renderer->type() == QLatin1String( "vector" ) )
743 {
744 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
745 if ( vlayer->geometryType() == Qgis::GeometryType::Point )
746 {
747 const QgsPoint3DSymbol *pointSymbol = static_cast< const QgsPoint3DSymbol * >( static_cast< QgsVectorLayer3DRenderer *>( renderer )->symbol() );
748 if ( pointSymbol->shape() == QgsPoint3DSymbol::Model )
749 {
750 mModelVectorLayers.append( layer );
751 }
752 }
753 }
754 else if ( renderer->type() == QLatin1String( "rulebased" ) )
755 {
756 const QgsRuleBased3DRenderer::RuleList rules = static_cast< QgsRuleBased3DRenderer *>( renderer )->rootRule()->descendants();
757 for ( auto rule : rules )
758 {
759 const QgsPoint3DSymbol *pointSymbol = dynamic_cast< const QgsPoint3DSymbol * >( rule->symbol() );
760 if ( pointSymbol && pointSymbol->shape() == QgsPoint3DSymbol::Model )
761 {
762 mModelVectorLayers.append( layer );
763 break;
764 }
765 }
766 }
767 }
768 else if ( layer->type() == Qgis::LayerType::Mesh && renderer->type() == QLatin1String( "mesh" ) )
769 {
770 QgsMeshLayer3DRenderer *meshRenderer = static_cast<QgsMeshLayer3DRenderer *>( renderer );
771 meshRenderer->setLayer( static_cast<QgsMeshLayer *>( layer ) );
772
773 // Before entity creation, set the maximum texture size
774 // Not very clean, but for now, only place found in the workflow to do that simple
775 QgsMesh3DSymbol *sym = meshRenderer->symbol()->clone();
776 sym->setMaximumTextureSize( maximumTextureSize() );
777 meshRenderer->setSymbol( sym );
778 }
779 else if ( layer->type() == Qgis::LayerType::PointCloud && renderer->type() == QLatin1String( "pointcloud" ) )
780 {
781 QgsPointCloudLayer3DRenderer *pointCloudRenderer = static_cast<QgsPointCloudLayer3DRenderer *>( renderer );
782 pointCloudRenderer->setLayer( static_cast<QgsPointCloudLayer *>( layer ) );
783 }
784
785 Qt3DCore::QEntity *newEntity = renderer->createEntity( mMap );
786 if ( newEntity )
787 {
788 newEntity->setParent( this );
789 mLayerEntities.insert( layer, newEntity );
790
791 finalizeNewEntity( newEntity );
792
793 if ( QgsChunkedEntity *chunkedNewEntity = qobject_cast<QgsChunkedEntity *>( newEntity ) )
794 {
795 mChunkEntities.append( chunkedNewEntity );
796 needsSceneUpdate = true;
797
798 chunkedNewEntity->setPickingEnabled( !mPickHandlers.isEmpty() );
799 connect( chunkedNewEntity, &QgsChunkedEntity::pickedObject, this, &Qgs3DMapScene::onLayerEntityPickedObject );
800
801 connect( chunkedNewEntity, &QgsChunkedEntity::newEntityCreated, this, [this]( Qt3DCore::QEntity * entity )
802 {
803 finalizeNewEntity( entity );
804 } );
805
806 connect( chunkedNewEntity, &QgsChunkedEntity::pendingJobsCountChanged, this, &Qgs3DMapScene::totalPendingJobsCountChanged );
807 }
808 }
809 }
810
811 if ( needsSceneUpdate )
812 onCameraChanged(); // needed for chunked entities
813
814 connect( layer, &QgsMapLayer::request3DUpdate, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
815
816 if ( layer->type() == Qgis::LayerType::Vector )
817 {
818 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
819 connect( vlayer, &QgsVectorLayer::selectionChanged, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
820 connect( vlayer, &QgsVectorLayer::layerModified, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
821 }
822
823 if ( layer->type() == Qgis::LayerType::Mesh )
824 {
825 connect( layer, &QgsMapLayer::rendererChanged, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
826 }
827
828 if ( layer->type() == Qgis::LayerType::PointCloud )
829 {
830 QgsPointCloudLayer *pclayer = qobject_cast<QgsPointCloudLayer *>( layer );
831 connect( pclayer, &QgsPointCloudLayer::renderer3DChanged, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
832 connect( pclayer, &QgsPointCloudLayer::subsetStringChanged, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
833 }
834}
835
836void Qgs3DMapScene::removeLayerEntity( QgsMapLayer *layer )
837{
838 Qt3DCore::QEntity *entity = mLayerEntities.take( layer );
839
840 if ( QgsChunkedEntity *chunkedEntity = qobject_cast<QgsChunkedEntity *>( entity ) )
841 {
842 mChunkEntities.removeOne( chunkedEntity );
843 }
844
845 if ( entity )
846 entity->deleteLater();
847
848 disconnect( layer, &QgsMapLayer::request3DUpdate, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
849
850 if ( layer->type() == Qgis::LayerType::Vector )
851 {
852 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
853 disconnect( vlayer, &QgsVectorLayer::selectionChanged, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
854 disconnect( vlayer, &QgsVectorLayer::layerModified, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
855 mModelVectorLayers.removeAll( layer );
856 }
857
858 if ( layer->type() == Qgis::LayerType::Mesh )
859 {
860 disconnect( layer, &QgsMapLayer::rendererChanged, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
861 }
862
863 if ( layer->type() == Qgis::LayerType::PointCloud )
864 {
865 QgsPointCloudLayer *pclayer = qobject_cast<QgsPointCloudLayer *>( layer );
866 disconnect( pclayer, &QgsPointCloudLayer::renderer3DChanged, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
867 disconnect( pclayer, &QgsPointCloudLayer::subsetStringChanged, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
868 }
869}
870
871void Qgs3DMapScene::finalizeNewEntity( Qt3DCore::QEntity *newEntity )
872{
873 // this is probably not the best place for material-specific configuration,
874 // maybe this could be more generalized when other materials need some specific treatment
875 for ( QgsLineMaterial *lm : newEntity->findChildren<QgsLineMaterial *>() )
876 {
877 connect( mEngine, &QgsAbstract3DEngine::sizeChanged, lm, [lm, this]
878 {
879 lm->setViewportSize( mEngine->size() );
880 } );
881
882 lm->setViewportSize( mEngine->size() );
883 }
884 // configure billboard's viewport when the viewport is changed.
885 for ( QgsPoint3DBillboardMaterial *bm : newEntity->findChildren<QgsPoint3DBillboardMaterial *>() )
886 {
887 connect( mEngine, &QgsAbstract3DEngine::sizeChanged, bm, [bm, this]
888 {
889 bm->setViewportSize( mEngine->size() );
890 } );
891
892 bm->setViewportSize( mEngine->size() );
893 }
894
895 // Finalize adding the 3D transparent objects by adding the layer components to the entities
896 QgsShadowRenderingFrameGraph *frameGraph = mEngine->frameGraph();
897 Qt3DRender::QLayer *transparentLayer = frameGraph->transparentObjectLayer();
898 for ( Qt3DRender::QMaterial *material : newEntity->findChildren<Qt3DRender::QMaterial *>() )
899 {
900 // This handles the phong material without data defined properties.
901 if ( Qt3DExtras::QDiffuseSpecularMaterial *ph = qobject_cast<Qt3DExtras::QDiffuseSpecularMaterial *>( material ) )
902 {
903 if ( ph->diffuse().value<QColor>().alphaF() != 1.0f )
904 {
905 Qt3DCore::QEntity *entity = qobject_cast<Qt3DCore::QEntity *>( ph->parent() );
906 if ( entity && !entity->components().contains( transparentLayer ) )
907 {
908 entity->addComponent( transparentLayer );
909 }
910 }
911 }
912 else
913 {
914 // This handles the phong material with data defined properties, the textured case and point (instanced) symbols.
915 Qt3DRender::QEffect *effect = material->effect();
916 if ( effect )
917 {
918 for ( const auto *parameter : effect->parameters() )
919 {
920 if ( parameter->name() == "opacity" && parameter->value() != 1.0f )
921 {
922 Qt3DCore::QEntity *entity = qobject_cast<Qt3DCore::QEntity *>( material->parent() );
923 if ( entity && !entity->components().contains( transparentLayer ) )
924 {
925 entity->addComponent( transparentLayer );
926 }
927 break;
928 }
929 }
930 }
931 }
932 }
933}
934
935int Qgs3DMapScene::maximumTextureSize() const
936{
937 QSurface *surface = mEngine->surface();
938 QOpenGLContext context;
939 context.create();
940 bool success = context.makeCurrent( surface );
941
942 if ( success )
943 {
944 QOpenGLFunctions openglFunctions = QOpenGLFunctions( &context );
945
946 GLint size;
947 openglFunctions.initializeOpenGLFunctions();
948 openglFunctions.glGetIntegerv( GL_MAX_TEXTURE_SIZE, &size );
949 return int( size );
950 }
951 else
952 {
953 return 4096; //we can't have a context to defined the max texture size, we use this reasonable value
954 }
955
956}
957
958void Qgs3DMapScene::addCameraViewCenterEntity( Qt3DRender::QCamera *camera )
959{
960 mEntityCameraViewCenter = new Qt3DCore::QEntity;
961
962 Qt3DCore::QTransform *trCameraViewCenter = new Qt3DCore::QTransform;
963 mEntityCameraViewCenter->addComponent( trCameraViewCenter );
964 connect( camera, &Qt3DRender::QCamera::viewCenterChanged, this, [trCameraViewCenter, camera]
965 {
966 trCameraViewCenter->setTranslation( camera->viewCenter() );
967 } );
968
969 Qt3DExtras::QPhongMaterial *materialCameraViewCenter = new Qt3DExtras::QPhongMaterial;
970 materialCameraViewCenter->setAmbient( Qt::red );
971 mEntityCameraViewCenter->addComponent( materialCameraViewCenter );
972
973 Qt3DExtras::QSphereMesh *rendererCameraViewCenter = new Qt3DExtras::QSphereMesh;
974 rendererCameraViewCenter->setRadius( 10 );
975 mEntityCameraViewCenter->addComponent( rendererCameraViewCenter );
976
977 mEntityCameraViewCenter->setEnabled( mMap.showCameraViewCenter() );
978 mEntityCameraViewCenter->setParent( this );
979
980 connect( &mMap, &Qgs3DMapSettings::showCameraViewCenterChanged, this, [this]
981 {
982 mEntityCameraViewCenter->setEnabled( mMap.showCameraViewCenter() );
983 } );
984}
985
986void Qgs3DMapScene::setSceneState( Qgs3DMapScene::SceneState state )
987{
988 if ( mSceneState == state )
989 return;
990 mSceneState = state;
991 emit sceneStateChanged();
992}
993
994void Qgs3DMapScene::updateSceneState()
995{
996 if ( mTerrainUpdateScheduled )
997 {
998 setSceneState( Updating );
999 return;
1000 }
1001
1002 for ( QgsChunkedEntity *entity : std::as_const( mChunkEntities ) )
1003 {
1004 if ( entity->isEnabled() && entity->pendingJobsCount() > 0 )
1005 {
1006 setSceneState( Updating );
1007 return;
1008 }
1009 }
1010
1011 setSceneState( Ready );
1012}
1013
1014void Qgs3DMapScene::onSkyboxSettingsChanged()
1015{
1016 QgsSkyboxSettings skyboxSettings = mMap.skyboxSettings();
1017 if ( mSkybox != nullptr )
1018 {
1019 mSkybox->deleteLater();
1020 mSkybox = nullptr;
1021 }
1022
1023 mEngine->setFrustumCullingEnabled( !mMap.isSkyboxEnabled() );
1024
1025 if ( mMap.isSkyboxEnabled() )
1026 {
1027 QMap<QString, QString> faces;
1028 switch ( skyboxSettings.skyboxType() )
1029 {
1031 faces = skyboxSettings.cubeMapFacesPaths();
1032 mSkybox = new QgsCubeFacesSkyboxEntity(
1033 faces[QStringLiteral( "posX" )], faces[QStringLiteral( "posY" )], faces[QStringLiteral( "posZ" )],
1034 faces[QStringLiteral( "negX" )], faces[QStringLiteral( "negY" )], faces[QStringLiteral( "negZ" )],
1035 this
1036 );
1037 break;
1039 mSkybox = new QgsPanoramicSkyboxEntity( skyboxSettings.panoramicTexturePath(), this );
1040 break;
1041 }
1042 }
1043}
1044
1045void Qgs3DMapScene::onShadowSettingsChanged()
1046{
1047 QgsShadowRenderingFrameGraph *shadowRenderingFrameGraph = mEngine->frameGraph();
1048
1049 const QList< QgsLightSource * > lightSources = mMap.lightSources();
1050 QList< QgsDirectionalLightSettings * > directionalLightSources;
1051 for ( QgsLightSource *source : lightSources )
1052 {
1053 if ( source->type() == Qgis::LightSourceType::Directional )
1054 {
1055 directionalLightSources << qgis::down_cast< QgsDirectionalLightSettings * >( source );
1056 }
1057 }
1058
1059 QgsShadowSettings shadowSettings = mMap.shadowSettings();
1060 int selectedLight = shadowSettings.selectedDirectionalLight();
1061 if ( shadowSettings.renderShadows() && selectedLight >= 0 && selectedLight < directionalLightSources.count() )
1062 {
1063 shadowRenderingFrameGraph->setShadowRenderingEnabled( true );
1064 shadowRenderingFrameGraph->setShadowBias( shadowSettings.shadowBias() );
1065 shadowRenderingFrameGraph->setShadowMapResolution( shadowSettings.shadowMapResolution() );
1066 QgsDirectionalLightSettings light = *directionalLightSources.at( selectedLight );
1067 shadowRenderingFrameGraph->setupDirectionalLight( light, shadowSettings.maximumShadowRenderingDistance() );
1068 }
1069 else
1070 shadowRenderingFrameGraph->setShadowRenderingEnabled( false );
1071}
1072
1073void Qgs3DMapScene::onAmbientOcclusionSettingsChanged()
1074{
1075 QgsShadowRenderingFrameGraph *shadowRenderingFrameGraph = mEngine->frameGraph();
1076 QgsAmbientOcclusionSettings ambientOcclusionSettings = mMap.ambientOcclusionSettings();
1077 shadowRenderingFrameGraph->setAmbientOcclusionEnabled( ambientOcclusionSettings.isEnabled() );
1078 shadowRenderingFrameGraph->setAmbientOcclusionRadius( ambientOcclusionSettings.radius() );
1079 shadowRenderingFrameGraph->setAmbientOcclusionIntensity( ambientOcclusionSettings.intensity() );
1080 shadowRenderingFrameGraph->setAmbientOcclusionThreshold( ambientOcclusionSettings.threshold() );
1081}
1082
1083void Qgs3DMapScene::onDebugShadowMapSettingsChanged()
1084{
1085 QgsShadowRenderingFrameGraph *shadowRenderingFrameGraph = mEngine->frameGraph();
1086 shadowRenderingFrameGraph->setupShadowMapDebugging( mMap.debugShadowMapEnabled(), mMap.debugShadowMapCorner(), mMap.debugShadowMapSize() );
1087}
1088
1089void Qgs3DMapScene::onDebugDepthMapSettingsChanged()
1090{
1091 QgsShadowRenderingFrameGraph *shadowRenderingFrameGraph = mEngine->frameGraph();
1092 shadowRenderingFrameGraph->setupDepthMapDebugging( mMap.debugDepthMapEnabled(), mMap.debugDepthMapCorner(), mMap.debugDepthMapSize() );
1093}
1094
1095void Qgs3DMapScene::onDebugOverlayEnabledChanged()
1096{
1097 QgsShadowRenderingFrameGraph *shadowRenderingFrameGraph = mEngine->frameGraph();
1098 shadowRenderingFrameGraph->setDebugOverlayEnabled( mMap.isDebugOverlayEnabled() );
1099}
1100
1101void Qgs3DMapScene::onEyeDomeShadingSettingsChanged()
1102{
1103 QgsShadowRenderingFrameGraph *shadowRenderingFrameGraph = mEngine->frameGraph();
1104
1105 bool edlEnabled = mMap.eyeDomeLightingEnabled();
1106 double edlStrength = mMap.eyeDomeLightingStrength();
1107 double edlDistance = mMap.eyeDomeLightingDistance();
1108 shadowRenderingFrameGraph->setupEyeDomeLighting( edlEnabled, edlStrength, edlDistance );
1109}
1110
1111void Qgs3DMapScene::onCameraMovementSpeedChanged()
1112{
1113 mCameraController->setCameraMovementSpeed( mMap.cameraMovementSpeed() );
1114}
1115
1116void Qgs3DMapScene::onCameraNavigationModeChanged()
1117{
1118 mCameraController->setCameraNavigationMode( mMap.cameraNavigationMode() );
1119}
1120
1122{
1123 QVector<QString> notParsedLayers;
1124 Qgs3DSceneExporter exporter;
1125
1126 exporter.setTerrainResolution( exportSettings.terrrainResolution() );
1127 exporter.setSmoothEdges( exportSettings.smoothEdges() );
1128 exporter.setExportNormals( exportSettings.exportNormals() );
1129 exporter.setExportTextures( exportSettings.exportTextures() );
1130 exporter.setTerrainTextureResolution( exportSettings.terrainTextureResolution() );
1131 exporter.setScale( exportSettings.scale() );
1132
1133 for ( auto it = mLayerEntities.constBegin(); it != mLayerEntities.constEnd(); ++it )
1134 {
1135 QgsMapLayer *layer = it.key();
1136 Qt3DCore::QEntity *rootEntity = it.value();
1137 Qgis::LayerType layerType = layer->type();
1138 switch ( layerType )
1139 {
1140 case Qgis::LayerType::Vector:
1141 if ( !exporter.parseVectorLayerEntity( rootEntity, qobject_cast<QgsVectorLayer *>( layer ) ) )
1142 notParsedLayers.push_back( layer->name() );
1143 break;
1144 case Qgis::LayerType::Raster:
1145 case Qgis::LayerType::Plugin:
1146 case Qgis::LayerType::Mesh:
1147 case Qgis::LayerType::VectorTile:
1148 case Qgis::LayerType::Annotation:
1149 case Qgis::LayerType::PointCloud:
1150 case Qgis::LayerType::Group:
1151 notParsedLayers.push_back( layer->name() );
1152 break;
1153 }
1154 }
1155
1156 if ( mTerrain )
1157 exporter.parseTerrain( mTerrain, "Terrain" );
1158
1159 exporter.save( exportSettings.sceneName(), exportSettings.sceneFolderPath() );
1160
1161 if ( !notParsedLayers.empty() )
1162 {
1163 QString message = tr( "The following layers were not exported:" ) + "\n";
1164 for ( const QString &layerName : notParsedLayers )
1165 message += layerName + "\n";
1166 QgsMessageOutput::showMessage( tr( "3D exporter warning" ), message, QgsMessageOutput::MessageText );
1167 }
1168}
1169
1170QVector<const QgsChunkNode *> Qgs3DMapScene::getLayerActiveChunkNodes( QgsMapLayer *layer )
1171{
1172 QVector<const QgsChunkNode *> chunks;
1173 if ( !mLayerEntities.contains( layer ) ) return chunks;
1174 if ( QgsChunkedEntity *c = qobject_cast<QgsChunkedEntity *>( mLayerEntities[ layer ] ) )
1175 {
1176 for ( QgsChunkNode *n : c->activeNodes() )
1177 chunks.push_back( n );
1178 }
1179 return chunks;
1180}
1181
1183{
1184 return mMap.extent();
1185}
1186
1188{
1189 double yMin = std::numeric_limits< double >::max();
1190 double yMax = std::numeric_limits< double >::lowest();
1191 if ( mMap.terrainRenderingEnabled() && mTerrain )
1192 {
1193 const QgsAABB bbox = mTerrain->rootNode()->bbox();
1194 yMin = std::min( yMin, static_cast< double >( bbox.yMin ) );
1195 yMax = std::max( yMax, static_cast< double >( bbox.yMax ) );
1196 }
1197
1198 for ( auto it = mLayerEntities.constBegin(); it != mLayerEntities.constEnd(); it++ )
1199 {
1200 QgsMapLayer *layer = it.key();
1201 if ( layer->type() == Qgis::LayerType::PointCloud )
1202 {
1203 QgsPointCloudLayer *pcl = qobject_cast< QgsPointCloudLayer *>( layer );
1204 QgsDoubleRange zRange = pcl->elevationProperties()->calculateZRange( pcl );
1205 yMin = std::min( yMin, zRange.lower() );
1206 yMax = std::max( yMax, zRange.upper() );
1207 }
1208 }
1209 const QgsDoubleRange yRange( std::min( yMin, std::numeric_limits<double>::max() ),
1210 std::max( yMax, std::numeric_limits<double>::lowest() ) );
1211 return yRange;
1212}
1213
1214QMap< QString, Qgs3DMapScene * > Qgs3DMapScene::openScenes()
1215{
1216 return sOpenScenesFunction();
1217}
1218
1219void Qgs3DMapScene::addCameraRotationCenterEntity( QgsCameraController *controller )
1220{
1221 mEntityRotationCenter = new Qt3DCore::QEntity;
1222
1223 Qt3DCore::QTransform *trCameraViewCenter = new Qt3DCore::QTransform;
1224 mEntityRotationCenter->addComponent( trCameraViewCenter );
1225 Qt3DExtras::QPhongMaterial *materialCameraViewCenter = new Qt3DExtras::QPhongMaterial;
1226 materialCameraViewCenter->setAmbient( Qt::blue );
1227 mEntityRotationCenter->addComponent( materialCameraViewCenter );
1228 Qt3DExtras::QSphereMesh *rendererCameraViewCenter = new Qt3DExtras::QSphereMesh;
1229 rendererCameraViewCenter->setRadius( 10 );
1230 mEntityRotationCenter->addComponent( rendererCameraViewCenter );
1231 mEntityRotationCenter->setEnabled( true );
1232 mEntityRotationCenter->setParent( this );
1233
1234 connect( controller, &QgsCameraController::cameraRotationCenterChanged, this, [trCameraViewCenter]( QVector3D center )
1235 {
1236 trCameraViewCenter->setTranslation( center );
1237 } );
1238
1239 mEntityRotationCenter->setEnabled( mMap.showCameraRotationCenter() );
1240
1241 connect( &mMap, &Qgs3DMapSettings::showCameraRotationCenterChanged, this, [this]
1242 {
1243 mEntityRotationCenter->setEnabled( mMap.showCameraRotationCenter() );
1244 } );
1245}
1246
1247void Qgs3DMapScene::on3DAxisSettingsChanged()
1248{
1249 if ( m3DAxis )
1250 {
1251 m3DAxis->onAxisSettingsChanged();
1252 }
1253 else
1254 {
1255 if ( QgsWindow3DEngine *engine = dynamic_cast<QgsWindow3DEngine *>( mEngine ) )
1256 {
1257 m3DAxis = new Qgs3DAxis( static_cast<Qt3DExtras::Qt3DWindow *>( engine->window() ),
1258 engine->root(),
1259 this,
1260 mCameraController,
1261 &mMap );
1262 }
1263 }
1264}
LayerType
Types of layers that can be added to a map.
Definition: qgis.h:115
@ Directional
Directional light source.
void onAxisSettingsChanged()
Force update of the axis and the viewport when a setting has changed.
Definition: qgs3daxis.cpp:1011
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.
void unregisterPickHandler(Qgs3DMapScenePickHandler *pickHandler)
Unregisters previously registered pick handler. Pick handler is not deleted. Also removes object pick...
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.
QgsAbstract3DEngine * engine()
Returns the abstract 3D engine.
void fpsCountChanged(float fpsCount)
Emitted when the FPS count changes.
QgsRectangle sceneExtent()
Returns the scene extent in the map's CRS.
void setViewFrom2DExtent(const QgsRectangle &extent)
Resets camera view to show the extent extent (top view)
void registerPickHandler(Qgs3DMapScenePickHandler *pickHandler)
Registers an object that will get results of pick events on 3D entities. Does not take ownership of t...
Qgs3DMapScene(Qgs3DMapSettings &map, QgsAbstract3DEngine *engine)
Constructs a 3D scene based on map settings and Qt 3D renderer configuration.
QgsDoubleRange elevationRange() const
Returns the scene's elevation range.
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 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.
void sceneStateChanged()
Emitted when the scene's state has changed.
int terrainPendingJobsCount() const
Returns number of pending jobs of the terrain entity.
float worldSpaceError(float epsilon, float distance)
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.
QgsCameraController * cameraController()
Returns camera controller.
Definition: qgs3dmapscene.h:86
static std::function< QMap< QString, Qgs3DMapScene * >() > sOpenScenesFunction
Static function for returning open 3D map scenes.
QVector< QgsPointXY > viewFrustum2DExtent()
Calculates the 2D extent viewed by the 3D camera as the vertices of the viewed trapezoid.
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 renderersChanged()
Emitted when the list of map's extra renderers have been modified.
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.
QList< QgsAbstract3DRenderer * > renderers() const
Returns list of extra 3D renderers.
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 project'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 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 save(const QString &sceneName, const QString &sceneFolderPath)
Saves the scene to a .obj file.
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...
Definition: qgs3dutils.cpp:230
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.
Definition: qgs3dutils.cpp:591
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.
Definition: qgs3dutils.cpp:684
3
Definition: qgsaabb.h:34
float yMax
Definition: qgsaabb.h:88
float xMax
Definition: qgsaabb.h:87
float xMin
Definition: qgsaabb.h:84
float zMax
Definition: qgsaabb.h:89
float yMin
Definition: qgsaabb.h:85
float zMin
Definition: qgsaabb.h:86
void sizeChanged()
Emitted after a call to setSize()
virtual QSurface * surface() const =0
Returns the surface of the engine.
QgsShadowRenderingFrameGraph * frameGraph()
Returns the shadow rendering frame graph object used to render the scene.
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 ...
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(const Qgs3DMapSettings &map) const =0
Returns a 3D entity that will be used to show renderer's data in 3D scene.
class containing the configuration of ambient occlusion rendering 3
float radius() const
Returns the radius parameter of the ambient occlusion effect.
bool isEnabled() const
Returns whether ambient occlusion effect is enabled.
float intensity() const
Returns the shading factor of the ambient occlusion effect.
float threshold() const
Returns at what amount of occlusion the effect will kick in.
static QgsSourceCache * sourceCache()
Returns the application's source cache, used for caching embedded and remote source strings as local ...
Qt3DRender::QCamera * camera() const
Returns camera that is being controlled.
float distance() const
Returns distance of the camera from the point it is looking at.
void setCameraNavigationMode(Qgis::NavigationMode navigationMode)
Sets the navigation mode used by the camera controller.
void cameraChanged()
Emitted when camera has been updated.
void frameTriggered(float dt)
Called internally from 3D scene when a new frame is generated. Updates camera according to keyboard/m...
void resetView(float distance)
Move camera back to the initial position (looking down towards origin of world's coordinates)
void setViewFromTop(float worldX, float worldY, float distance, float yaw=0)
Sets camera to look down towards given point in world coordinate, in given distance from plane with z...
void setCameraMovementSpeed(double movementSpeed)
Sets the camera movement speed.
void cameraRotationCenterChanged(QVector3D position)
Emitted when the camera rotation center changes.
A skybox constructed from a 6 cube faces.
QgsRange which stores a range of double values.
Definition: qgsrange.h:203
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 all map layer types.
Definition: qgsmaplayer.h:73
QString name
Definition: qgsmaplayer.h:76
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:80
void rendererChanged()
Signal emitted when renderer is changed.
virtual QgsMapLayerTemporalProperties * temporalProperties()
Returns the layer's temporal properties.
Definition: qgsmaplayer.h:1523
void layerModified()
Emitted when modifications has been done on layer.
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.
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.
Definition: qgsmeshlayer.h:100
virtual void showMessage(bool blocking=true)=0
display the message to the user and deletes itself
A skybox constructed from a panoramic image.
Shape shape() const
Returns 3D shape for points.
QVariantMap shapeProperties() const
Returns a key-value dictionary of point shape properties.
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:59
double y
Definition: qgspointxy.h:63
Q_GADGET double x
Definition: qgspointxy.h:62
T lower() const
Returns the lower bound of the range.
Definition: qgsrange.h:66
T upper() const
Returns the upper bound of the range.
Definition: qgsrange.h:73
A representation of a ray in 3D.
Definition: qgsray3d.h:31
QVector3D origin() const
Returns the origin of the ray.
Definition: qgsray3d.h:44
QVector3D direction() const
Returns the direction of the ray see setDirection()
Definition: qgsray3d.h:50
A rectangle specified with double values.
Definition: qgsrectangle.h:42
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:193
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:183
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:188
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:198
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
Definition: qgsrectangle.h:230
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:223
QgsPointXY center() const SIP_HOLDGIL
Returns the center point of the rectangle.
Definition: qgsrectangle.h:251
QList< QgsRuleBased3DRenderer::Rule * > RuleList
void setupDepthMapDebugging(bool enabled, Qt::Corner corner, double size)
Sets the depth map debugging view port.
Qt3DRender::QLayer * transparentObjectLayer()
Returns a layer object used to indicate that the object is transparent.
void setAmbientOcclusionThreshold(float threshold)
Sets the ambient occlusion threshold.
void setupShadowMapDebugging(bool enabled, Qt::Corner corner, double size)
Sets the shadow map debugging view port.
void setShadowBias(float shadowBias)
Sets the shadow bias value.
void setAmbientOcclusionIntensity(float intensity)
Sets the ambient occlusion intensity.
void setShadowMapResolution(int resolution)
Sets the resolution of the shadow map.
void setupEyeDomeLighting(bool enabled, double strength, int distance)
Sets eye dome lighting shading related settings.
void setAmbientOcclusionRadius(float radius)
Sets the ambient occlusion radius.
void setDebugOverlayEnabled(bool enabled)
Sets whether debug overlay is enabled.
void setAmbientOcclusionEnabled(bool enabled)
Sets whether Screen Space Ambient Occlusion will be enabled.
void setupDirectionalLight(const QgsDirectionalLightSettings &light, float maximumShadowRenderingDistance)
Sets shadow rendering to use a directional light.
void setShadowRenderingEnabled(bool enabled)
Sets whether the shadow rendering is enabled.
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.
bool isActive() const
Returns true if the temporal property is active.
virtual float rootChunkError(const Qgs3DMapSettings &map) const
Returns error of the root chunk in world coordinates.
virtual QgsAABB rootChunkBbox(const Qgs3DMapSettings &map) const
Returns bounding box of the root chunk.
virtual QgsRectangle rootChunkExtent() const =0
extent of the terrain's root chunk in terrain's CRS
double y() const
Returns Y coordinate.
Definition: qgsvector3d.h:51
double z() const
Returns Z coordinate.
Definition: qgsvector3d.h:53
double x() const
Returns X coordinate.
Definition: qgsvector3d.h:49
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:3526
void addQLayerComponentsToHierarchy(Qt3DCore::QEntity *entity, const QVector< Qt3DRender::QLayer * > &layers)
QgsChunkedEntity::SceneState sceneState_(QgsAbstract3DEngine *engine)
void removeQLayerComponentsFromHierarchy(Qt3DCore::QEntity *entity)
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39