70#include <QOpenGLContext>
71#include <QOpenGLFunctions>
76#include <Qt3DExtras/QDiffuseSpecularMaterial>
77#include <Qt3DExtras/QForwardRenderer>
78#include <Qt3DExtras/QPhongAlphaMaterial>
79#include <Qt3DExtras/QPhongMaterial>
80#include <Qt3DExtras/QSphereMesh>
81#include <Qt3DLogic/QFrameAction>
82#include <Qt3DRender/QCamera>
83#include <Qt3DRender/QCullFace>
84#include <Qt3DRender/QDepthTest>
85#include <Qt3DRender/QEffect>
86#include <Qt3DRender/QMesh>
87#include <Qt3DRender/QRenderPass>
88#include <Qt3DRender/QRenderSettings>
89#include <Qt3DRender/QRenderState>
90#include <Qt3DRender/QSceneLoader>
91#include <Qt3DRender/QTechnique>
94#include "moc_qgs3dmapscene.cpp"
96using namespace Qt::StringLiterals;
105 onBackgroundColorChanged();
110 mEngine->renderSettings()->setRenderPolicy( Qt3DRender::QRenderSettings::OnDemand );
112 QRect viewportRect( QPoint( 0, 0 ), mEngine->size() );
118 float aspectRatio = ( float ) viewportRect.width() / viewportRect.height();
119 mEngine->camera()->lens()->setPerspectiveProjection( mMap.fieldOfView(), aspectRatio, 10.f, 10000.0f );
121 mFrameAction =
new Qt3DLogic::QFrameAction();
122 connect( mFrameAction, &Qt3DLogic::QFrameAction::triggered,
this, &Qgs3DMapScene::onFrameTriggered );
123 addComponent( mFrameAction );
129 mCameraController->resetGlobe( 10'000'000 );
131 mCameraController->resetView( 1000 );
133 addCameraViewCenterEntity( mEngine->camera() );
134 addCameraRotationCenterEntity( mCameraController );
139 createTerrainDeferred();
171 const QList<QgsMapLayer *> modelVectorLayers = mModelVectorLayers;
177 if ( renderer->
type() ==
"vector"_L1 )
180 if ( pointSymbol && pointSymbol->
shapeProperty( u
"model"_s ).toString() == url )
182 removeLayerEntity( layer );
183 addLayerEntity( layer );
186 else if ( renderer->
type() ==
"rulebased"_L1 )
192 if ( pointSymbol && pointSymbol->
shapeProperty( u
"model"_s ).toString() == url )
194 removeLayerEntity( layer );
195 addLayerEntity( layer );
210 onSkyboxSettingsChanged();
215 onEyeDomeShadingSettingsChanged();
217 onDebugShadowMapSettingsChanged();
218 onDebugDepthMapSettingsChanged();
220 onAmbientOcclusionSettingsChanged();
225 mOverlayUpdateTimer =
new QTimer(
this );
226 mOverlayUpdateTimer->setSingleShot(
true );
227 mOverlayUpdateTimer->setInterval( 250 );
228 connect( mOverlayUpdateTimer, &QTimer::timeout,
this, &Qgs3DMapScene::applyPendingOverlayUpdate );
231 onShowMapOverlayChanged();
233 onCameraMovementSpeedChanged();
235 on3DAxisSettingsChanged();
242 mCameraController->resetGlobe( 10'000'000 );
248 const double side = std::max( extent.
width(), extent.
height() );
249 double d = side / 2 / std::tan(
cameraController()->camera()->fieldOfView() / 2 * M_PI / 180 );
251 mCameraController->resetView(
static_cast<float>( d ) );
262 const double xSide = std::abs( p1.
x() - p2.
x() );
263 const double ySide = std::abs( p1.
y() - p2.
y() );
264 const double side = std::max( xSide, ySide );
266 const double fov = qDegreesToRadians(
cameraController()->camera()->fieldOfView() );
267 double distance = side / 2.0f / std::tan( fov / 2.0f );
272 distance += zRange.
upper();
276 mCameraController->setViewFromTop(
277 static_cast<float>( center.
x() - origin.
x() ),
278 static_cast<float>( center.
y() - origin.
y() ),
279 static_cast<float>( distance )
286 Qt3DRender::QCamera *camera = mCameraController->camera();
287 QVector<QgsPointXY> extent;
288 QVector<int> pointsOrder = { 0, 1, 3, 2 };
289 for (
int i : pointsOrder )
291 const QPoint p( ( ( i >> 0 ) & 1 ) ? 0 : mEngine->size().width(), ( ( i >> 1 ) & 1 ) ? 0 : mEngine->size().height() );
294 if ( dir.z() == 0.0 )
295 dir.setZ( 0.000001 );
296 double t = -ray.
origin().z() / dir.z();
300 t = camera->farPlane();
305 t = std::min<float>( t, camera->farPlane() );
307 QVector3D planePoint = ray.
origin() + t * dir;
308 QgsVector3D pMap = mMap.worldToMapCoordinates( planePoint );
317 for ( Qgs3DMapSceneEntity *entity : std::as_const( mSceneEntities ) )
318 count += entity->pendingJobsCount();
324 Qt3DRender::QCamera *camera = mCameraController->camera();
325 const double fov = camera->fieldOfView();
326 const QSize size = mEngine->size();
327 const int screenSizePx = std::max( size.width(), size.height() );
331 const double frustumWidthAtDistance = 2 * distance * tan( fov / 2 );
332 const double err = frustumWidthAtDistance * epsilon / screenSizePx;
336void Qgs3DMapScene::onCameraChanged()
339 updateCameraNearFarPlanes();
341 onShadowSettingsChanged();
345 schedule2DMapOverlayUpdate();
353 constexpr float ORIGIN_SHIFT_THRESHOLD = 10'000;
354 if ( mSceneOriginShiftEnabled && mEngine->
camera()->position().length() > ORIGIN_SHIFT_THRESHOLD )
362bool Qgs3DMapScene::updateScene(
bool forceUpdate )
364 if ( !mSceneUpdatesEnabled )
370 QgsEventTracing::ScopedEvent traceEvent( u
"3D"_s, forceUpdate ? u
"Force update scene"_s : u
"Update scene"_s );
372 Qgs3DMapSceneEntity::SceneContext sceneContext;
373 Qt3DRender::QCamera *camera = mEngine->camera();
374 sceneContext.cameraFov = camera->fieldOfView();
375 sceneContext.cameraPos = camera->position();
376 const QSize size = mEngine->size();
377 sceneContext.screenSizePx = std::max( size.width(), size.height() );
385 QMatrix4x4 projMatrix;
386 switch ( mMap.projectionType() )
388 case Qt3DRender::QCameraLens::PerspectiveProjection:
390 float fovRadians = ( camera->fieldOfView() / 2.0f ) *
static_cast<float>( M_PI ) / 180.0f;
391 float fovCotan = std::cos( fovRadians ) / std::sin( fovRadians );
394 fovCotan / camera->aspectRatio(), 0, 0, 0,
402 case Qt3DRender::QCameraLens::OrthographicProjection:
404 Qt3DRender::QCameraLens *lens = camera->lens();
407 2.0f / ( lens->right() - lens->left() ), 0, 0, 0,
408 0, 2.0f / ( lens->top() - lens->bottom() ), 0, 0,
410 -( lens->left() + lens->right() ) / ( lens->right() - lens->left() ), -( lens->top() + lens->bottom() ) / ( lens->top() - lens->bottom() ), -1.0f, 1.0f
417 projMatrix = camera->projectionMatrix();
419 sceneContext.viewProjectionMatrix = projMatrix * camera->viewMatrix();
422 bool anyUpdated =
false;
423 for ( Qgs3DMapSceneEntity *entity : std::as_const( mSceneEntities ) )
425 if ( forceUpdate || ( entity->isEnabled() && entity->needsUpdate() ) )
428 entity->handleSceneUpdate( sceneContext );
429 if ( entity->hasReachedGpuMemoryLimit() )
439bool Qgs3DMapScene::updateCameraNearFarPlanes()
454 QMatrix4x4 viewMatrix = camera->viewMatrix();
460 for ( Qgs3DMapSceneEntity *se : std::as_const( mSceneEntities ) )
462 const QgsRange<float> depthRange = se->getNearFarPlaneRange( viewMatrix );
464 fnear = std::min( fnear, depthRange.
lower() );
465 ffar = std::max( ffar, depthRange.
upper() );
474 if ( fnear == 1e9 && ffar == 0 )
477 sceneZRange = sceneZRange.
isInfinite() ? QgsDoubleRange( 0.0, 0.0 ) : sceneZRange;
484 std::swap( fnear, ffar );
487 float newFar = ffar * 2;
488 float newNear = fnear / 2;
491 camera->setFarPlane( newFar );
492 camera->setNearPlane( newNear );
499void Qgs3DMapScene::onFrameTriggered(
float dt )
501 QgsEventTracing::addEvent( QgsEventTracing::EventType::Instant, u
"3D"_s, u
"Frame begins"_s );
503 mCameraController->frameTriggered( dt );
508 updateCameraNearFarPlanes();
511 static int frameCount = 0;
512 static float accumulatedTime = 0.0f;
514 if ( !mMap.isFpsCounterEnabled() )
522 accumulatedTime += dt;
523 if ( accumulatedTime >= 0.2f )
525 float fps = ( float ) frameCount / accumulatedTime;
527 accumulatedTime = 0.0f;
532void Qgs3DMapScene::update2DMapOverlay(
const QVector<QgsPointXY> &extent2DAsPoints )
534 QgsFrameGraph *frameGraph = mEngine->frameGraph();
537 if ( !mMap.is2DMapOverlayEnabled() )
539 if ( mMapOverlayEntity )
541 mMapOverlayEntity.reset();
543 overlayRenderView.
setEnabled( mMap.debugShadowMapEnabled() || mMap.debugDepthMapEnabled() );
547 if ( !mMapOverlayEntity )
549 QgsWindow3DEngine *
engine = qobject_cast<QgsWindow3DEngine *>( mEngine );
550 mMapOverlayEntity.reset(
new QgsMapOverlayEntity(
engine, &overlayRenderView, &mMap,
this ) );
551 mMapOverlayEntity->setEnabled(
true );
556 Qt3DRender::QCamera *camera = mEngine->camera();
557 const QgsVector3D extentCenter3D = mMap.worldToMapCoordinates( camera->position() );
558 const QgsPointXY extentCenter2D( extentCenter3D.
x(), extentCenter3D.
y() );
565 double minHalfExtent = std::numeric_limits<double>::max();
566 double maxHalfExtent = 0.0;
567 for (
const QgsPointXY &extentPoint : extent2DAsPoints )
569 const double distance = extentCenter2D.distance( extentPoint );
570 minHalfExtent = std::min( minHalfExtent, distance );
571 maxHalfExtent = std::max( maxHalfExtent, distance );
575 const double sceneHalfExtent = 0.6 * std::max( fullExtent.
width(), fullExtent.
height() );
577 minHalfExtent = std::min( 50., minHalfExtent );
578 maxHalfExtent = std::min( 100., maxHalfExtent );
579 const double smoothFactor = std::sin( mCameraController->pitch() / 90.0 * M_PI_2 );
582 const double adjustedHalfExtent = std::min( 3.0 * ( minHalfExtent + smoothFactor * maxHalfExtent ), sceneHalfExtent );
585 const bool showFrustum = mMap.viewFrustumVisualizationEnabled();
586 mMapOverlayEntity->update( overviewExtent, extent2DAsPoints, mCameraController->yaw(), showFrustum );
589void Qgs3DMapScene::createTerrain()
593 mSceneEntities.removeOne( mTerrain );
601 mSceneEntities.removeOne( mGlobe );
607 if ( !mTerrainUpdateScheduled )
610 QTimer::singleShot( 0,
this, &Qgs3DMapScene::createTerrainDeferred );
611 mTerrainUpdateScheduled =
true;
620void Qgs3DMapScene::createTerrainDeferred()
622 QgsChunkedEntity *terrainOrGlobe =
nullptr;
626 mGlobe =
new QgsGlobeEntity( &mMap );
627 terrainOrGlobe = mGlobe;
629 else if ( mMap.sceneMode() ==
Qgis::SceneMode::Local && mMap.terrainRenderingEnabled() && mMap.terrainGenerator() )
631 double tile0width = mMap.terrainGenerator()->rootChunkExtent().width();
632 int maxZoomLevel =
Qgs3DUtils::maxZoomLevel( tile0width, mMap.terrainSettings()->mapTileResolution(), mMap.terrainSettings()->maximumGroundError() );
633 const QgsBox3D rootBox3D = mMap.terrainGenerator()->rootChunkBox3D( mMap );
634 float rootError = mMap.terrainGenerator()->rootChunkError( mMap );
635 const QgsBox3D clippingBox3D( mMap.extent(), rootBox3D.
zMinimum(), rootBox3D.
zMaximum() );
636 mMap.terrainGenerator()->setupQuadtree( rootBox3D, rootError, maxZoomLevel, clippingBox3D );
638 mTerrain =
new QgsTerrainEntity( &mMap );
639 terrainOrGlobe = mTerrain;
642 if ( terrainOrGlobe )
645 QgsFrameGraph *frameGraph = mEngine->frameGraph();
649 terrainOrGlobe->setParent(
this );
650 terrainOrGlobe->setShowBoundingBoxes( mMap.showTerrainBoundingBoxes() );
652 mSceneEntities << terrainOrGlobe;
655 connect( terrainOrGlobe, &Qgs3DMapSceneEntity::newEntityCreated,
this, [
this]( Qt3DCore::QEntity *entity ) {
657 const QList<QgsGeoTransform *> transforms = entity->findChildren<QgsGeoTransform *>();
658 for ( QgsGeoTransform *transform : transforms )
660 transform->setOrigin( mMap.origin() );
664 handleClippingOnEntity( entity );
669 const QList<QgsMapLayer *>
layers = mMap.layers();
670 for ( QgsMapLayer *layer :
layers )
673 removeLayerEntity( layer );
676 addLayerEntity( layer );
681 mTerrainUpdateScheduled =
false;
684void Qgs3DMapScene::onBackgroundColorChanged()
686 mEngine->setClearColor( mMap.backgroundColor() );
689void Qgs3DMapScene::updateLights()
691 for ( Qt3DCore::QEntity *entity : std::as_const( mLightEntities ) )
692 entity->deleteLater();
693 mLightEntities.clear();
695 QgsFrameGraph *frameGraph = mEngine->frameGraph();
696 const QList<QgsLightSource *> newLights = mMap.lightSources();
697 for (
const QgsLightSource *source : newLights )
699 Qt3DCore::QEntity *entity = source->createEntity( mMap,
this );
701 mLightEntities.append( entity );
704 onShadowSettingsChanged();
707void Qgs3DMapScene::updateCameraLens()
709 mEngine->camera()->lens()->setFieldOfView( mMap.fieldOfView() );
710 mEngine->camera()->lens()->setProjectionType( mMap.projectionType() );
714void Qgs3DMapScene::onLayerRenderer3DChanged()
716 QgsMapLayer *layer = qobject_cast<QgsMapLayer *>( sender() );
720 removeLayerEntity( layer );
723 addLayerEntity( layer );
726void Qgs3DMapScene::onLayersChanged()
728 QSet<QgsMapLayer *> layersBefore = qgis::listToSet( mLayerEntities.keys() );
729 QList<QgsMapLayer *> layersAdded;
730 const QList<QgsMapLayer *>
layers = mMap.layers();
731 for ( QgsMapLayer *layer :
layers )
733 if ( !layersBefore.contains( layer ) )
735 layersAdded << layer;
739 layersBefore.remove( layer );
744 for ( QgsMapLayer *layer : std::as_const( layersBefore ) )
746 removeLayerEntity( layer );
749 for ( QgsMapLayer *layer : std::as_const( layersAdded ) )
751 addLayerEntity( layer );
757 const QList<QgsMapLayer *>
layers = mLayerEntities.keys();
762 if ( temporalProperties->isActive() )
764 removeLayerEntity( layer );
765 addLayerEntity( layer );
773 Q_ASSERT( sceneNewEntity );
775 mSceneEntities.append( sceneNewEntity );
777 sceneNewEntity->setParent(
this );
779 finalizeNewEntity( sceneNewEntity );
781 connect( sceneNewEntity, &Qgs3DMapSceneEntity::newEntityCreated,
this, [
this]( Qt3DCore::QEntity *entity ) {
782 finalizeNewEntity( entity );
784 updateCameraNearFarPlanes();
794 Q_ASSERT( sceneEntity );
796 mSceneEntities.removeOne( sceneEntity );
798 sceneEntity->deleteLater();
802void Qgs3DMapScene::addLayerEntity(
QgsMapLayer *layer )
814 if ( renderer->
type() ==
"vector"_L1 )
822 mModelVectorLayers.append( layer );
826 else if ( renderer->
type() ==
"rulebased"_L1 )
829 for (
auto rule : rules )
831 const QgsPoint3DSymbol *pointSymbol =
dynamic_cast<const QgsPoint3DSymbol *
>( rule->symbol() );
834 mModelVectorLayers.append( layer );
842 QgsMeshLayer3DRenderer *meshRenderer =
static_cast<QgsMeshLayer3DRenderer *
>( renderer );
843 meshRenderer->
setLayer(
static_cast<QgsMeshLayer *
>( layer ) );
847 QgsMesh3DSymbol *sym = meshRenderer->
symbol()->
clone();
853 QgsPointCloudLayer3DRenderer *pointCloudRenderer =
static_cast<QgsPointCloudLayer3DRenderer *
>( renderer );
854 pointCloudRenderer->
setLayer(
static_cast<QgsPointCloudLayer *
>( layer ) );
858 QgsTiledSceneLayer3DRenderer *tiledSceneRenderer =
static_cast<QgsTiledSceneLayer3DRenderer *
>( renderer );
859 tiledSceneRenderer->
setLayer(
static_cast<QgsTiledSceneLayer *
>( layer ) );
863 auto annotationLayerRenderer = qgis::down_cast<QgsAnnotationLayer3DRenderer *>( renderer );
864 annotationLayerRenderer->setLayer( qobject_cast<QgsAnnotationLayer *>( layer ) );
867 Qt3DCore::QEntity *newEntity = renderer->
createEntity( &mMap );
870 mLayerEntities.insert( layer, newEntity );
872 if ( Qgs3DMapSceneEntity *sceneNewEntity = qobject_cast<Qgs3DMapSceneEntity *>( newEntity ) )
879 newEntity->setParent(
this );
880 finalizeNewEntity( newEntity );
889 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
902 QgsPointCloudLayer *pclayer = qobject_cast<QgsPointCloudLayer *>( layer );
908void Qgs3DMapScene::removeLayerEntity(
QgsMapLayer *layer )
910 Qt3DCore::QEntity *entity = mLayerEntities.take( layer );
912 if ( Qgs3DMapSceneEntity *sceneEntity = qobject_cast<Qgs3DMapSceneEntity *>( entity ) )
920 entity->deleteLater();
927 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
931 mModelVectorLayers.removeAll( layer );
941 QgsPointCloudLayer *pclayer = qobject_cast<QgsPointCloudLayer *>( layer );
948void Qgs3DMapScene::finalizeNewEntity( Qt3DCore::QEntity *newEntity )
951 const QList<QgsGeoTransform *> transforms = newEntity->findChildren<QgsGeoTransform *>();
952 for ( QgsGeoTransform *transform : transforms )
954 transform->setOrigin( mMap.origin() );
958 handleClippingOnEntity( newEntity );
962 const QList<QgsLineMaterial *> childLineMaterials = newEntity->findChildren<QgsLineMaterial *>();
963 for ( QgsLineMaterial *lm : childLineMaterials )
967 lm->setViewportSize( mEngine->size() );
970 const QList<QgsPoint3DBillboardMaterial *> childBillboardMaterials = newEntity->findChildren<QgsPoint3DBillboardMaterial *>();
971 for ( QgsPoint3DBillboardMaterial *bm : childBillboardMaterials )
975 bm->setViewportSize( mEngine->size() );
978 QgsFrameGraph *frameGraph = mEngine->frameGraph();
982 const QVector<Qt3DRender::QLayer *>
layers = newEntity->componentsOfType<Qt3DRender::QLayer>();
992 const QList<Qt3DRender::QMaterial *> childMaterials = newEntity->findChildren<Qt3DRender::QMaterial *>();
993 for ( Qt3DRender::QMaterial *material : childMaterials )
996 if ( Qt3DExtras::QDiffuseSpecularMaterial *ph = qobject_cast<Qt3DExtras::QDiffuseSpecularMaterial *>( material ) )
998 if ( ph->diffuse().value<QColor>().alphaF() != 1.0f )
1000 Qt3DCore::QEntity *entity = qobject_cast<Qt3DCore::QEntity *>( ph->parent() );
1001 if ( entity && !entity->components().contains( transparentLayer ) )
1003 entity->addComponent( transparentLayer );
1024 else if ( QgsPoint3DBillboardMaterial *billboardMaterial = qobject_cast<QgsPoint3DBillboardMaterial *>( material ) )
1026 Qt3DCore::QEntity *entity = qobject_cast<Qt3DCore::QEntity *>( billboardMaterial->parent() );
1027 if ( entity && !entity->components().contains( transparentLayer ) )
1029 entity->addComponent( transparentLayer );
1036 Qt3DRender::QEffect *effect = material->effect();
1039 const QVector<Qt3DRender::QParameter *> parameters = effect->parameters();
1040 for (
const Qt3DRender::QParameter *parameter : parameters )
1042 if ( parameter->name() ==
"opacity" && parameter->value() != 1.0f )
1044 Qt3DCore::QEntity *entity = qobject_cast<Qt3DCore::QEntity *>( material->parent() );
1045 if ( entity && !entity->components().contains( transparentLayer ) )
1047 entity->addComponent( transparentLayer );
1057int Qgs3DMapScene::maximumTextureSize()
const
1059 QSurface *surface = mEngine->surface();
1060 QOpenGLContext context;
1062 bool success = context.makeCurrent( surface );
1066 QOpenGLFunctions openglFunctions = QOpenGLFunctions( &context );
1069 openglFunctions.initializeOpenGLFunctions();
1070 openglFunctions.glGetIntegerv( GL_MAX_TEXTURE_SIZE, &size );
1079void Qgs3DMapScene::addCameraViewCenterEntity( Qt3DRender::QCamera *camera )
1081 mEntityCameraViewCenter =
new Qt3DCore::QEntity;
1083 Qt3DCore::QTransform *trCameraViewCenter =
new Qt3DCore::QTransform;
1084 mEntityCameraViewCenter->addComponent( trCameraViewCenter );
1085 connect( camera, &Qt3DRender::QCamera::viewCenterChanged,
this, [trCameraViewCenter, camera] { trCameraViewCenter->setTranslation( camera->viewCenter() ); } );
1087 Qt3DExtras::QPhongMaterial *materialCameraViewCenter =
new Qt3DExtras::QPhongMaterial;
1088 materialCameraViewCenter->setAmbient( Qt::red );
1089 mEntityCameraViewCenter->addComponent( materialCameraViewCenter );
1091 Qt3DExtras::QSphereMesh *rendererCameraViewCenter =
new Qt3DExtras::QSphereMesh;
1092 rendererCameraViewCenter->setRadius( 10 );
1093 mEntityCameraViewCenter->addComponent( rendererCameraViewCenter );
1095 mEntityCameraViewCenter->setEnabled( mMap.showCameraViewCenter() );
1096 mEntityCameraViewCenter->setParent(
this );
1103 if ( mSceneState == state )
1105 mSceneState = state;
1109void Qgs3DMapScene::updateSceneState()
1111 if ( mTerrainUpdateScheduled )
1117 for ( Qgs3DMapSceneEntity *entity : std::as_const( mSceneEntities ) )
1119 if ( entity->isEnabled() && entity->pendingJobsCount() > 0 )
1126 setSceneState(
Ready );
1129void Qgs3DMapScene::onSkyboxSettingsChanged()
1131 QgsSkyboxSettings skyboxSettings = mMap.skyboxSettings();
1134 mSkybox->deleteLater();
1138 mEngine->setFrustumCullingEnabled( !mMap.isSkyboxEnabled() );
1140 if ( mMap.isSkyboxEnabled() )
1142 QMap<QString, QString> faces;
1147 mSkybox =
new QgsCubeFacesSkyboxEntity( faces[u
"posX"_s], faces[u
"posY"_s], faces[u
"posZ"_s], faces[u
"negX"_s], faces[u
"negY"_s], faces[u
"negZ"_s],
this );
1156void Qgs3DMapScene::onShadowSettingsChanged()
1158 mEngine->frameGraph()->updateShadowSettings( mMap.shadowSettings(), mMap.lightSources() );
1161void Qgs3DMapScene::onAmbientOcclusionSettingsChanged()
1163 mEngine->frameGraph()->updateAmbientOcclusionSettings( mMap.ambientOcclusionSettings() );
1166void Qgs3DMapScene::onDebugShadowMapSettingsChanged()
1168 mEngine->frameGraph()->updateDebugShadowMapSettings( mMap );
1171void Qgs3DMapScene::onDebugDepthMapSettingsChanged()
1173 mEngine->frameGraph()->updateDebugDepthMapSettings( mMap );
1176void Qgs3DMapScene::onDebugOverlayEnabledChanged()
1178 mEngine->frameGraph()->setDebugOverlayEnabled( mMap.isDebugOverlayEnabled() );
1179 mEngine->renderSettings()->setRenderPolicy( mMap.isDebugOverlayEnabled() ? Qt3DRender::QRenderSettings::Always : Qt3DRender::QRenderSettings::OnDemand );
1182void Qgs3DMapScene::onEyeDomeShadingSettingsChanged()
1184 mEngine->frameGraph()->updateEyeDomeSettings( mMap );
1187void Qgs3DMapScene::onShowMapOverlayChanged()
1190 update2DMapOverlay( extent2D );
1193void Qgs3DMapScene::onCameraMovementSpeedChanged()
1195 mCameraController->setCameraMovementSpeed( mMap.cameraMovementSpeed() );
1198void Qgs3DMapScene::onCameraNavigationModeChanged()
1200 mCameraController->setCameraNavigationMode( mMap.cameraNavigationMode() );
1205 QVector<QString> notParsedLayers;
1216 for (
auto it = mLayerEntities.constBegin(); it != mLayerEntities.constEnd(); ++it )
1219 Qt3DCore::QEntity *rootEntity = it.value();
1221 switch ( layerType )
1225 notParsedLayers.push_back( layer->
name() );
1235 notParsedLayers.push_back( layer->
name() );
1249 if ( !notParsedLayers.empty() )
1251 QString message = tr(
"The following layers were not exported:" ) +
"\n";
1252 for (
const QString &layerName : notParsedLayers )
1253 message += layerName +
"\n";
1262 QVector<const QgsChunkNode *> chunks;
1263 if ( !mLayerEntities.contains( layer ) )
1265 if ( QgsChunkedEntity *
c = qobject_cast<QgsChunkedEntity *>( mLayerEntities[layer] ) )
1267 const QList<QgsChunkNode *> activeNodes =
c->activeNodes();
1268 for ( QgsChunkNode *n : activeNodes )
1269 chunks.push_back( n );
1276 return mMap.extent();
1281 double zMin = std::numeric_limits<double>::max();
1282 double zMax = std::numeric_limits<double>::lowest();
1283 if ( mMap.terrainRenderingEnabled() && mTerrain && !ignoreTerrain )
1285 const QgsBox3D box3D = mTerrain->rootNode()->box3D();
1286 zMin = std::min( zMin, box3D.
zMinimum() );
1287 zMax = std::max( zMax, box3D.
zMaximum() );
1290 for (
auto it = mLayerEntities.constBegin(); it != mLayerEntities.constEnd(); it++ )
1293 switch ( layer->
type() )
1299 zMin = std::min( zMin, zRange.
lower() );
1300 zMax = std::max( zMax, zRange.
upper() );
1305 QgsMeshLayer *meshLayer = qobject_cast<QgsMeshLayer *>( layer );
1313 zMin = std::min( zMin, verticalGroupMetadata.
minimum() * verticalScale );
1314 zMax = std::max( zMax, verticalGroupMetadata.
maximum() * verticalScale );
1324 zMin = std::min( zMin, zRange.
lower() );
1325 zMax = std::max( zMax, zRange.
upper() );
1338 const QgsDoubleRange zRange( std::min( zMin, std::numeric_limits<double>::max() ), std::max( zMax, std::numeric_limits<double>::lowest() ) );
1349 mEntityRotationCenter =
new Qt3DCore::QEntity;
1351 Qt3DCore::QTransform *trRotationCenter =
new Qt3DCore::QTransform;
1352 mEntityRotationCenter->addComponent( trRotationCenter );
1353 Qt3DExtras::QPhongMaterial *materialRotationCenter =
new Qt3DExtras::QPhongMaterial;
1354 materialRotationCenter->setAmbient( Qt::blue );
1355 mEntityRotationCenter->addComponent( materialRotationCenter );
1356 Qt3DExtras::QSphereMesh *rendererRotationCenter =
new Qt3DExtras::QSphereMesh;
1357 rendererRotationCenter->setRadius( 10 );
1358 mEntityRotationCenter->addComponent( rendererRotationCenter );
1359 mEntityRotationCenter->setEnabled(
false );
1360 mEntityRotationCenter->setParent(
this );
1367void Qgs3DMapScene::on3DAxisSettingsChanged()
1371 m3DAxis->onAxisSettingsChanged();
1375 if ( QgsWindow3DEngine *
engine =
dynamic_cast<QgsWindow3DEngine *
>( mEngine ) )
1377 m3DAxis =
new Qgs3DAxis(
static_cast<Qgs3DMapCanvas *
>(
engine->window() ),
engine->root(),
this, mCameraController, &mMap );
1382void Qgs3DMapScene::onOriginChanged()
1384 const QList<QgsGeoTransform *> geoTransforms = findChildren<QgsGeoTransform *>();
1385 for ( QgsGeoTransform *transform : geoTransforms )
1387 transform->setOrigin( mMap.origin() );
1390 const QList<QgsGeoTransform *> rubberBandGeoTransforms = mEngine->frameGraph()->rubberBandsRootEntity()->findChildren<QgsGeoTransform *>();
1391 for ( QgsGeoTransform *transform : rubberBandGeoTransforms )
1393 transform->setOrigin( mMap.origin() );
1396 const QgsVector3D oldOrigin = mCameraController->origin();
1397 mCameraController->setOrigin( mMap.origin() );
1399 if ( !mClipPlanesEquations.isEmpty() )
1408 QList<QVector4D> newPlanes;
1409 QgsVector3D originShift = mMap.origin() - oldOrigin;
1410 for ( QVector4D plane : std::as_const( mClipPlanesEquations ) )
1412 plane.setW( originShift.
x() * plane.x() + originShift.
y() * plane.y() + originShift.
z() * plane.z() + plane.w() );
1413 newPlanes.append( plane );
1419void Qgs3DMapScene::handleClippingOnEntity( QEntity *entity )
const
1421 if ( mClipPlanesEquations.isEmpty() )
1423 for ( QgsMaterial *material : entity->componentsOfType<QgsMaterial>() )
1425 material->disableClipping();
1430 for ( QgsMaterial *material : entity->componentsOfType<QgsMaterial>() )
1432 material->enableClipping( mClipPlanesEquations );
1438 for ( QObject *child : entity->children() )
1440 Qt3DCore::QEntity *childEntity = qobject_cast<Qt3DCore::QEntity *>( child );
1443 handleClippingOnEntity( childEntity );
1448void Qgs3DMapScene::handleClippingOnAllEntities()
const
1452 for (
auto it = mLayerEntities.constBegin(); it != mLayerEntities.constEnd(); ++it )
1454 handleClippingOnEntity( it.value() );
1458 handleClippingOnEntity( mTerrain );
1462 handleClippingOnEntity( mGlobe );
1470 QgsDebugMsgLevel( u
"Qgs3DMapScene::enableClipping: it is not possible to use more than %1 clipping planes."_s.arg( mMaxClipPlanes ), 2 );
1478 handleClippingOnAllEntities();
1483 mClipPlanesEquations.clear();
1486 mEngine->frameGraph()->removeClipPlanes();
1489 handleClippingOnAllEntities();
1492void Qgs3DMapScene::onStopUpdatesChanged()
1497void Qgs3DMapScene::schedule2DMapOverlayUpdate()
1500 if ( mMap.is2DMapOverlayEnabled() && mOverlayUpdateTimer && !mOverlayUpdateTimer->isActive() )
1502 mOverlayUpdateTimer->start();
1506void Qgs3DMapScene::applyPendingOverlayUpdate()
1508 if ( mMap.is2DMapOverlayEnabled() )
1511 update2DMapOverlay( extent2D );
LayerType
Types of layers that can be added to a map.
@ Group
Composite group layer. Added in QGIS 3.24.
@ Plugin
Plugin based layer.
@ TiledScene
Tiled scene layer. Added in QGIS 3.34.
@ Annotation
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
@ VectorTile
Vector tile layer. Added in QGIS 3.14.
@ Mesh
Mesh layer. Added in QGIS 3.2.
@ PointCloud
Point cloud layer. Added in QGIS 3.18.
@ Globe
Scene is represented as a globe using a geocentric CRS.
@ Local
Local scene based on a projected CRS.
Manages the various settings the user can choose from when exporting a 3D scene.
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.
bool terrainExportEnabled() const
Returns whether terrain export is enabled.
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 viewed2DExtentFrom3DChanged(QVector< QgsPointXY > extent)
Emitted when the viewed 2D extent seen by the 3D camera has changed.
QList< QVector4D > clipPlaneEquations() const
Returns list of clipping planes if clipping is enabled, otherwise an empty list.
static std::function< QMap< QString, Qgs3DMapScene * >()> sOpenScenesFunction
Static function for returning open 3D map scenes.
void fpsCountChanged(float fpsCount)
Emitted when the FPS count changes.
void setViewFrom2DExtent(const QgsRectangle &extent)
Resets camera view to show the extent extent (top view).
void disableClipping()
Disables OpenGL clipping.
QVector< const QgsChunkNode * > getLayerActiveChunkNodes(QgsMapLayer *layer) SIP_SKIP
Returns the active chunk nodes of layer.
void gpuMemoryLimitReached()
Emitted when one of the entities reaches its GPU memory limit and it is not possible to lower the GPU...
static Q_DECL_DEPRECATED QMap< QString, Qgs3DMapScene * > openScenes() SIP_DEPRECATED
Returns a map of 3D map scenes (by name) open in the QGIS application.
QgsCameraController * cameraController() const
Returns camera controller.
SceneState
Enumeration of possible states of the 3D scene.
@ Ready
The scene is fully loaded/updated.
@ Updating
The scene is still being loaded/updated.
bool exportScene(const Qgs3DMapExportSettings &exportSettings)
Exports the scene according to the scene export settings Returns false if the operation failed.
int totalPendingJobsCount() const
Returns number of pending jobs for all chunked entities.
QList< QgsMapLayer * > layers() const SIP_SKIP
Returns the layers that contain chunked entities.
void addSceneEntity(Qgs3DMapSceneEntity *entity) SIP_SKIP
Adds a 3D map scene entity to the scene.
void updateTemporal()
Updates the temporale entities.
void totalPendingJobsCountChanged()
Emitted when the total number of pending jobs changes.
Qgs3DMapScene(Qgs3DMapSettings &map, QgsAbstract3DEngine *engine) SIP_SKIP
Constructs a 3D scene based on map settings and Qt 3D renderer configuration.
void fpsCounterEnabledChanged(bool fpsCounterEnabled)
Emitted when the FPS counter is activated or deactivated.
void removeSceneEntity(Qgs3DMapSceneEntity *entity) SIP_SKIP
Removes a 3D scene entity for the scene.
QgsDoubleRange elevationRange(bool ignoreTerrain=false) const
Returns the scene's elevation range.
QgsRectangle sceneExtent() const
Returns the scene extent in the map's CRS.
void sceneStateChanged()
Emitted when the scene's state has changed.
QgsAbstract3DEngine * engine() const SIP_SKIP
Returns the abstract 3D engine.
QVector< QgsPointXY > viewFrustum2DExtent() const
Calculates the 2D extent viewed by the 3D camera as the vertices of the viewed trapezoid.
void enableClipping(const QList< QVector4D > &clipPlaneEquations)
Enables OpenGL clipping based on the planes equations defined in clipPlaneEquations.
void terrainEntityChanged()
Emitted when the current terrain entity is replaced by a new one.
void viewZoomFull()
Resets camera view to show the whole scene (top view).
double worldSpaceError(double epsilon, double distance) const
Given screen error (in pixels) and distance from camera (in 3D world coordinates),...
void extentChanged()
Emitted when the 3d view's 2d extent has changed.
void originChanged()
Emitted when the world's origin point has been shifted.
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.
void debugDepthMapSettingsChanged()
Emitted when depth map debugging has changed.
void backgroundColorChanged()
Emitted when the background color has changed.
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.
void show2DMapOverlayChanged()
Emitted when the 2D map overlay is enabled or disabled.
bool stopUpdates() const
Returns whether the scene updates on camera movement.
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 setOrigin(const QgsVector3D &origin)
Sets coordinates in map CRS at which our 3D world has origin (0,0,0).
void skyboxSettingsChanged()
Emitted when skybox settings are changed.
void projectionTypeChanged()
Emitted when the camera lens projection type changes.
void stopUpdatesChanged()
Emitted when the flag whether to keep updating scene has changed.
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.
void terrainSettingsChanged()
Emitted when the terrain settings are changed.
void fpsCounterEnabledChanged(bool fpsCounterEnabled)
Emitted when the FPS counter is enabled or disabled.
void axisSettingsChanged()
Emitted when 3d axis rendering settings are changed.
void viewFrustumVisualizationEnabledChanged()
Emitted when the camera's view frustum visualization on the main 2D map canvas is enabled or disabled...
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.
void cameraMovementSpeedChanged()
Emitted when the camera movement speed was changed.
void fieldOfViewChanged()
Emitted when the camera lens field of view changes.
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.
QgsVector3D origin() const
Returns coordinates in map CRS at which 3D scene has origin (0,0,0).
Entity that handles the exporting of 3D scenes.
bool save(const QString &sceneName, const QString &sceneFolderPath, int precision=6) const
Saves the scene to a .obj file Returns false if the operation failed.
void setExportTextures(bool exportTextures)
Sets whether the textures will be exported.
void parseTerrain(QgsTerrainEntity *terrain, const QString &layer)
Creates terrain export objects from the terrain entity.
void setTerrainResolution(int resolution)
Sets the terrain resolution.
void setTerrainTextureResolution(int resolution)
Sets the terrain texture resolution.
bool parseVectorLayerEntity(Qt3DCore::QEntity *entity, QgsVectorLayer *layer)
Creates necessary export objects from entity if it represents valid vector layer entity Returns false...
void setScale(float scale)
Sets the scale of the exported 3D model.
void setExportNormals(bool exportNormals)
Sets whether the normals will be exported.
void setSmoothEdges(bool smoothEdges)
Sets whether the triangles will look smooth.
void setTerrainExportEnabled(bool enabled)
Sets whether terrain export is enabled.
static int maxZoomLevel(double tile0width, double tileResolution, double maxError)
Calculates the highest needed zoom level for tiles in quad-tree given width of the base tile (zoom le...
static QgsAABB mapToWorldExtent(const QgsRectangle &extent, double zMin, double zMax, const QgsVector3D &mapOrigin)
Converts map extent to axis aligned bounding box in 3D world coordinates.
static void computeBoundingBoxNearFarPlanes(const QgsAABB &bbox, const QMatrix4x4 &viewMatrix, float &fnear, float &ffar)
This routine computes nearPlane farPlane from the closest and farthest corners point of bounding box ...
static QgsRay3D rayFromScreenPoint(const QPoint &point, const QSize &windowSize, Qt3DRender::QCamera *camera)
Convert from clicked point on the screen to a ray in world coordinates.
static int openGlMaxClipPlanes(QSurface *surface)
Gets the maximum number of clip planes that can be used.
Base class for 3D engine implementation.
void sizeChanged()
Emitted after a call to setSize().
virtual Qt3DRender::QCamera * camera()=0
Returns pointer to the engine's camera entity.
Base class for all renderers that participate in 3D views.
virtual QString type() const =0
Returns unique identifier of the renderer class (used to identify subclass).
virtual Qt3DCore::QEntity * createEntity(Qgs3DMapSettings *map) const =0
Returns a 3D entity that will be used to show renderer's data in 3D scene.
virtual void setEnabled(bool enable)
Enable or disable via enable the render view sub tree.
Base class for 3D renderers that are based on vector layers.
static QgsSourceCache * sourceCache()
Returns the application's source cache, used for caching embedded and remote source strings as local ...
A 3-dimensional box composed of x, y, z coordinates.
double zMaximum() const
Returns the maximum z value.
double zMinimum() const
Returns the minimum z value.
Object that controls camera movement based on user input.
Qt3DRender::QCamera * camera() const
Returns camera that is being controlled.
void cameraChanged()
Emitted when camera has been updated.
void cameraRotationCenterChanged(QVector3D position)
Emitted when the camera rotation center changes.
QgsRange which stores a range of double values.
bool isInfinite() const
Returns true if the range consists of all possible values.
Qt3DRender::QLayer * renderLayer()
Returns a layer object used to indicate that the object is transparent.
Qt3DRender::QLayer * transparentObjectLayer()
Returns a layer object used to indicate that the object is transparent.
QgsHighlightsRenderView & highlightsRenderView()
Returns the highlights renderview, used for rendering highlight overlays of identified features.
QgsForwardRenderView & forwardRenderView()
Returns forward renderview.
QgsOverlayTextureRenderView & overlayTextureRenderView()
Returns overlay texture renderview.
QgsShadowRenderView & shadowRenderView()
Returns shadow renderview.
Qt3DRender::QLayer * highlightsLayer()
Returns a layer that should be attached to entities meant to be rendered by QgsHighlightsRenderView.
virtual QgsDoubleRange calculateZRange(QgsMapLayer *layer) const
Attempts to calculate the overall elevation or z range for the specified layer, using the settings de...
Base class for storage of map layer temporal properties.
Base class for all map layer types.
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.
void rendererChanged()
Signal emitted when renderer is changed.
virtual QgsMapLayerTemporalProperties * temporalProperties()
Returns the layer's temporal properties.
void layerModified()
Emitted when modifications has been done on layer.
double verticalScale() const
Returns mesh vertical scale.
int verticalDatasetGroupIndex() const
Returns the index of the dataset group that will be used to render the vertical component of the 3D m...
void setMaximumTextureSize(int maximumTextureSize)
Sets the maximum texture size supported by the hardware Used to store the GL_MAX_TEXTURE_SIZE value t...
QgsMesh3DSymbol * clone() const override SIP_FACTORY
Returns a new instance of the symbol with the same settings.
3D renderer that renders all mesh triangles of a mesh layer.
void setSymbol(QgsMesh3DSymbol *symbol)
Sets 3D symbol associated with the renderer.
const QgsMesh3DSymbol * symbol() const
Returns 3D symbol associated with the renderer.
void setLayer(QgsMeshLayer *layer)
Sets vector layer associated with the renderer.
Represents a mesh layer supporting display of data on structured or unstructured meshes.
QgsMeshDatasetGroupMetadata datasetGroupMetadata(const QgsMeshDatasetIndex &index) const
Returns the dataset groups metadata.
virtual void showMessage(bool blocking=true)=0
display the message to the user and deletes itself
3D symbol that draws point geometries as 3D objects using one of the predefined shapes.
Qgis::Point3DShape shape() const
Returns 3D shape for points.
QVariant shapeProperty(const QString &property) const
Returns the value for a specific shape property.
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.
T lower() const
Returns the lower bound of the range.
T upper() const
Returns the upper bound of the range.
bool isEmpty() const
Returns true if the range is empty, ie the lower bound equals (or exceeds) the upper bound and either...
A representation of a ray in 3D.
QVector3D origin() const
Returns the origin of the ray.
QVector3D direction() const
Returns the direction of the ray see setDirection().
A rectangle specified with double values.
static QgsRectangle fromCenterAndSize(const QgsPointXY ¢er, double width, double height)
Creates a new rectangle, given the specified center point and width and height.
A child rule for a QgsRuleBased3DRenderer.
QList< QgsRuleBased3DRenderer::Rule * > RuleList
Qt3DRender::QLayer * entityCastingShadowsLayer() const
Returns the layer to be used by entities to be included in this renderview.
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.
void setLayer(QgsTiledSceneLayer *layer)
Sets tiled scene layer associated with the renderer.
Represents a map layer supporting display of tiled scene objects.
QgsMapLayerElevationProperties * elevationProperties() override
Returns the layer's elevation properties.
A 3D vector (similar to QVector3D) with the difference that it uses double precision instead of singl...
double y() const
Returns Y coordinate.
double z() const
Returns Z coordinate.
QString toString(int precision=17) const
Returns a string representation of the 3D vector.
double x() const
Returns X coordinate.
3D renderer that renders all features of a vector layer with the same 3D symbol.
const QgsAbstract3DSymbol * symbol() const
Returns 3D symbol associated with the renderer.
Represents a vector layer which manages a vector based dataset.
void subsetStringChanged()
Emitted when the layer's subset string has changed.
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).
#define QgsDebugMsgLevel(str, level)
#define QgsDebugError(str)