QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
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"
73
74#include "qgslinematerial_p.h"
75#include "qgs3dsceneexporter.h"
78#include "qgsmessageoutput.h"
79
80#include "qgsskyboxentity.h"
81#include "qgsskyboxsettings.h"
82
83#include "qgswindow3dengine.h"
85#include "qgspointcloudlayer.h"
87
89 : mMap( map )
90 , mEngine( engine )
91{
92
93 connect( &map, &Qgs3DMapSettings::backgroundColorChanged, this, &Qgs3DMapScene::onBackgroundColorChanged );
94 onBackgroundColorChanged();
95
96 // The default render policy in Qt3D is "Always" - i.e. the 3D map scene gets refreshed up to 60 fps
97 // even if there's no change. Switching to "on demand" should only re-render when something has changed
98 // and we save quite a lot of resources
99 mEngine->renderSettings()->setRenderPolicy( Qt3DRender::QRenderSettings::OnDemand );
100
101 // we want precise picking of terrain (also bounding volume picking does not seem to work - not sure why)
102 mEngine->renderSettings()->pickingSettings()->setPickMethod( Qt3DRender::QPickingSettings::TrianglePicking );
103
104 QRect viewportRect( QPoint( 0, 0 ), mEngine->size() );
105
106 // Camera
107 float aspectRatio = ( float )viewportRect.width() / viewportRect.height();
108 mEngine->camera()->lens()->setPerspectiveProjection( mMap.fieldOfView(), aspectRatio, 10.f, 10000.0f );
109
110 mFrameAction = new Qt3DLogic::QFrameAction();
111 connect( mFrameAction, &Qt3DLogic::QFrameAction::triggered,
112 this, &Qgs3DMapScene::onFrameTriggered );
113 addComponent( mFrameAction ); // takes ownership
114
115 // Camera controlling
116 mCameraController = new QgsCameraController( this ); // attaches to the scene
117 mCameraController->setViewport( viewportRect );
118 mCameraController->setCamera( mEngine->camera() );
119 mCameraController->resetView( 1000 );
120
121 addCameraViewCenterEntity( mEngine->camera() );
122 addCameraRotationCenterEntity( mCameraController );
123 updateLights();
124
125 // create terrain entity
126
127 createTerrainDeferred();
128 connect( &map, &Qgs3DMapSettings::terrainGeneratorChanged, this, &Qgs3DMapScene::createTerrain );
129 connect( &map, &Qgs3DMapSettings::terrainVerticalScaleChanged, this, &Qgs3DMapScene::createTerrain );
130 connect( &map, &Qgs3DMapSettings::mapTileResolutionChanged, this, &Qgs3DMapScene::createTerrain );
131 connect( &map, &Qgs3DMapSettings::maxTerrainScreenErrorChanged, this, &Qgs3DMapScene::createTerrain );
132 connect( &map, &Qgs3DMapSettings::maxTerrainGroundErrorChanged, this, &Qgs3DMapScene::createTerrain );
133 connect( &map, &Qgs3DMapSettings::terrainShadingChanged, this, &Qgs3DMapScene::createTerrain );
134 connect( &map, &Qgs3DMapSettings::lightSourcesChanged, this, &Qgs3DMapScene::updateLights );
135 connect( &map, &Qgs3DMapSettings::showLightSourceOriginsChanged, this, &Qgs3DMapScene::updateLights );
136 connect( &map, &Qgs3DMapSettings::fieldOfViewChanged, this, &Qgs3DMapScene::updateCameraLens );
137 connect( &map, &Qgs3DMapSettings::projectionTypeChanged, this, &Qgs3DMapScene::updateCameraLens );
138 connect( &map, &Qgs3DMapSettings::renderersChanged, this, &Qgs3DMapScene::onRenderersChanged );
139 connect( &map, &Qgs3DMapSettings::skyboxSettingsChanged, this, &Qgs3DMapScene::onSkyboxSettingsChanged );
140 connect( &map, &Qgs3DMapSettings::shadowSettingsChanged, this, &Qgs3DMapScene::onShadowSettingsChanged );
141 connect( &map, &Qgs3DMapSettings::ambientOcclusionSettingsChanged, this, &Qgs3DMapScene::onAmbientOcclusionSettingsChanged );
142 connect( &map, &Qgs3DMapSettings::eyeDomeLightingEnabledChanged, this, &Qgs3DMapScene::onEyeDomeShadingSettingsChanged );
143 connect( &map, &Qgs3DMapSettings::eyeDomeLightingStrengthChanged, this, &Qgs3DMapScene::onEyeDomeShadingSettingsChanged );
144 connect( &map, &Qgs3DMapSettings::eyeDomeLightingDistanceChanged, this, &Qgs3DMapScene::onEyeDomeShadingSettingsChanged );
145 connect( &map, &Qgs3DMapSettings::debugShadowMapSettingsChanged, this, &Qgs3DMapScene::onDebugShadowMapSettingsChanged );
146 connect( &map, &Qgs3DMapSettings::debugDepthMapSettingsChanged, this, &Qgs3DMapScene::onDebugDepthMapSettingsChanged );
148 connect( &map, &Qgs3DMapSettings::cameraMovementSpeedChanged, this, &Qgs3DMapScene::onCameraMovementSpeedChanged );
149 connect( &map, &Qgs3DMapSettings::cameraNavigationModeChanged, this, &Qgs3DMapScene::onCameraNavigationModeChanged );
150 connect( &map, &Qgs3DMapSettings::debugOverlayEnabledChanged, this, &Qgs3DMapScene::onDebugOverlayEnabledChanged );
151
152 connect( &map, &Qgs3DMapSettings::axisSettingsChanged, this, &Qgs3DMapScene::on3DAxisSettingsChanged );
153
154 connect( QgsApplication::sourceCache(), &QgsSourceCache::remoteSourceFetched, this, [ = ]( const QString & url )
155 {
156 const QList<QgsMapLayer *> modelVectorLayers = mModelVectorLayers;
157 for ( QgsMapLayer *layer : modelVectorLayers )
158 {
159 QgsAbstract3DRenderer *renderer = layer->renderer3D();
160 if ( renderer )
161 {
162 if ( renderer->type() == QLatin1String( "vector" ) )
163 {
164 const QgsPoint3DSymbol *pointSymbol = static_cast< const QgsPoint3DSymbol * >( static_cast< QgsVectorLayer3DRenderer *>( renderer )->symbol() );
165 if ( pointSymbol->shapeProperties()[QStringLiteral( "model" )].toString() == url )
166 {
167 removeLayerEntity( layer );
168 addLayerEntity( layer );
169 }
170 }
171 else if ( renderer->type() == QLatin1String( "rulebased" ) )
172 {
173 const QgsRuleBased3DRenderer::RuleList rules = static_cast< QgsRuleBased3DRenderer *>( renderer )->rootRule()->descendants();
174 for ( auto rule : rules )
175 {
176 const QgsPoint3DSymbol *pointSymbol = dynamic_cast< const QgsPoint3DSymbol * >( rule->symbol() );
177 if ( pointSymbol->shapeProperties()[QStringLiteral( "model" )].toString() == url )
178 {
179 removeLayerEntity( layer );
180 addLayerEntity( layer );
181 break;
182 }
183 }
184 }
185 }
186 }
187 } );
188
189 // create entities of renderers
190
191 onRenderersChanged();
192
193 // listen to changes of layers in order to add/remove 3D renderer entities
194 connect( &map, &Qgs3DMapSettings::layersChanged, this, &Qgs3DMapScene::onLayersChanged );
195
196
197#if 0
198 ChunkedEntity *testChunkEntity = new ChunkedEntity( AABB( -500, 0, -500, 500, 100, 500 ), 2.f, 3.f, 7, new TestChunkLoaderFactory );
199 testChunkEntity->setEnabled( false );
200 testChunkEntity->setParent( this );
201 chunkEntities << testChunkEntity;
202#endif
203
204 connect( mCameraController, &QgsCameraController::cameraChanged, this, &Qgs3DMapScene::onCameraChanged );
205 connect( mCameraController, &QgsCameraController::viewportChanged, this, &Qgs3DMapScene::onCameraChanged );
206
207#if 0
208 // experiments with loading of existing 3D models.
209
210 // scene loader only gets loaded only when added to a scene...
211 // it loads everything: geometries, materials, transforms, lights, cameras (if any)
212 Qt3DCore::QEntity *loaderEntity = new Qt3DCore::QEntity;
213 Qt3DRender::QSceneLoader *loader = new Qt3DRender::QSceneLoader;
214 loader->setSource( QUrl( "file:///home/martin/Downloads/LowPolyModels/tree.dae" ) );
215 loaderEntity->addComponent( loader );
216 loaderEntity->setParent( this );
217
218 // mesh loads just geometry as one geometry...
219 // so if there are different materials (e.g. colors) used in the model, this information is lost
220 Qt3DCore::QEntity *meshEntity = new Qt3DCore::QEntity;
221 Qt3DRender::QMesh *mesh = new Qt3DRender::QMesh;
222 mesh->setSource( QUrl( "file:///home/martin/Downloads/LowPolyModels/tree.obj" ) );
223 meshEntity->addComponent( mesh );
224 Qt3DExtras::QPhongMaterial *material = new Qt3DExtras::QPhongMaterial;
225 material->setAmbient( Qt::red );
226 meshEntity->addComponent( material );
227 Qt3DCore::QTransform *meshTransform = new Qt3DCore::QTransform;
228 meshTransform->setScale( 1 );
229 meshEntity->addComponent( meshTransform );
230 meshEntity->setParent( this );
231#endif
232 onSkyboxSettingsChanged();
233
234 // force initial update of chunked entities
235 onCameraChanged();
236 // force initial update of eye dome shading
237 onEyeDomeShadingSettingsChanged();
238 // force initial update of debugging setting of preview quads
239 onDebugShadowMapSettingsChanged();
240 onDebugDepthMapSettingsChanged();
241 // force initial update of ambient occlusion settings
242 onAmbientOcclusionSettingsChanged();
243
244 mCameraController->setCameraNavigationMode( mMap.cameraNavigationMode() );
245 onCameraMovementSpeedChanged();
246
247 on3DAxisSettingsChanged();
248}
249
251{
252 QgsRectangle extent = sceneExtent();
253 float side = std::max( extent.width(), extent.height() );
254 float a = side / 2.0f / std::sin( qDegreesToRadians( cameraController()->camera()->fieldOfView() ) / 2.0f );
255 // Note: the 1.5 multiplication is to move the view upwards to look better
256 mCameraController->resetView( 1.5 * std::sqrt( a * a - side * side ) ); // assuming FOV being 45 degrees
257}
258
260{
261 QgsPointXY center = extent.center();
262 QgsVector3D centerWorld = mMap.mapToWorldCoordinates( QVector3D( center.x(), center.y(), 0 ) );
263 QgsVector3D p1 = mMap.mapToWorldCoordinates( QVector3D( extent.xMinimum(), extent.yMinimum(), 0 ) );
264 QgsVector3D p2 = mMap.mapToWorldCoordinates( QVector3D( extent.xMaximum(), extent.yMaximum(), 0 ) );
265
266 float xSide = std::abs( p1.x() - p2.x() );
267 float ySide = std::abs( p1.z() - p2.z() );
268 if ( xSide < ySide )
269 {
270 float fov = 2 * std::atan( std::tan( qDegreesToRadians( cameraController()->camera()->fieldOfView() ) / 2 ) * cameraController()->camera()->aspectRatio() );
271 float r = xSide / 2.0f / std::tan( fov / 2.0f );
272 mCameraController->setViewFromTop( centerWorld.x(), centerWorld.z(), r );
273 }
274 else
275 {
276 float fov = qDegreesToRadians( cameraController()->camera()->fieldOfView() );
277 float r = ySide / 2.0f / std::tan( fov / 2.0f );
278 mCameraController->setViewFromTop( centerWorld.x(), centerWorld.z(), r );
279 }
280}
281
283{
284 Qt3DRender::QCamera *camera = mCameraController->camera();
285 const QRect viewport = mCameraController->viewport();
286 QVector<QgsPointXY> extent;
287 QVector<int> pointsOrder = { 0, 1, 3, 2 };
288 for ( int i : pointsOrder )
289 {
290 const QPoint p( ( ( i >> 0 ) & 1 ) ? 0 : viewport.width(), ( ( i >> 1 ) & 1 ) ? 0 : viewport.height() );
291 QgsRay3D ray = Qgs3DUtils::rayFromScreenPoint( p, viewport.size(), camera );
292 QVector3D dir = ray.direction();
293 if ( dir.y() == 0.0 )
294 dir.setY( 0.000001 );
295 double t = - ray.origin().y() / dir.y();
296 if ( t < 0 )
297 {
298 // If the projected point is on the back of the camera we choose the farthest point in the front
299 t = camera->farPlane();
300 }
301 else
302 {
303 // If the projected point is on the front of the camera we choose the closest between it and farthest point in the front
304 t = std::min<float>( t, camera->farPlane() );
305 }
306 QVector3D planePoint = ray.origin() + t * dir;
307 QgsVector3D pMap = mMap.worldToMapCoordinates( planePoint );
308 extent.push_back( QgsPointXY( pMap.x(), pMap.y() ) );
309 }
310 return extent;
311}
312
314{
315 return mTerrain ? mTerrain->pendingJobsCount() : 0;
316}
317
319{
320 int count = 0;
321 for ( QgsChunkedEntity *entity : std::as_const( mChunkEntities ) )
322 count += entity->pendingJobsCount();
323 return count;
324}
325
327{
328 if ( mPickHandlers.isEmpty() )
329 {
330 // we need to add object pickers
331 for ( Qt3DCore::QEntity *entity : mLayerEntities.values() )
332 {
333 if ( QgsChunkedEntity *chunkedEntity = qobject_cast<QgsChunkedEntity *>( entity ) )
334 chunkedEntity->setPickingEnabled( true );
335 }
336 }
337
338 mPickHandlers.append( pickHandler );
339}
340
342{
343 mPickHandlers.removeOne( pickHandler );
344
345 if ( mPickHandlers.isEmpty() )
346 {
347 // we need to remove pickers
348 for ( Qt3DCore::QEntity *entity : mLayerEntities.values() )
349 {
350 if ( QgsChunkedEntity *chunkedEntity = qobject_cast<QgsChunkedEntity *>( entity ) )
351 chunkedEntity->setPickingEnabled( false );
352 }
353 }
354}
355
356void Qgs3DMapScene::onLayerEntityPickedObject( Qt3DRender::QPickEvent *pickEvent, QgsFeatureId fid )
357{
358 QgsMapLayer *layer = mLayerEntities.key( qobject_cast<QgsChunkedEntity *>( sender() ) );
359 if ( !layer )
360 return;
361
362 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
363 if ( !vlayer )
364 return;
365
366 for ( Qgs3DMapScenePickHandler *pickHandler : std::as_const( mPickHandlers ) )
367 {
368 pickHandler->handlePickOnVectorLayer( vlayer, fid, pickEvent->worldIntersection(), pickEvent );
369 }
370}
371
372float Qgs3DMapScene::worldSpaceError( float epsilon, float distance )
373{
374 Qt3DRender::QCamera *camera = mCameraController->camera();
375 float fov = camera->fieldOfView();
376 QRect rect = mCameraController->viewport();
377 float screenSizePx = std::max( rect.width(), rect.height() ); // TODO: is this correct?
378
379 // in qgschunkedentity_p.cpp there is inverse calculation (world space error to screen space error)
380 // with explanation of the math.
381 float frustumWidthAtDistance = 2 * distance * tan( fov / 2 );
382 float err = frustumWidthAtDistance * epsilon / screenSizePx;
383 return err;
384}
385
386QgsChunkedEntity::SceneState _sceneState( QgsCameraController *cameraController )
387{
388 Qt3DRender::QCamera *camera = cameraController->camera();
389 QgsChunkedEntity::SceneState state;
390 state.cameraFov = camera->fieldOfView();
391 state.cameraPos = camera->position();
392 QRect rect = cameraController->viewport();
393 state.screenSizePx = std::max( rect.width(), rect.height() ); // TODO: is this correct?
394 state.viewProjectionMatrix = camera->projectionMatrix() * camera->viewMatrix();
395 return state;
396}
397
398void Qgs3DMapScene::onCameraChanged()
399{
400 if ( mMap.projectionType() == Qt3DRender::QCameraLens::OrthographicProjection )
401 {
402 QRect viewportRect( QPoint( 0, 0 ), mEngine->size() );
403 const float viewWidthFromCenter = mCameraController->distance();
404 const float viewHeightFromCenter = viewportRect.height() * viewWidthFromCenter / viewportRect.width();
405 mEngine->camera()->lens()->setOrthographicProjection( -viewWidthFromCenter, viewWidthFromCenter, -viewHeightFromCenter, viewHeightFromCenter, mEngine->camera()->nearPlane(), mEngine->camera()->farPlane() );
406 }
407
408 updateScene();
409 bool changedCameraPlanes = updateCameraNearFarPlanes();
410
411 if ( changedCameraPlanes )
412 {
413 // repeat update of entities - because we have updated camera's near/far planes,
414 // the active nodes may have changed as well
415 updateScene();
416 updateCameraNearFarPlanes();
417 }
418
419 onShadowSettingsChanged();
420
421 QVector<QgsPointXY> extent2D = viewFrustum2DExtent();
422 emit viewed2DExtentFrom3DChanged( extent2D );
423}
424
425void removeQLayerComponentsFromHierarchy( Qt3DCore::QEntity *entity )
426{
427 QVector<Qt3DCore::QComponent *> toBeRemovedComponents;
428 for ( Qt3DCore::QComponent *component : entity->components() )
429 {
430 Qt3DRender::QLayer *layer = qobject_cast<Qt3DRender::QLayer *>( component );
431 if ( layer != nullptr )
432 toBeRemovedComponents.push_back( layer );
433 }
434 for ( Qt3DCore::QComponent *component : toBeRemovedComponents )
435 entity->removeComponent( component );
436 for ( Qt3DCore::QEntity *obj : entity->findChildren<Qt3DCore::QEntity *>() )
437 {
438 if ( obj != nullptr )
440 }
441}
442
443void addQLayerComponentsToHierarchy( Qt3DCore::QEntity *entity, const QVector<Qt3DRender::QLayer *> &layers )
444{
445 for ( Qt3DRender::QLayer *layer : layers )
446 entity->addComponent( layer );
447 for ( Qt3DCore::QEntity *child : entity->findChildren<Qt3DCore::QEntity *>() )
448 {
449 if ( child != nullptr )
450 addQLayerComponentsToHierarchy( child, layers );
451 }
452}
453
454void Qgs3DMapScene::updateScene()
455{
456 QgsEventTracing::addEvent( QgsEventTracing::Instant, QStringLiteral( "3D" ), QStringLiteral( "Update Scene" ) );
457 for ( QgsChunkedEntity *entity : std::as_const( mChunkEntities ) )
458 {
459 if ( entity->isEnabled() )
460 entity->update( _sceneState( mCameraController ) );
461 }
462 updateSceneState();
463}
464
465static void _updateNearFarPlane( const QList<QgsChunkNode *> &activeNodes, const QMatrix4x4 &viewMatrix, float &fnear, float &ffar )
466{
467 for ( QgsChunkNode *node : activeNodes )
468 {
469 // project each corner of bbox to camera coordinates
470 // and determine closest and farthest point.
471 QgsAABB bbox = node->bbox();
472 for ( int i = 0; i < 8; ++i )
473 {
474 QVector4D p( ( ( i >> 0 ) & 1 ) ? bbox.xMin : bbox.xMax,
475 ( ( i >> 1 ) & 1 ) ? bbox.yMin : bbox.yMax,
476 ( ( i >> 2 ) & 1 ) ? bbox.zMin : bbox.zMax, 1 );
477
478 QVector4D pc = viewMatrix * p;
479
480
481 float dst = -pc.z(); // in camera coordinates, x grows right, y grows down, z grows to the back
482 fnear = std::min( fnear, dst );
483 ffar = std::max( ffar, dst );
484 }
485 }
486}
487
488bool Qgs3DMapScene::updateCameraNearFarPlanes()
489{
490 // Update near and far plane from the terrain.
491 // this needs to be done with great care as we have kind of circular dependency here:
492 // active nodes are culled based on the current frustum (which involves near + far plane)
493 // and then based on active nodes we set near and far plane.
494 //
495 // All of this is just heuristics assuming that all other stuff is being rendered somewhere
496 // around the area where the terrain is.
497 //
498 // Near/far plane is setup in order to make best use of the depth buffer to avoid:
499 // 1. precision errors - if the range is too great
500 // 2. unwanted clipping of scene - if the range is too small
501
502 Qt3DRender::QCamera *camera = cameraController()->camera();
503 QMatrix4x4 viewMatrix = camera->viewMatrix();
504 float fnear = 1e9;
505 float ffar = 0;
506 QList<QgsChunkNode *> activeNodes;
507 if ( mTerrain )
508 activeNodes = mTerrain->activeNodes();
509
510 // it could be that there are no active nodes - they could be all culled or because root node
511 // is not yet loaded - we still need at least something to understand bounds of our scene
512 // so lets use the root node
513 if ( mTerrain && activeNodes.isEmpty() )
514 activeNodes << mTerrain->rootNode();
515
516 _updateNearFarPlane( activeNodes, viewMatrix, fnear, ffar );
517
518 // Also involve all the other chunked entities to make sure that they will not get
519 // clipped by the near or far plane
520 for ( QgsChunkedEntity *e : std::as_const( mChunkEntities ) )
521 {
522 if ( e != mTerrain )
523 {
524 QList<QgsChunkNode *> activeEntityNodes = e->activeNodes();
525 if ( activeEntityNodes.empty() )
526 activeEntityNodes << e->rootNode();
527 _updateNearFarPlane( activeEntityNodes, viewMatrix, fnear, ffar );
528 }
529 }
530
531 if ( fnear < 1 )
532 fnear = 1; // does not really make sense to use negative far plane (behind camera)
533
534 // when zooming in a lot, fnear can become smaller than ffar. This should not happen
535 if ( fnear > ffar )
536 std::swap( fnear, ffar );
537
538 if ( fnear == 1e9 && ffar == 0 )
539 {
540 // the update didn't work out... this should not happen
541 // well at least temporarily use some conservative starting values
542 qWarning() << "oops... this should not happen! couldn't determine near/far plane. defaulting to 1...1e9";
543 fnear = 1;
544 ffar = 1e9;
545 }
546
547 // set near/far plane - with some tolerance in front/behind expected near/far planes
548 float newFar = ffar * 2;
549 float newNear = fnear / 2;
550 if ( !qgsFloatNear( newFar, camera->farPlane() ) || !qgsFloatNear( newNear, camera->nearPlane() ) )
551 {
552 camera->setFarPlane( newFar );
553 camera->setNearPlane( newNear );
554 return true;
555 }
556
557 return false;
558}
559
560void Qgs3DMapScene::onFrameTriggered( float dt )
561{
562 mCameraController->frameTriggered( dt );
563
564 for ( QgsChunkedEntity *entity : std::as_const( mChunkEntities ) )
565 {
566 if ( entity->isEnabled() && entity->needsUpdate() )
567 {
568 QgsDebugMsgLevel( QStringLiteral( "need for update" ), 2 );
569 entity->update( _sceneState( mCameraController ) );
570 }
571 }
572
573 updateSceneState();
574
575 // lock changing the FPS counter to 5 fps
576 static int frameCount = 0;
577 static float accumulatedTime = 0.0f;
578
579 if ( !mMap.isFpsCounterEnabled() )
580 {
581 frameCount = 0;
582 accumulatedTime = 0;
583 return;
584 }
585
586 frameCount++;
587 accumulatedTime += dt;
588 if ( accumulatedTime >= 0.2f )
589 {
590 float fps = ( float )frameCount / accumulatedTime;
591 frameCount = 0;
592 accumulatedTime = 0.0f;
593 emit fpsCountChanged( fps );
594 }
595}
596
597void Qgs3DMapScene::createTerrain()
598{
599 if ( mTerrain )
600 {
601 mChunkEntities.removeOne( mTerrain );
602
603 mTerrain->deleteLater();
604 mTerrain = nullptr;
605 }
606
607 if ( !mTerrainUpdateScheduled )
608 {
609 // defer re-creation of terrain: there may be multiple invocations of this slot, so create the new entity just once
610 QTimer::singleShot( 0, this, &Qgs3DMapScene::createTerrainDeferred );
611 mTerrainUpdateScheduled = true;
612 setSceneState( Updating );
613 }
614 else
615 {
617 }
618}
619
620void Qgs3DMapScene::createTerrainDeferred()
621{
622 if ( mMap.terrainRenderingEnabled() && mMap.terrainGenerator() )
623 {
624 double tile0width = mMap.terrainGenerator()->extent().width();
625 int maxZoomLevel = Qgs3DUtils::maxZoomLevel( tile0width, mMap.mapTileResolution(), mMap.maxTerrainGroundError() );
626 QgsAABB rootBbox = mMap.terrainGenerator()->rootChunkBbox( mMap );
627 float rootError = mMap.terrainGenerator()->rootChunkError( mMap );
628 mMap.terrainGenerator()->setupQuadtree( rootBbox, rootError, maxZoomLevel );
629
630 mTerrain = new QgsTerrainEntity( mMap );
631 mTerrain->setParent( this );
632 mTerrain->setShowBoundingBoxes( mMap.showTerrainBoundingBoxes() );
633
634 mCameraController->setTerrainEntity( mTerrain );
635
636 mChunkEntities << mTerrain;
637
638 connect( mTerrain, &QgsChunkedEntity::pendingJobsCountChanged, this, &Qgs3DMapScene::totalPendingJobsCountChanged );
639 connect( mTerrain, &QgsTerrainEntity::pendingJobsCountChanged, this, &Qgs3DMapScene::terrainPendingJobsCountChanged );
640 }
641 else
642 {
643 mTerrain = nullptr;
644 mCameraController->setTerrainEntity( mTerrain );
645 }
646
647 // make sure that renderers for layers are re-created as well
648 const QList<QgsMapLayer *> layers = mMap.layers();
649 for ( QgsMapLayer *layer : layers )
650 {
651 // remove old entity - if any
652 removeLayerEntity( layer );
653
654 // add new entity - if any 3D renderer
655 addLayerEntity( layer );
656 }
657
659 onCameraChanged(); // force update of the new terrain
660 mTerrainUpdateScheduled = false;
661}
662
663void Qgs3DMapScene::onBackgroundColorChanged()
664{
665 mEngine->setClearColor( mMap.backgroundColor() );
666}
667
668void Qgs3DMapScene::updateLights()
669{
670 for ( Qt3DCore::QEntity *entity : std::as_const( mLightEntities ) )
671 entity->deleteLater();
672 mLightEntities.clear();
673
674 const QList< QgsLightSource * > newLights = mMap.lightSources();
675 for ( const QgsLightSource *source : newLights )
676 {
677 mLightEntities.append( source->createEntity( mMap, this ) );
678 }
679
680 onShadowSettingsChanged();
681}
682
683void Qgs3DMapScene::updateCameraLens()
684{
685 mEngine->camera()->lens()->setFieldOfView( mMap.fieldOfView() );
686 mEngine->camera()->lens()->setProjectionType( mMap.projectionType() );
687 onCameraChanged();
688}
689
690void Qgs3DMapScene::onRenderersChanged()
691{
692 // remove entities (if any)
693 qDeleteAll( mRenderersEntities );
694 mRenderersEntities.clear();
695
696 // re-add entities from new set of renderers
697 const QList<QgsAbstract3DRenderer *> renderers = mMap.renderers();
698 for ( const QgsAbstract3DRenderer *renderer : renderers )
699 {
700 Qt3DCore::QEntity *newEntity = renderer->createEntity( mMap );
701 if ( newEntity )
702 {
703 newEntity->setParent( this );
704 finalizeNewEntity( newEntity );
705 mRenderersEntities[renderer] = newEntity;
706 }
707 }
708}
709
710void Qgs3DMapScene::onLayerRenderer3DChanged()
711{
712 QgsMapLayer *layer = qobject_cast<QgsMapLayer *>( sender() );
713 Q_ASSERT( layer );
714
715 // remove old entity - if any
716 removeLayerEntity( layer );
717
718 // add new entity - if any 3D renderer
719 addLayerEntity( layer );
720}
721
722void Qgs3DMapScene::onLayersChanged()
723{
724 QSet<QgsMapLayer *> layersBefore = qgis::listToSet( mLayerEntities.keys() );
725 QList<QgsMapLayer *> layersAdded;
726 const QList<QgsMapLayer *> layers = mMap.layers();
727 for ( QgsMapLayer *layer : layers )
728 {
729 if ( !layersBefore.contains( layer ) )
730 {
731 layersAdded << layer;
732 }
733 else
734 {
735 layersBefore.remove( layer );
736 }
737 }
738
739 // what is left in layersBefore are layers that have been removed
740 for ( QgsMapLayer *layer : std::as_const( layersBefore ) )
741 {
742 removeLayerEntity( layer );
743 }
744
745 for ( QgsMapLayer *layer : std::as_const( layersAdded ) )
746 {
747 addLayerEntity( layer );
748 }
749}
750
752{
753 for ( auto layer : mLayerEntities.keys() )
754 {
755 if ( layer->temporalProperties()->isActive() )
756 {
757 removeLayerEntity( layer );
758 addLayerEntity( layer );
759 }
760 }
761}
762
763void Qgs3DMapScene::addLayerEntity( QgsMapLayer *layer )
764{
765 bool needsSceneUpdate = false;
766 QgsAbstract3DRenderer *renderer = layer->renderer3D();
767 if ( renderer )
768 {
769 // Fix vector layer's renderer to make sure the renderer is pointing to its layer.
770 // It has happened before that renderer pointed to a different layer (probably after copying a style).
771 // This is a bit of a hack and it should be handled in QgsMapLayer::setRenderer3D() but in qgis_core
772 // the vector layer 3D renderer classes are not available.
773 if ( layer->type() == QgsMapLayerType::VectorLayer &&
774 ( renderer->type() == QLatin1String( "vector" ) || renderer->type() == QLatin1String( "rulebased" ) ) )
775 {
776 static_cast<QgsAbstractVectorLayer3DRenderer *>( renderer )->setLayer( static_cast<QgsVectorLayer *>( layer ) );
777 if ( renderer->type() == QLatin1String( "vector" ) )
778 {
779 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
780 if ( vlayer->geometryType() == QgsWkbTypes::PointGeometry )
781 {
782 const QgsPoint3DSymbol *pointSymbol = static_cast< const QgsPoint3DSymbol * >( static_cast< QgsVectorLayer3DRenderer *>( renderer )->symbol() );
783 if ( pointSymbol->shape() == QgsPoint3DSymbol::Model )
784 {
785 mModelVectorLayers.append( layer );
786 }
787 }
788 }
789 else if ( renderer->type() == QLatin1String( "rulebased" ) )
790 {
791 const QgsRuleBased3DRenderer::RuleList rules = static_cast< QgsRuleBased3DRenderer *>( renderer )->rootRule()->descendants();
792 for ( auto rule : rules )
793 {
794 const QgsPoint3DSymbol *pointSymbol = dynamic_cast< const QgsPoint3DSymbol * >( rule->symbol() );
795 if ( pointSymbol && pointSymbol->shape() == QgsPoint3DSymbol::Model )
796 {
797 mModelVectorLayers.append( layer );
798 break;
799 }
800 }
801 }
802 }
803 else if ( layer->type() == QgsMapLayerType::MeshLayer && renderer->type() == QLatin1String( "mesh" ) )
804 {
805 QgsMeshLayer3DRenderer *meshRenderer = static_cast<QgsMeshLayer3DRenderer *>( renderer );
806 meshRenderer->setLayer( static_cast<QgsMeshLayer *>( layer ) );
807
808 // Before entity creation, set the maximum texture size
809 // Not very clean, but for now, only place found in the workflow to do that simple
810 QgsMesh3DSymbol *sym = meshRenderer->symbol()->clone();
811 sym->setMaximumTextureSize( maximumTextureSize() );
812 meshRenderer->setSymbol( sym );
813 }
814 else if ( layer->type() == QgsMapLayerType::PointCloudLayer && renderer->type() == QLatin1String( "pointcloud" ) )
815 {
816 QgsPointCloudLayer3DRenderer *pointCloudRenderer = static_cast<QgsPointCloudLayer3DRenderer *>( renderer );
817 pointCloudRenderer->setLayer( static_cast<QgsPointCloudLayer *>( layer ) );
818 }
819
820 Qt3DCore::QEntity *newEntity = renderer->createEntity( mMap );
821 if ( newEntity )
822 {
823 newEntity->setParent( this );
824 mLayerEntities.insert( layer, newEntity );
825
826 finalizeNewEntity( newEntity );
827
828 if ( QgsChunkedEntity *chunkedNewEntity = qobject_cast<QgsChunkedEntity *>( newEntity ) )
829 {
830 mChunkEntities.append( chunkedNewEntity );
831 needsSceneUpdate = true;
832
833 chunkedNewEntity->setPickingEnabled( !mPickHandlers.isEmpty() );
834 connect( chunkedNewEntity, &QgsChunkedEntity::pickedObject, this, &Qgs3DMapScene::onLayerEntityPickedObject );
835
836 connect( chunkedNewEntity, &QgsChunkedEntity::newEntityCreated, this, [this]( Qt3DCore::QEntity * entity )
837 {
838 finalizeNewEntity( entity );
839 } );
840
841 connect( chunkedNewEntity, &QgsChunkedEntity::pendingJobsCountChanged, this, &Qgs3DMapScene::totalPendingJobsCountChanged );
842 }
843 }
844 }
845
846 if ( needsSceneUpdate )
847 onCameraChanged(); // needed for chunked entities
848
849 connect( layer, &QgsMapLayer::request3DUpdate, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
850
851 if ( layer->type() == QgsMapLayerType::VectorLayer )
852 {
853 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
854 connect( vlayer, &QgsVectorLayer::selectionChanged, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
855 connect( vlayer, &QgsVectorLayer::layerModified, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
856 }
857
858 if ( layer->type() == QgsMapLayerType::MeshLayer )
859 {
860 connect( layer, &QgsMapLayer::rendererChanged, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
861 }
862
863 if ( layer->type() == QgsMapLayerType::PointCloudLayer )
864 {
865 QgsPointCloudLayer *pclayer = qobject_cast<QgsPointCloudLayer *>( layer );
866 connect( pclayer, &QgsPointCloudLayer::renderer3DChanged, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
867 connect( pclayer, &QgsPointCloudLayer::subsetStringChanged, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
868 }
869}
870
871void Qgs3DMapScene::removeLayerEntity( QgsMapLayer *layer )
872{
873 Qt3DCore::QEntity *entity = mLayerEntities.take( layer );
874
875 if ( QgsChunkedEntity *chunkedEntity = qobject_cast<QgsChunkedEntity *>( entity ) )
876 {
877 mChunkEntities.removeOne( chunkedEntity );
878 }
879
880 if ( entity )
881 entity->deleteLater();
882
883 disconnect( layer, &QgsMapLayer::request3DUpdate, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
884
885 if ( layer->type() == QgsMapLayerType::VectorLayer )
886 {
887 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
888 disconnect( vlayer, &QgsVectorLayer::selectionChanged, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
889 disconnect( vlayer, &QgsVectorLayer::layerModified, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
890 mModelVectorLayers.removeAll( layer );
891 }
892
893 if ( layer->type() == QgsMapLayerType::MeshLayer )
894 {
895 disconnect( layer, &QgsMapLayer::rendererChanged, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
896 }
897
898 if ( layer->type() == QgsMapLayerType::PointCloudLayer )
899 {
900 QgsPointCloudLayer *pclayer = qobject_cast<QgsPointCloudLayer *>( layer );
901 disconnect( pclayer, &QgsPointCloudLayer::renderer3DChanged, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
902 disconnect( pclayer, &QgsPointCloudLayer::subsetStringChanged, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
903 }
904}
905
906void Qgs3DMapScene::finalizeNewEntity( Qt3DCore::QEntity *newEntity )
907{
908 // this is probably not the best place for material-specific configuration,
909 // maybe this could be more generalized when other materials need some specific treatment
910 for ( QgsLineMaterial *lm : newEntity->findChildren<QgsLineMaterial *>() )
911 {
912 connect( mCameraController, &QgsCameraController::viewportChanged, lm, [lm, this]
913 {
914 lm->setViewportSize( mCameraController->viewport().size() );
915 } );
916
917 lm->setViewportSize( cameraController()->viewport().size() );
918 }
919 // configure billboard's viewport when the viewport is changed.
920 for ( QgsPoint3DBillboardMaterial *bm : newEntity->findChildren<QgsPoint3DBillboardMaterial *>() )
921 {
922 connect( mCameraController, &QgsCameraController::viewportChanged, bm, [bm, this]
923 {
924 bm->setViewportSize( mCameraController->viewport().size() );
925 } );
926
927 bm->setViewportSize( mCameraController->viewport().size() );
928 }
929
930 // Finalize adding the 3D transparent objects by adding the layer components to the entities
931 QgsShadowRenderingFrameGraph *frameGraph = mEngine->frameGraph();
932 Qt3DRender::QLayer *transparentLayer = frameGraph->transparentObjectLayer();
933 for ( Qt3DRender::QMaterial *material : newEntity->findChildren<Qt3DRender::QMaterial *>() )
934 {
935 // This handles the phong material without data defined properties.
936 if ( Qt3DExtras::QDiffuseSpecularMaterial *ph = qobject_cast<Qt3DExtras::QDiffuseSpecularMaterial *>( material ) )
937 {
938 if ( ph->diffuse().value<QColor>().alphaF() != 1.0f )
939 {
940 Qt3DCore::QEntity *entity = qobject_cast<Qt3DCore::QEntity *>( ph->parent() );
941 if ( entity && !entity->components().contains( transparentLayer ) )
942 {
943 entity->addComponent( transparentLayer );
944 }
945 }
946 }
947 else
948 {
949 // This handles the phong material with data defined properties, the textured case and point (instanced) symbols.
950 Qt3DRender::QEffect *effect = material->effect();
951 if ( effect )
952 {
953 for ( const auto *parameter : effect->parameters() )
954 {
955 if ( parameter->name() == "opacity" && parameter->value() != 1.0f )
956 {
957 Qt3DCore::QEntity *entity = qobject_cast<Qt3DCore::QEntity *>( material->parent() );
958 if ( entity && !entity->components().contains( transparentLayer ) )
959 {
960 entity->addComponent( transparentLayer );
961 }
962 break;
963 }
964 }
965 }
966 }
967 }
968}
969
970int Qgs3DMapScene::maximumTextureSize() const
971{
972 QSurface *surface = mEngine->surface();
973 QOpenGLContext context;
974 context.create();
975 bool success = context.makeCurrent( surface );
976
977 if ( success )
978 {
979 QOpenGLFunctions openglFunctions = QOpenGLFunctions( &context );
980
981 GLint size;
982 openglFunctions.initializeOpenGLFunctions();
983 openglFunctions.glGetIntegerv( GL_MAX_TEXTURE_SIZE, &size );
984 return int( size );
985 }
986 else
987 {
988 return 4096; //we can't have a context to defined the max texture size, we use this reasonable value
989 }
990
991}
992
993void Qgs3DMapScene::addCameraViewCenterEntity( Qt3DRender::QCamera *camera )
994{
995 mEntityCameraViewCenter = new Qt3DCore::QEntity;
996
997 Qt3DCore::QTransform *trCameraViewCenter = new Qt3DCore::QTransform;
998 mEntityCameraViewCenter->addComponent( trCameraViewCenter );
999 connect( camera, &Qt3DRender::QCamera::viewCenterChanged, this, [trCameraViewCenter, camera]
1000 {
1001 trCameraViewCenter->setTranslation( camera->viewCenter() );
1002 } );
1003
1004 Qt3DExtras::QPhongMaterial *materialCameraViewCenter = new Qt3DExtras::QPhongMaterial;
1005 materialCameraViewCenter->setAmbient( Qt::red );
1006 mEntityCameraViewCenter->addComponent( materialCameraViewCenter );
1007
1008 Qt3DExtras::QSphereMesh *rendererCameraViewCenter = new Qt3DExtras::QSphereMesh;
1009 rendererCameraViewCenter->setRadius( 10 );
1010 mEntityCameraViewCenter->addComponent( rendererCameraViewCenter );
1011
1012 mEntityCameraViewCenter->setEnabled( mMap.showCameraViewCenter() );
1013 mEntityCameraViewCenter->setParent( this );
1014
1015 connect( &mMap, &Qgs3DMapSettings::showCameraViewCenterChanged, this, [this]
1016 {
1017 mEntityCameraViewCenter->setEnabled( mMap.showCameraViewCenter() );
1018 } );
1019}
1020
1021void Qgs3DMapScene::setSceneState( Qgs3DMapScene::SceneState state )
1022{
1023 if ( mSceneState == state )
1024 return;
1025 mSceneState = state;
1026 emit sceneStateChanged();
1027}
1028
1029void Qgs3DMapScene::updateSceneState()
1030{
1031 if ( mTerrainUpdateScheduled )
1032 {
1033 setSceneState( Updating );
1034 return;
1035 }
1036
1037 for ( QgsChunkedEntity *entity : std::as_const( mChunkEntities ) )
1038 {
1039 if ( entity->isEnabled() && entity->pendingJobsCount() > 0 )
1040 {
1041 setSceneState( Updating );
1042 return;
1043 }
1044 }
1045
1046 setSceneState( Ready );
1047}
1048
1049void Qgs3DMapScene::onSkyboxSettingsChanged()
1050{
1051 QgsSkyboxSettings skyboxSettings = mMap.skyboxSettings();
1052 if ( mSkybox != nullptr )
1053 {
1054 mSkybox->deleteLater();
1055 mSkybox = nullptr;
1056 }
1057
1058 mEngine->setFrustumCullingEnabled( !mMap.isSkyboxEnabled() );
1059
1060 if ( mMap.isSkyboxEnabled() )
1061 {
1062 QMap<QString, QString> faces;
1063 switch ( skyboxSettings.skyboxType() )
1064 {
1066 faces = skyboxSettings.cubeMapFacesPaths();
1067 mSkybox = new QgsCubeFacesSkyboxEntity(
1068 faces[QStringLiteral( "posX" )], faces[QStringLiteral( "posY" )], faces[QStringLiteral( "posZ" )],
1069 faces[QStringLiteral( "negX" )], faces[QStringLiteral( "negY" )], faces[QStringLiteral( "negZ" )],
1070 this
1071 );
1072 break;
1074 mSkybox = new QgsPanoramicSkyboxEntity( skyboxSettings.panoramicTexturePath(), this );
1075 break;
1076 }
1077 }
1078}
1079
1080void Qgs3DMapScene::onShadowSettingsChanged()
1081{
1082 QgsShadowRenderingFrameGraph *shadowRenderingFrameGraph = mEngine->frameGraph();
1083
1084 const QList< QgsLightSource * > lightSources = mMap.lightSources();
1085 QList< QgsDirectionalLightSettings * > directionalLightSources;
1086 for ( QgsLightSource *source : lightSources )
1087 {
1088 if ( source->type() == Qgis::LightSourceType::Directional )
1089 {
1090 directionalLightSources << qgis::down_cast< QgsDirectionalLightSettings * >( source );
1091 }
1092 }
1093
1094 QgsShadowSettings shadowSettings = mMap.shadowSettings();
1095 int selectedLight = shadowSettings.selectedDirectionalLight();
1096 if ( shadowSettings.renderShadows() && selectedLight >= 0 && selectedLight < directionalLightSources.count() )
1097 {
1098 shadowRenderingFrameGraph->setShadowRenderingEnabled( true );
1099 shadowRenderingFrameGraph->setShadowBias( shadowSettings.shadowBias() );
1100 shadowRenderingFrameGraph->setShadowMapResolution( shadowSettings.shadowMapResolution() );
1101 QgsDirectionalLightSettings light = *directionalLightSources.at( selectedLight );
1102 shadowRenderingFrameGraph->setupDirectionalLight( light, shadowSettings.maximumShadowRenderingDistance() );
1103 }
1104 else
1105 shadowRenderingFrameGraph->setShadowRenderingEnabled( false );
1106}
1107
1108void Qgs3DMapScene::onAmbientOcclusionSettingsChanged()
1109{
1110 QgsShadowRenderingFrameGraph *shadowRenderingFrameGraph = mEngine->frameGraph();
1111 QgsAmbientOcclusionSettings ambientOcclusionSettings = mMap.ambientOcclusionSettings();
1112 shadowRenderingFrameGraph->setAmbientOcclusionEnabled( ambientOcclusionSettings.isEnabled() );
1113 shadowRenderingFrameGraph->setAmbientOcclusionRadius( ambientOcclusionSettings.radius() );
1114 shadowRenderingFrameGraph->setAmbientOcclusionIntensity( ambientOcclusionSettings.intensity() );
1115 shadowRenderingFrameGraph->setAmbientOcclusionThreshold( ambientOcclusionSettings.threshold() );
1116}
1117
1118void Qgs3DMapScene::onDebugShadowMapSettingsChanged()
1119{
1120 QgsShadowRenderingFrameGraph *shadowRenderingFrameGraph = mEngine->frameGraph();
1121 shadowRenderingFrameGraph->setupShadowMapDebugging( mMap.debugShadowMapEnabled(), mMap.debugShadowMapCorner(), mMap.debugShadowMapSize() );
1122}
1123
1124void Qgs3DMapScene::onDebugDepthMapSettingsChanged()
1125{
1126 QgsShadowRenderingFrameGraph *shadowRenderingFrameGraph = mEngine->frameGraph();
1127 shadowRenderingFrameGraph->setupDepthMapDebugging( mMap.debugDepthMapEnabled(), mMap.debugDepthMapCorner(), mMap.debugDepthMapSize() );
1128}
1129
1130void Qgs3DMapScene::onDebugOverlayEnabledChanged()
1131{
1132 QgsShadowRenderingFrameGraph *shadowRenderingFrameGraph = mEngine->frameGraph();
1133 shadowRenderingFrameGraph->setDebugOverlayEnabled( mMap.isDebugOverlayEnabled() );
1134}
1135
1136void Qgs3DMapScene::onEyeDomeShadingSettingsChanged()
1137{
1138 QgsShadowRenderingFrameGraph *shadowRenderingFrameGraph = mEngine->frameGraph();
1139
1140 bool edlEnabled = mMap.eyeDomeLightingEnabled();
1141 double edlStrength = mMap.eyeDomeLightingStrength();
1142 double edlDistance = mMap.eyeDomeLightingDistance();
1143 shadowRenderingFrameGraph->setupEyeDomeLighting( edlEnabled, edlStrength, edlDistance );
1144}
1145
1146void Qgs3DMapScene::onCameraMovementSpeedChanged()
1147{
1148 mCameraController->setCameraMovementSpeed( mMap.cameraMovementSpeed() );
1149}
1150
1151void Qgs3DMapScene::onCameraNavigationModeChanged()
1152{
1153 mCameraController->setCameraNavigationMode( mMap.cameraNavigationMode() );
1154}
1155
1157{
1158 QVector<QString> notParsedLayers;
1159 Qgs3DSceneExporter exporter;
1160
1161 exporter.setTerrainResolution( exportSettings.terrrainResolution() );
1162 exporter.setSmoothEdges( exportSettings.smoothEdges() );
1163 exporter.setExportNormals( exportSettings.exportNormals() );
1164 exporter.setExportTextures( exportSettings.exportTextures() );
1165 exporter.setTerrainTextureResolution( exportSettings.terrainTextureResolution() );
1166 exporter.setScale( exportSettings.scale() );
1167
1168 for ( auto it = mLayerEntities.constBegin(); it != mLayerEntities.constEnd(); ++it )
1169 {
1170 QgsMapLayer *layer = it.key();
1171 Qt3DCore::QEntity *rootEntity = it.value();
1172 QgsMapLayerType layerType = layer->type();
1173 switch ( layerType )
1174 {
1176 if ( !exporter.parseVectorLayerEntity( rootEntity, qobject_cast<QgsVectorLayer *>( layer ) ) )
1177 notParsedLayers.push_back( layer->name() );
1178 break;
1186 notParsedLayers.push_back( layer->name() );
1187 break;
1188 }
1189 }
1190
1191 if ( mTerrain )
1192 exporter.parseTerrain( mTerrain, "Terrain" );
1193
1194 exporter.save( exportSettings.sceneName(), exportSettings.sceneFolderPath() );
1195
1196 if ( !notParsedLayers.empty() )
1197 {
1198 QString message = tr( "The following layers were not exported:" ) + "\n";
1199 for ( const QString &layerName : notParsedLayers )
1200 message += layerName + "\n";
1201 QgsMessageOutput::showMessage( tr( "3D exporter warning" ), message, QgsMessageOutput::MessageText );
1202 }
1203}
1204
1205QVector<const QgsChunkNode *> Qgs3DMapScene::getLayerActiveChunkNodes( QgsMapLayer *layer )
1206{
1207 QVector<const QgsChunkNode *> chunks;
1208 if ( !mLayerEntities.contains( layer ) ) return chunks;
1209 if ( QgsChunkedEntity *c = qobject_cast<QgsChunkedEntity *>( mLayerEntities[ layer ] ) )
1210 {
1211 for ( QgsChunkNode *n : c->activeNodes() )
1212 chunks.push_back( n );
1213 }
1214 return chunks;
1215}
1216
1218{
1219 QgsRectangle extent;
1220 extent.setMinimal();
1221
1222 for ( QgsMapLayer *layer : mLayerEntities.keys() )
1223 {
1224 Qt3DCore::QEntity *layerEntity = mLayerEntities[ layer ];
1225 QgsChunkedEntity *c = qobject_cast<QgsChunkedEntity *>( layerEntity );
1226 if ( !c )
1227 continue;
1228 QgsChunkNode *chunkNode = c->rootNode();
1229 QgsAABB bbox = chunkNode->bbox();
1230 QgsRectangle layerExtent = Qgs3DUtils::worldToLayerExtent( bbox, layer->crs(), mMap.origin(), mMap.crs(), mMap.transformContext() );
1231 extent.combineExtentWith( layerExtent );
1232 }
1233
1234 if ( mMap.terrainRenderingEnabled() )
1235 {
1236 if ( QgsTerrainGenerator *terrainGenerator = mMap.terrainGenerator() )
1237 {
1238 QgsRectangle terrainExtent = terrainGenerator->extent();
1239 QgsCoordinateTransform terrainToMapTransform( terrainGenerator->crs(), mMap.crs(), QgsProject::instance() );
1240 terrainToMapTransform.setBallparkTransformsAreAppropriate( true );
1241 terrainExtent = terrainToMapTransform.transformBoundingBox( terrainExtent );
1242 extent.combineExtentWith( terrainExtent );
1243 }
1244 }
1245
1246 return extent;
1247}
1248
1249void Qgs3DMapScene::addCameraRotationCenterEntity( QgsCameraController *controller )
1250{
1251 mEntityRotationCenter = new Qt3DCore::QEntity;
1252
1253 Qt3DCore::QTransform *trCameraViewCenter = new Qt3DCore::QTransform;
1254 mEntityRotationCenter->addComponent( trCameraViewCenter );
1255 Qt3DExtras::QPhongMaterial *materialCameraViewCenter = new Qt3DExtras::QPhongMaterial;
1256 materialCameraViewCenter->setAmbient( Qt::blue );
1257 mEntityRotationCenter->addComponent( materialCameraViewCenter );
1258 Qt3DExtras::QSphereMesh *rendererCameraViewCenter = new Qt3DExtras::QSphereMesh;
1259 rendererCameraViewCenter->setRadius( 10 );
1260 mEntityRotationCenter->addComponent( rendererCameraViewCenter );
1261 mEntityRotationCenter->setEnabled( true );
1262 mEntityRotationCenter->setParent( this );
1263
1264 connect( controller, &QgsCameraController::cameraRotationCenterChanged, this, [trCameraViewCenter]( QVector3D center )
1265 {
1266 trCameraViewCenter->setTranslation( center );
1267 } );
1268
1269 mEntityRotationCenter->setEnabled( mMap.showCameraRotationCenter() );
1270
1271 connect( &mMap, &Qgs3DMapSettings::showCameraRotationCenterChanged, this, [this]
1272 {
1273 mEntityRotationCenter->setEnabled( mMap.showCameraRotationCenter() );
1274 } );
1275}
1276
1277void Qgs3DMapScene::on3DAxisSettingsChanged()
1278{
1279 if ( m3DAxis )
1280 {
1281 m3DAxis->onAxisSettingsChanged();
1282 }
1283 else
1284 {
1285 if ( QgsWindow3DEngine *engine = dynamic_cast<QgsWindow3DEngine *>( mEngine ) )
1286 {
1287 m3DAxis = new Qgs3DAxis( static_cast<Qt3DExtras::Qt3DWindow *>( engine->window() ),
1288 engine->root(),
1289 this,
1290 mCameraController,
1291 &mMap );
1292 }
1293 }
1294}
@ 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.
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.
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:78
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 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.
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.
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.
QgsCoordinateReferenceSystem crs() const
Returns coordinate reference system used in the 3D scene.
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.
QgsCameraController::NavigationMode cameraNavigationMode() const
Returns the navigation mode used by the camera.
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.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context, which stores various information regarding which datum tran...
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 QgsRectangle worldToLayerExtent(const QgsAABB &bbox, const QgsCoordinateReferenceSystem &layerCrs, const QgsVector3D &mapOrigin, const QgsCoordinateReferenceSystem &mapCrs, const QgsCoordinateTransformContext &context)
Converts axis aligned bounding box in 3D world coordinates to extent in map layer CRS.
Definition: qgs3dutils.cpp:582
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:227
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:681
3
Definition: qgsaabb.h:34
float yMax
Definition: qgsaabb.h:85
float xMax
Definition: qgsaabb.h:84
float xMin
Definition: qgsaabb.h:81
float zMax
Definition: qgsaabb.h:86
float yMin
Definition: qgsaabb.h:82
float zMin
Definition: qgsaabb.h:83
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 ...
void setViewport(QRect viewport)
Sets viewport rectangle. Called internally from 3D canvas. Allows conversion of mouse coordinates.
void setCameraNavigationMode(QgsCameraController::NavigationMode navigationMode)
Sets the navigation mode used by the camera controller.
Qt3DRender::QCamera * camera
float distance() const
Returns distance of the camera from the point it is looking at.
void setCamera(Qt3DRender::QCamera *camera)
Assigns camera that should be controlled by this class. Called internally from 3D scene.
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 setTerrainEntity(QgsTerrainEntity *te)
Connects to object picker attached to terrain entity.
void setCameraMovementSpeed(double movementSpeed)
Sets the camera movement speed.
void cameraRotationCenterChanged(QVector3D position)
Emitted when the camera rotation center changes.
void viewportChanged()
Emitted when viewport rectangle has been updated.
Class for doing transforms between two map coordinate systems.
void setBallparkTransformsAreAppropriate(bool appropriate)
Sets whether approximate "ballpark" results are appropriate for this coordinate transform.
QgsRectangle transformBoundingBox(const QgsRectangle &rectangle, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool handle180Crossover=false) const SIP_THROW(QgsCsException)
Transforms a rectangle from the source CRS to the destination CRS.
A skybox constructed from a 6 cube faces.
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.
QgsMapLayerType type
Definition: qgsmaplayer.h:80
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:79
void renderer3DChanged()
Signal emitted when 3D renderer associated with the layer has changed.
void rendererChanged()
Signal emitted when renderer is changed.
virtual QgsMapLayerTemporalProperties * temporalProperties()
Returns the layer's temporal properties.
Definition: qgsmaplayer.h:1503
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.
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
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:477
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
void setMinimal() SIP_HOLDGIL
Set a rectangle so that min corner is at max and max corner is at min.
Definition: qgsrectangle.h:172
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:223
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle.
Definition: qgsrectangle.h:391
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 QgsRectangle extent() const =0
extent of the terrain in terrain's CRS
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.
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 QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
void selectionChanged(const QgsFeatureIds &selected, const QgsFeatureIds &deselected, bool clearAndSelect)
Emitted when selection was changed.
QgsMapLayerType
Types of layers that can be added to a map.
Definition: qgis.h:47
@ PointCloudLayer
Point cloud layer. Added in QGIS 3.18.
@ MeshLayer
Mesh layer. Added in QGIS 3.2.
@ VectorLayer
Vector layer.
@ RasterLayer
Raster layer.
@ GroupLayer
Composite group layer. Added in QGIS 3.24.
@ VectorTileLayer
Vector tile layer. Added in QGIS 3.14.
@ AnnotationLayer
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
@ PluginLayer
Plugin based layer.
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:2544
void addQLayerComponentsToHierarchy(Qt3DCore::QEntity *entity, const QVector< Qt3DRender::QLayer * > &layers)
QgsChunkedEntity::SceneState _sceneState(QgsCameraController *cameraController)
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