65#include <QOpenGLContext>
66#include <QOpenGLFunctions>
71#include <Qt3DExtras/QDiffuseSpecularMaterial>
72#include <Qt3DExtras/QForwardRenderer>
73#include <Qt3DExtras/QPhongAlphaMaterial>
74#include <Qt3DExtras/QPhongMaterial>
75#include <Qt3DExtras/QSphereMesh>
76#include <Qt3DLogic/QFrameAction>
77#include <Qt3DRender/QCamera>
78#include <Qt3DRender/QCullFace>
79#include <Qt3DRender/QDepthTest>
80#include <Qt3DRender/QEffect>
81#include <Qt3DRender/QMesh>
82#include <Qt3DRender/QRenderPass>
83#include <Qt3DRender/QRenderSettings>
84#include <Qt3DRender/QRenderState>
85#include <Qt3DRender/QSceneLoader>
86#include <Qt3DRender/QTechnique>
89#include "moc_qgs3dmapscene.cpp"
91using namespace Qt::StringLiterals;
100 onBackgroundColorChanged();
105 mEngine->renderSettings()->setRenderPolicy( Qt3DRender::QRenderSettings::OnDemand );
107 QRect viewportRect( QPoint( 0, 0 ), mEngine->size() );
113 float aspectRatio = ( float ) viewportRect.width() / viewportRect.height();
114 mEngine->camera()->lens()->setPerspectiveProjection( mMap.fieldOfView(), aspectRatio, 10.f, 10000.0f );
116 mFrameAction =
new Qt3DLogic::QFrameAction();
117 connect( mFrameAction, &Qt3DLogic::QFrameAction::triggered,
this, &Qgs3DMapScene::onFrameTriggered );
118 addComponent( mFrameAction );
124 mCameraController->resetGlobe( 10'000'000 );
126 mCameraController->resetView( 1000 );
128 addCameraViewCenterEntity( mEngine->camera() );
129 addCameraRotationCenterEntity( mCameraController );
134 createTerrainDeferred();
164 const QList<QgsMapLayer *> modelVectorLayers = mModelVectorLayers;
170 if ( renderer->
type() ==
"vector"_L1 )
173 if ( pointSymbol && pointSymbol->
shapeProperty( u
"model"_s ).toString() == url )
175 removeLayerEntity( layer );
176 addLayerEntity( layer );
179 else if ( renderer->
type() ==
"rulebased"_L1 )
185 if ( pointSymbol && pointSymbol->
shapeProperty( u
"model"_s ).toString() == url )
187 removeLayerEntity( layer );
188 addLayerEntity( layer );
203 onSkyboxSettingsChanged();
208 onEyeDomeShadingSettingsChanged();
210 onDebugShadowMapSettingsChanged();
211 onDebugDepthMapSettingsChanged();
213 onAmbientOcclusionSettingsChanged();
215 onCameraMovementSpeedChanged();
217 on3DAxisSettingsChanged();
224 mCameraController->resetGlobe( 10'000'000 );
230 const double side = std::max( extent.
width(), extent.
height() );
231 double d = side / 2 / std::tan(
cameraController()->camera()->fieldOfView() / 2 * M_PI / 180 );
233 mCameraController->resetView(
static_cast<float>( d ) );
244 const double xSide = std::abs( p1.
x() - p2.
x() );
245 const double ySide = std::abs( p1.
y() - p2.
y() );
246 const double side = std::max( xSide, ySide );
248 const double fov = qDegreesToRadians(
cameraController()->camera()->fieldOfView() );
249 double distance = side / 2.0f / std::tan( fov / 2.0f );
254 distance += zRange.
upper();
257 mCameraController->setViewFromTop(
258 static_cast<float>( center.
x() - origin.
x() ),
259 static_cast<float>( center.
y() - origin.
y() ),
260 static_cast<float>( distance )
266 Qt3DRender::QCamera *camera = mCameraController->camera();
267 QVector<QgsPointXY> extent;
268 QVector<int> pointsOrder = { 0, 1, 3, 2 };
269 for (
int i : pointsOrder )
271 const QPoint p( ( ( i >> 0 ) & 1 ) ? 0 : mEngine->size().width(), ( ( i >> 1 ) & 1 ) ? 0 : mEngine->size().height() );
274 if ( dir.z() == 0.0 )
275 dir.setZ( 0.000001 );
276 double t = -ray.
origin().z() / dir.z();
280 t = camera->farPlane();
285 t = std::min<float>( t, camera->farPlane() );
287 QVector3D planePoint = ray.
origin() + t * dir;
288 QgsVector3D pMap = mMap.worldToMapCoordinates( planePoint );
297 for ( Qgs3DMapSceneEntity *entity : std::as_const( mSceneEntities ) )
298 count += entity->pendingJobsCount();
304 Qt3DRender::QCamera *camera = mCameraController->camera();
305 const double fov = camera->fieldOfView();
306 const QSize size = mEngine->size();
307 const int screenSizePx = std::max( size.width(), size.height() );
311 const double frustumWidthAtDistance = 2 * distance * tan( fov / 2 );
312 const double err = frustumWidthAtDistance * epsilon / screenSizePx;
316void Qgs3DMapScene::onCameraChanged()
318 if ( mMap.
projectionType() == Qt3DRender::QCameraLens::OrthographicProjection )
320 QRect viewportRect( QPoint( 0, 0 ), mEngine->
size() );
321 const float viewWidthFromCenter = mCameraController->
distance();
322 const float viewHeightFromCenter = viewportRect.height() * viewWidthFromCenter / viewportRect.width();
323 mEngine->
camera()->lens()->setOrthographicProjection( -viewWidthFromCenter, viewWidthFromCenter, -viewHeightFromCenter, viewHeightFromCenter, mEngine->
camera()->nearPlane(), mEngine->
camera()->farPlane() );
327 updateCameraNearFarPlanes();
329 onShadowSettingsChanged();
340 constexpr float ORIGIN_SHIFT_THRESHOLD = 10'000;
341 if ( mSceneOriginShiftEnabled && mEngine->camera()->position().length() > ORIGIN_SHIFT_THRESHOLD )
343 const QgsVector3D newOrigin = mMap.origin() + QgsVector3D( mEngine->camera()->position() );
344 QgsDebugMsgLevel( u
"Rebasing scene origin from %1 to %2"_s.arg( mMap.origin().toString( 1 ), newOrigin.
toString( 1 ) ), 2 );
345 mMap.setOrigin( newOrigin );
349bool Qgs3DMapScene::updateScene(
bool forceUpdate )
351 if ( !mSceneUpdatesEnabled )
357 QgsEventTracing::ScopedEvent traceEvent( u
"3D"_s, forceUpdate ? u
"Force update scene"_s : u
"Update scene"_s );
359 Qgs3DMapSceneEntity::SceneContext sceneContext;
360 Qt3DRender::QCamera *camera = mEngine->camera();
361 sceneContext.cameraFov = camera->fieldOfView();
362 sceneContext.cameraPos = camera->position();
363 const QSize size = mEngine->size();
364 sceneContext.screenSizePx = std::max( size.width(), size.height() );
372 QMatrix4x4 projMatrix;
373 switch ( mMap.projectionType() )
375 case Qt3DRender::QCameraLens::PerspectiveProjection:
377 float fovRadians = ( camera->fieldOfView() / 2.0f ) *
static_cast<float>( M_PI ) / 180.0f;
378 float fovCotan = std::cos( fovRadians ) / std::sin( fovRadians );
380 fovCotan / camera->aspectRatio(), 0, 0, 0,
387 case Qt3DRender::QCameraLens::OrthographicProjection:
389 Qt3DRender::QCameraLens *lens = camera->lens();
391 2.0f / ( lens->right() - lens->left() ),
396 2.0f / ( lens->top() - lens->bottom() ),
403 -( lens->left() + lens->right() ) / ( lens->right() - lens->left() ),
404 -( lens->top() + lens->bottom() ) / ( lens->top() - lens->bottom() ),
412 projMatrix = camera->projectionMatrix();
414 sceneContext.viewProjectionMatrix = projMatrix * camera->viewMatrix();
417 bool anyUpdated =
false;
418 for ( Qgs3DMapSceneEntity *entity : std::as_const( mSceneEntities ) )
420 if ( forceUpdate || ( entity->isEnabled() && entity->needsUpdate() ) )
423 entity->handleSceneUpdate( sceneContext );
424 if ( entity->hasReachedGpuMemoryLimit() )
434bool Qgs3DMapScene::updateCameraNearFarPlanes()
449 QMatrix4x4 viewMatrix = camera->viewMatrix();
455 for ( Qgs3DMapSceneEntity *se : std::as_const( mSceneEntities ) )
457 const QgsRange<float> depthRange = se->getNearFarPlaneRange( viewMatrix );
459 fnear = std::min( fnear, depthRange.
lower() );
460 ffar = std::max( ffar, depthRange.
upper() );
469 if ( fnear == 1e9 && ffar == 0 )
472 sceneZRange = sceneZRange.
isInfinite() ? QgsDoubleRange( 0.0, 0.0 ) : sceneZRange;
479 std::swap( fnear, ffar );
482 float newFar = ffar * 2;
483 float newNear = fnear / 2;
486 camera->setFarPlane( newFar );
487 camera->setNearPlane( newNear );
494void Qgs3DMapScene::onFrameTriggered(
float dt )
496 QgsEventTracing::addEvent( QgsEventTracing::EventType::Instant, u
"3D"_s, u
"Frame begins"_s );
498 mCameraController->frameTriggered( dt );
503 updateCameraNearFarPlanes();
506 static int frameCount = 0;
507 static float accumulatedTime = 0.0f;
509 if ( !mMap.isFpsCounterEnabled() )
517 accumulatedTime += dt;
518 if ( accumulatedTime >= 0.2f )
520 float fps = ( float ) frameCount / accumulatedTime;
522 accumulatedTime = 0.0f;
527void Qgs3DMapScene::createTerrain()
531 mSceneEntities.removeOne( mTerrain );
539 mSceneEntities.removeOne( mGlobe );
545 if ( !mTerrainUpdateScheduled )
548 QTimer::singleShot( 0,
this, &Qgs3DMapScene::createTerrainDeferred );
549 mTerrainUpdateScheduled =
true;
558void Qgs3DMapScene::createTerrainDeferred()
560 QgsChunkedEntity *terrainOrGlobe =
nullptr;
564 mGlobe =
new QgsGlobeEntity( &mMap );
565 terrainOrGlobe = mGlobe;
567 else if ( mMap.sceneMode() ==
Qgis::SceneMode::Local && mMap.terrainRenderingEnabled() && mMap.terrainGenerator() )
569 double tile0width = mMap.terrainGenerator()->rootChunkExtent().width();
570 int maxZoomLevel =
Qgs3DUtils::maxZoomLevel( tile0width, mMap.terrainSettings()->mapTileResolution(), mMap.terrainSettings()->maximumGroundError() );
571 const QgsBox3D rootBox3D = mMap.terrainGenerator()->rootChunkBox3D( mMap );
572 float rootError = mMap.terrainGenerator()->rootChunkError( mMap );
573 const QgsBox3D clippingBox3D( mMap.extent(), rootBox3D.
zMinimum(), rootBox3D.
zMaximum() );
574 mMap.terrainGenerator()->setupQuadtree( rootBox3D, rootError, maxZoomLevel, clippingBox3D );
576 mTerrain =
new QgsTerrainEntity( &mMap );
577 terrainOrGlobe = mTerrain;
580 if ( terrainOrGlobe )
582 terrainOrGlobe->setParent(
this );
583 terrainOrGlobe->setShowBoundingBoxes( mMap.showTerrainBoundingBoxes() );
585 mSceneEntities << terrainOrGlobe;
588 connect( terrainOrGlobe, &Qgs3DMapSceneEntity::newEntityCreated,
this, [
this]( Qt3DCore::QEntity *entity ) {
590 const QList<QgsGeoTransform *> transforms = entity->findChildren<QgsGeoTransform *>();
591 for ( QgsGeoTransform *transform : transforms )
593 transform->setOrigin( mMap.origin() );
597 handleClippingOnEntity( entity );
602 const QList<QgsMapLayer *>
layers = mMap.layers();
603 for ( QgsMapLayer *layer :
layers )
606 removeLayerEntity( layer );
609 addLayerEntity( layer );
614 mTerrainUpdateScheduled =
false;
617void Qgs3DMapScene::onBackgroundColorChanged()
619 mEngine->setClearColor( mMap.backgroundColor() );
622void Qgs3DMapScene::updateLights()
624 for ( Qt3DCore::QEntity *entity : std::as_const( mLightEntities ) )
625 entity->deleteLater();
626 mLightEntities.clear();
628 const QList<QgsLightSource *> newLights = mMap.lightSources();
629 for (
const QgsLightSource *source : newLights )
631 mLightEntities.append( source->createEntity( mMap,
this ) );
634 onShadowSettingsChanged();
637void Qgs3DMapScene::updateCameraLens()
639 mEngine->camera()->lens()->setFieldOfView( mMap.fieldOfView() );
640 mEngine->camera()->lens()->setProjectionType( mMap.projectionType() );
644void Qgs3DMapScene::onLayerRenderer3DChanged()
646 QgsMapLayer *layer = qobject_cast<QgsMapLayer *>( sender() );
650 removeLayerEntity( layer );
653 addLayerEntity( layer );
656void Qgs3DMapScene::onLayersChanged()
658 QSet<QgsMapLayer *> layersBefore = qgis::listToSet( mLayerEntities.keys() );
659 QList<QgsMapLayer *> layersAdded;
660 const QList<QgsMapLayer *>
layers = mMap.layers();
661 for ( QgsMapLayer *layer :
layers )
663 if ( !layersBefore.contains( layer ) )
665 layersAdded << layer;
669 layersBefore.remove( layer );
674 for ( QgsMapLayer *layer : std::as_const( layersBefore ) )
676 removeLayerEntity( layer );
679 for ( QgsMapLayer *layer : std::as_const( layersAdded ) )
681 addLayerEntity( layer );
687 const QList<QgsMapLayer *>
layers = mLayerEntities.keys();
692 if ( temporalProperties->isActive() )
694 removeLayerEntity( layer );
695 addLayerEntity( layer );
703 Q_ASSERT( sceneNewEntity );
705 mSceneEntities.append( sceneNewEntity );
707 sceneNewEntity->setParent(
this );
709 finalizeNewEntity( sceneNewEntity );
711 connect( sceneNewEntity, &Qgs3DMapSceneEntity::newEntityCreated,
this, [
this]( Qt3DCore::QEntity *entity ) {
712 finalizeNewEntity( entity );
714 updateCameraNearFarPlanes();
724 Q_ASSERT( sceneEntity );
726 mSceneEntities.removeOne( sceneEntity );
728 sceneEntity->deleteLater();
732void Qgs3DMapScene::addLayerEntity(
QgsMapLayer *layer )
744 if ( renderer->
type() ==
"vector"_L1 )
752 mModelVectorLayers.append( layer );
756 else if ( renderer->
type() ==
"rulebased"_L1 )
759 for (
auto rule : rules )
761 const QgsPoint3DSymbol *pointSymbol =
dynamic_cast<const QgsPoint3DSymbol *
>( rule->symbol() );
764 mModelVectorLayers.append( layer );
772 QgsMeshLayer3DRenderer *meshRenderer =
static_cast<QgsMeshLayer3DRenderer *
>( renderer );
773 meshRenderer->
setLayer(
static_cast<QgsMeshLayer *
>( layer ) );
777 QgsMesh3DSymbol *sym = meshRenderer->
symbol()->
clone();
783 QgsPointCloudLayer3DRenderer *pointCloudRenderer =
static_cast<QgsPointCloudLayer3DRenderer *
>( renderer );
784 pointCloudRenderer->
setLayer(
static_cast<QgsPointCloudLayer *
>( layer ) );
788 QgsTiledSceneLayer3DRenderer *tiledSceneRenderer =
static_cast<QgsTiledSceneLayer3DRenderer *
>( renderer );
789 tiledSceneRenderer->
setLayer(
static_cast<QgsTiledSceneLayer *
>( layer ) );
793 auto annotationLayerRenderer = qgis::down_cast<QgsAnnotationLayer3DRenderer *>( renderer );
794 annotationLayerRenderer->setLayer( qobject_cast<QgsAnnotationLayer *>( layer ) );
797 Qt3DCore::QEntity *newEntity = renderer->
createEntity( &mMap );
800 mLayerEntities.insert( layer, newEntity );
802 if ( Qgs3DMapSceneEntity *sceneNewEntity = qobject_cast<Qgs3DMapSceneEntity *>( newEntity ) )
809 newEntity->setParent(
this );
810 finalizeNewEntity( newEntity );
819 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
832 QgsPointCloudLayer *pclayer = qobject_cast<QgsPointCloudLayer *>( layer );
838void Qgs3DMapScene::removeLayerEntity(
QgsMapLayer *layer )
840 Qt3DCore::QEntity *entity = mLayerEntities.take( layer );
842 if ( Qgs3DMapSceneEntity *sceneEntity = qobject_cast<Qgs3DMapSceneEntity *>( entity ) )
850 entity->deleteLater();
857 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
861 mModelVectorLayers.removeAll( layer );
871 QgsPointCloudLayer *pclayer = qobject_cast<QgsPointCloudLayer *>( layer );
878void Qgs3DMapScene::finalizeNewEntity( Qt3DCore::QEntity *newEntity )
881 const QList<QgsGeoTransform *> transforms = newEntity->findChildren<QgsGeoTransform *>();
882 for ( QgsGeoTransform *transform : transforms )
884 transform->setOrigin( mMap.origin() );
888 handleClippingOnEntity( newEntity );
892 const QList<QgsLineMaterial *> childLineMaterials = newEntity->findChildren<QgsLineMaterial *>();
893 for ( QgsLineMaterial *lm : childLineMaterials )
896 lm->setViewportSize( mEngine->size() );
899 lm->setViewportSize( mEngine->size() );
902 const QList<QgsPoint3DBillboardMaterial *> childBillboardMaterials = newEntity->findChildren<QgsPoint3DBillboardMaterial *>();
903 for ( QgsPoint3DBillboardMaterial *bm : childBillboardMaterials )
906 bm->setViewportSize( mEngine->size() );
909 bm->setViewportSize( mEngine->size() );
913 QgsFrameGraph *frameGraph = mEngine->frameGraph();
915 const QList<Qt3DRender::QMaterial *> childMaterials = newEntity->findChildren<Qt3DRender::QMaterial *>();
916 for ( Qt3DRender::QMaterial *material : childMaterials )
919 if ( Qt3DExtras::QDiffuseSpecularMaterial *ph = qobject_cast<Qt3DExtras::QDiffuseSpecularMaterial *>( material ) )
921 if ( ph->diffuse().value<QColor>().alphaF() != 1.0f )
923 Qt3DCore::QEntity *entity = qobject_cast<Qt3DCore::QEntity *>( ph->parent() );
924 if ( entity && !entity->components().contains( transparentLayer ) )
926 entity->addComponent( transparentLayer );
947 else if ( QgsPoint3DBillboardMaterial *billboardMaterial = qobject_cast<QgsPoint3DBillboardMaterial *>( material ) )
949 Qt3DCore::QEntity *entity = qobject_cast<Qt3DCore::QEntity *>( billboardMaterial->parent() );
950 if ( entity && !entity->components().contains( transparentLayer ) )
952 entity->addComponent( transparentLayer );
959 Qt3DRender::QEffect *effect = material->effect();
962 const QVector<Qt3DRender::QParameter *> parameters = effect->parameters();
963 for (
const Qt3DRender::QParameter *parameter : parameters )
965 if ( parameter->name() ==
"opacity" && parameter->value() != 1.0f )
967 Qt3DCore::QEntity *entity = qobject_cast<Qt3DCore::QEntity *>( material->parent() );
968 if ( entity && !entity->components().contains( transparentLayer ) )
970 entity->addComponent( transparentLayer );
980int Qgs3DMapScene::maximumTextureSize()
const
982 QSurface *surface = mEngine->surface();
983 QOpenGLContext context;
985 bool success = context.makeCurrent( surface );
989 QOpenGLFunctions openglFunctions = QOpenGLFunctions( &context );
992 openglFunctions.initializeOpenGLFunctions();
993 openglFunctions.glGetIntegerv( GL_MAX_TEXTURE_SIZE, &size );
1002void Qgs3DMapScene::addCameraViewCenterEntity( Qt3DRender::QCamera *camera )
1004 mEntityCameraViewCenter =
new Qt3DCore::QEntity;
1006 Qt3DCore::QTransform *trCameraViewCenter =
new Qt3DCore::QTransform;
1007 mEntityCameraViewCenter->addComponent( trCameraViewCenter );
1008 connect( camera, &Qt3DRender::QCamera::viewCenterChanged,
this, [trCameraViewCenter, camera] {
1009 trCameraViewCenter->setTranslation( camera->viewCenter() );
1012 Qt3DExtras::QPhongMaterial *materialCameraViewCenter =
new Qt3DExtras::QPhongMaterial;
1013 materialCameraViewCenter->setAmbient( Qt::red );
1014 mEntityCameraViewCenter->addComponent( materialCameraViewCenter );
1016 Qt3DExtras::QSphereMesh *rendererCameraViewCenter =
new Qt3DExtras::QSphereMesh;
1017 rendererCameraViewCenter->setRadius( 10 );
1018 mEntityCameraViewCenter->addComponent( rendererCameraViewCenter );
1020 mEntityCameraViewCenter->setEnabled( mMap.showCameraViewCenter() );
1021 mEntityCameraViewCenter->setParent(
this );
1024 mEntityCameraViewCenter->setEnabled( mMap.showCameraViewCenter() );
1030 if ( mSceneState == state )
1032 mSceneState = state;
1036void Qgs3DMapScene::updateSceneState()
1038 if ( mTerrainUpdateScheduled )
1044 for ( Qgs3DMapSceneEntity *entity : std::as_const( mSceneEntities ) )
1046 if ( entity->isEnabled() && entity->pendingJobsCount() > 0 )
1053 setSceneState(
Ready );
1056void Qgs3DMapScene::onSkyboxSettingsChanged()
1058 QgsSkyboxSettings skyboxSettings = mMap.skyboxSettings();
1061 mSkybox->deleteLater();
1065 mEngine->setFrustumCullingEnabled( !mMap.isSkyboxEnabled() );
1067 if ( mMap.isSkyboxEnabled() )
1069 QMap<QString, QString> faces;
1074 mSkybox =
new QgsCubeFacesSkyboxEntity(
1075 faces[u
"posX"_s], faces[u
"posY"_s], faces[u
"posZ"_s],
1076 faces[u
"negX"_s], faces[u
"negY"_s], faces[u
"negZ"_s],
1087void Qgs3DMapScene::onShadowSettingsChanged()
1089 mEngine->frameGraph()->updateShadowSettings( mMap.shadowSettings(), mMap.lightSources() );
1092void Qgs3DMapScene::onAmbientOcclusionSettingsChanged()
1094 mEngine->frameGraph()->updateAmbientOcclusionSettings( mMap.ambientOcclusionSettings() );
1097void Qgs3DMapScene::onDebugShadowMapSettingsChanged()
1099 mEngine->frameGraph()->updateDebugShadowMapSettings( mMap );
1102void Qgs3DMapScene::onDebugDepthMapSettingsChanged()
1104 mEngine->frameGraph()->updateDebugDepthMapSettings( mMap );
1107void Qgs3DMapScene::onDebugOverlayEnabledChanged()
1109 mEngine->frameGraph()->setDebugOverlayEnabled( mMap.isDebugOverlayEnabled() );
1110 mEngine->renderSettings()->setRenderPolicy( mMap.isDebugOverlayEnabled() ? Qt3DRender::QRenderSettings::Always : Qt3DRender::QRenderSettings::OnDemand );
1113void Qgs3DMapScene::onEyeDomeShadingSettingsChanged()
1115 mEngine->frameGraph()->updateEyeDomeSettings( mMap );
1118void Qgs3DMapScene::onCameraMovementSpeedChanged()
1120 mCameraController->setCameraMovementSpeed( mMap.cameraMovementSpeed() );
1123void Qgs3DMapScene::onCameraNavigationModeChanged()
1125 mCameraController->setCameraNavigationMode( mMap.cameraNavigationMode() );
1130 QVector<QString> notParsedLayers;
1140 for (
auto it = mLayerEntities.constBegin(); it != mLayerEntities.constEnd(); ++it )
1143 Qt3DCore::QEntity *rootEntity = it.value();
1145 switch ( layerType )
1149 notParsedLayers.push_back( layer->
name() );
1159 notParsedLayers.push_back( layer->
name() );
1173 if ( !notParsedLayers.empty() )
1175 QString message = tr(
"The following layers were not exported:" ) +
"\n";
1176 for (
const QString &layerName : notParsedLayers )
1177 message += layerName +
"\n";
1186 QVector<const QgsChunkNode *> chunks;
1187 if ( !mLayerEntities.contains( layer ) )
1189 if ( QgsChunkedEntity *
c = qobject_cast<QgsChunkedEntity *>( mLayerEntities[layer] ) )
1191 const QList<QgsChunkNode *> activeNodes =
c->activeNodes();
1192 for ( QgsChunkNode *n : activeNodes )
1193 chunks.push_back( n );
1200 return mMap.extent();
1205 double zMin = std::numeric_limits<double>::max();
1206 double zMax = std::numeric_limits<double>::lowest();
1207 if ( mMap.terrainRenderingEnabled() && mTerrain && !ignoreTerrain )
1209 const QgsBox3D box3D = mTerrain->rootNode()->box3D();
1210 zMin = std::min( zMin, box3D.
zMinimum() );
1211 zMax = std::max( zMax, box3D.
zMaximum() );
1214 for (
auto it = mLayerEntities.constBegin(); it != mLayerEntities.constEnd(); it++ )
1217 switch ( layer->
type() )
1223 zMin = std::min( zMin, zRange.
lower() );
1224 zMax = std::max( zMax, zRange.
upper() );
1229 QgsMeshLayer *meshLayer = qobject_cast<QgsMeshLayer *>( layer );
1237 zMin = std::min( zMin, verticalGroupMetadata.
minimum() * verticalScale );
1238 zMax = std::max( zMax, verticalGroupMetadata.
maximum() * verticalScale );
1248 zMin = std::min( zMin, zRange.
lower() );
1249 zMax = std::max( zMax, zRange.
upper() );
1262 const QgsDoubleRange zRange( std::min( zMin, std::numeric_limits<double>::max() ), std::max( zMax, std::numeric_limits<double>::lowest() ) );
1273 mEntityRotationCenter =
new Qt3DCore::QEntity;
1275 Qt3DCore::QTransform *trRotationCenter =
new Qt3DCore::QTransform;
1276 mEntityRotationCenter->addComponent( trRotationCenter );
1277 Qt3DExtras::QPhongMaterial *materialRotationCenter =
new Qt3DExtras::QPhongMaterial;
1278 materialRotationCenter->setAmbient( Qt::blue );
1279 mEntityRotationCenter->addComponent( materialRotationCenter );
1280 Qt3DExtras::QSphereMesh *rendererRotationCenter =
new Qt3DExtras::QSphereMesh;
1281 rendererRotationCenter->setRadius( 10 );
1282 mEntityRotationCenter->addComponent( rendererRotationCenter );
1283 mEntityRotationCenter->setEnabled(
false );
1284 mEntityRotationCenter->setParent(
this );
1287 trRotationCenter->setTranslation( center );
1291 mEntityRotationCenter->setEnabled( mMap.showCameraRotationCenter() );
1295void Qgs3DMapScene::on3DAxisSettingsChanged()
1299 m3DAxis->onAxisSettingsChanged();
1303 if ( QgsWindow3DEngine *
engine =
dynamic_cast<QgsWindow3DEngine *
>( mEngine ) )
1305 m3DAxis =
new Qgs3DAxis(
static_cast<Qgs3DMapCanvas *
>(
engine->window() ),
engine->root(),
this, mCameraController, &mMap );
1310void Qgs3DMapScene::onOriginChanged()
1312 const QList<QgsGeoTransform *> geoTransforms = findChildren<QgsGeoTransform *>();
1313 for ( QgsGeoTransform *transform : geoTransforms )
1315 transform->setOrigin( mMap.origin() );
1318 const QList<QgsGeoTransform *> rubberBandGeoTransforms = mEngine->frameGraph()->rubberBandsRootEntity()->findChildren<QgsGeoTransform *>();
1319 for ( QgsGeoTransform *transform : rubberBandGeoTransforms )
1321 transform->setOrigin( mMap.origin() );
1324 const QgsVector3D oldOrigin = mCameraController->origin();
1325 mCameraController->setOrigin( mMap.origin() );
1327 if ( !mClipPlanesEquations.isEmpty() )
1336 QList<QVector4D> newPlanes;
1337 QgsVector3D originShift = mMap.origin() - oldOrigin;
1338 for ( QVector4D plane : std::as_const( mClipPlanesEquations ) )
1340 plane.setW( originShift.
x() * plane.x() + originShift.
y() * plane.y() + originShift.
z() * plane.z() + plane.w() );
1341 newPlanes.append( plane );
1347void Qgs3DMapScene::handleClippingOnEntity( QEntity *entity )
const
1349 if ( mClipPlanesEquations.isEmpty() )
1351 for ( QgsMaterial *material : entity->componentsOfType<QgsMaterial>() )
1353 material->disableClipping();
1358 for ( QgsMaterial *material : entity->componentsOfType<QgsMaterial>() )
1360 material->enableClipping( mClipPlanesEquations );
1366 for ( QObject *child : entity->children() )
1368 Qt3DCore::QEntity *childEntity = qobject_cast<Qt3DCore::QEntity *>( child );
1371 handleClippingOnEntity( childEntity );
1376void Qgs3DMapScene::handleClippingOnAllEntities()
const
1380 for (
auto it = mLayerEntities.constBegin(); it != mLayerEntities.constEnd(); ++it )
1382 handleClippingOnEntity( it.value() );
1386 handleClippingOnEntity( mTerrain );
1390 handleClippingOnEntity( mGlobe );
1398 QgsDebugMsgLevel( u
"Qgs3DMapScene::enableClipping: it is not possible to use more than %1 clipping planes."_s.arg( mMaxClipPlanes ), 2 );
1406 handleClippingOnAllEntities();
1411 mClipPlanesEquations.clear();
1414 mEngine->frameGraph()->removeClipPlanes();
1417 handleClippingOnAllEntities();
1420void Qgs3DMapScene::onStopUpdatesChanged()
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.
QString sceneName() const
Returns the scene name.
bool smoothEdges() const
Returns whether triangles edges will look smooth.
bool exportTextures() const
Returns whether textures will be exported.
QVector< const QgsChunkNode * > getLayerActiveChunkNodes(QgsMapLayer *layer)
Returns the active chunk nodes of layer.
void 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.
Qgs3DMapScene(Qgs3DMapSettings &map, QgsAbstract3DEngine *engine)
Constructs a 3D scene based on map settings and Qt 3D renderer configuration.
QgsAbstract3DEngine * engine() const
Returns the abstract 3D engine.
void gpuMemoryLimitReached()
Emitted when one of the entities reaches its GPU memory limit and it is not possible to lower the GPU...
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.
void updateTemporal()
Updates the temporale entities.
static Q_DECL_DEPRECATED QMap< QString, Qgs3DMapScene * > openScenes()
Returns a map of 3D map scenes (by name) open in the QGIS application.
void totalPendingJobsCountChanged()
Emitted when the total number of pending jobs changes.
void fpsCounterEnabledChanged(bool fpsCounterEnabled)
Emitted when the FPS counter is activated or deactivated.
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.
void removeSceneEntity(Qgs3DMapSceneEntity *entity)
Removes a 3D scene entity for the scene.
QList< QgsMapLayer * > layers() const
Returns the layers that contain chunked entities.
QVector< QgsPointXY > viewFrustum2DExtent() const
Calculates the 2D extent viewed by the 3D camera as the vertices of the viewed trapezoid.
void enableClipping(const QList< QVector4D > &clipPlaneEquations)
Enables OpenGL clipping based on the planes equations defined in clipPlaneEquations.
void terrainEntityChanged()
Emitted when the current terrain entity is replaced by a new one.
void addSceneEntity(Qgs3DMapSceneEntity *entity)
Adds a 3D map scene entity to the scene.
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.
Qt3DRender::QCameraLens::ProjectionType projectionType() const
Returns the camera lens' projection type.
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.
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 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 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.
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.
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.
virtual QSize size() const =0
Returns size of the engine's rendering area in pixels.
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.
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.
float distance() const
Returns distance of the camera from the point it is looking at.
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 * transparentObjectLayer()
Returns a layer object used to indicate that the object is transparent.
QgsForwardRenderView & forwardRenderView()
Returns forward renderview.
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.
A child rule for a QgsRuleBased3DRenderer.
QList< QgsRuleBased3DRenderer::Rule * > RuleList
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)