65#include <QOpenGLContext>
66#include <QOpenGLFunctions>
70#include <Qt3DExtras/QDiffuseSpecularMaterial>
71#include <Qt3DExtras/QForwardRenderer>
72#include <Qt3DExtras/QPhongAlphaMaterial>
73#include <Qt3DExtras/QPhongMaterial>
74#include <Qt3DExtras/QSphereMesh>
75#include <Qt3DLogic/QFrameAction>
76#include <Qt3DRender/QCamera>
77#include <Qt3DRender/QCullFace>
78#include <Qt3DRender/QDepthTest>
79#include <Qt3DRender/QEffect>
80#include <Qt3DRender/QMesh>
81#include <Qt3DRender/QRenderPass>
82#include <Qt3DRender/QRenderSettings>
83#include <Qt3DRender/QRenderState>
84#include <Qt3DRender/QSceneLoader>
85#include <Qt3DRender/QTechnique>
88#include "moc_qgs3dmapscene.cpp"
97 onBackgroundColorChanged();
102 mEngine->renderSettings()->setRenderPolicy( Qt3DRender::QRenderSettings::OnDemand );
104 QRect viewportRect( QPoint( 0, 0 ), mEngine->size() );
110 float aspectRatio = ( float ) viewportRect.width() / viewportRect.height();
111 mEngine->camera()->lens()->setPerspectiveProjection( mMap.fieldOfView(), aspectRatio, 10.f, 10000.0f );
113 mFrameAction =
new Qt3DLogic::QFrameAction();
114 connect( mFrameAction, &Qt3DLogic::QFrameAction::triggered,
this, &Qgs3DMapScene::onFrameTriggered );
115 addComponent( mFrameAction );
121 mCameraController->resetGlobe( 10'000'000 );
123 mCameraController->resetView( 1000 );
125 addCameraViewCenterEntity( mEngine->camera() );
126 addCameraRotationCenterEntity( mCameraController );
131 createTerrainDeferred();
161 const QList<QgsMapLayer *> modelVectorLayers = mModelVectorLayers;
167 if ( renderer->
type() == QLatin1String(
"vector" ) )
170 if ( pointSymbol && pointSymbol->
shapeProperty( QStringLiteral(
"model" ) ).toString() == url )
172 removeLayerEntity( layer );
173 addLayerEntity( layer );
176 else if ( renderer->
type() == QLatin1String(
"rulebased" ) )
182 if ( pointSymbol && pointSymbol->
shapeProperty( QStringLiteral(
"model" ) ).toString() == url )
184 removeLayerEntity( layer );
185 addLayerEntity( layer );
200 onSkyboxSettingsChanged();
205 onEyeDomeShadingSettingsChanged();
207 onDebugShadowMapSettingsChanged();
208 onDebugDepthMapSettingsChanged();
210 onAmbientOcclusionSettingsChanged();
212 onCameraMovementSpeedChanged();
214 on3DAxisSettingsChanged();
221 mCameraController->resetGlobe( 10'000'000 );
227 const double side = std::max( extent.
width(), extent.
height() );
228 double d = side / 2 / std::tan(
cameraController()->camera()->fieldOfView() / 2 * M_PI / 180 );
230 mCameraController->resetView(
static_cast<float>( d ) );
241 const double xSide = std::abs( p1.
x() - p2.
x() );
242 const double ySide = std::abs( p1.
y() - p2.
y() );
243 const double side = std::max( xSide, ySide );
245 const double fov = qDegreesToRadians(
cameraController()->camera()->fieldOfView() );
246 double distance = side / 2.0f / std::tan( fov / 2.0f );
251 distance += zRange.
upper();
254 mCameraController->setViewFromTop(
255 static_cast<float>( center.
x() - origin.
x() ),
256 static_cast<float>( center.
y() - origin.
y() ),
257 static_cast<float>( distance )
263 Qt3DRender::QCamera *camera = mCameraController->camera();
264 QVector<QgsPointXY> extent;
265 QVector<int> pointsOrder = { 0, 1, 3, 2 };
266 for (
int i : pointsOrder )
268 const QPoint p( ( ( i >> 0 ) & 1 ) ? 0 : mEngine->size().width(), ( ( i >> 1 ) & 1 ) ? 0 : mEngine->size().height() );
271 if ( dir.z() == 0.0 )
272 dir.setZ( 0.000001 );
273 double t = -ray.
origin().z() / dir.z();
277 t = camera->farPlane();
282 t = std::min<float>( t, camera->farPlane() );
284 QVector3D planePoint = ray.
origin() + t * dir;
285 QgsVector3D pMap = mMap.worldToMapCoordinates( planePoint );
294 for ( Qgs3DMapSceneEntity *entity : std::as_const( mSceneEntities ) )
295 count += entity->pendingJobsCount();
301 Qt3DRender::QCamera *camera = mCameraController->camera();
302 const double fov = camera->fieldOfView();
303 const QSize size = mEngine->size();
304 const int screenSizePx = std::max( size.width(), size.height() );
308 const double frustumWidthAtDistance = 2 * distance * tan( fov / 2 );
309 const double err = frustumWidthAtDistance * epsilon / screenSizePx;
313void Qgs3DMapScene::onCameraChanged()
315 if ( mMap.
projectionType() == Qt3DRender::QCameraLens::OrthographicProjection )
317 QRect viewportRect( QPoint( 0, 0 ), mEngine->
size() );
318 const float viewWidthFromCenter = mCameraController->
distance();
319 const float viewHeightFromCenter = viewportRect.height() * viewWidthFromCenter / viewportRect.width();
320 mEngine->
camera()->lens()->setOrthographicProjection( -viewWidthFromCenter, viewWidthFromCenter, -viewHeightFromCenter, viewHeightFromCenter, mEngine->
camera()->nearPlane(), mEngine->
camera()->farPlane() );
324 updateCameraNearFarPlanes();
326 onShadowSettingsChanged();
337 constexpr float ORIGIN_SHIFT_THRESHOLD = 10'000;
338 if ( mSceneOriginShiftEnabled && mEngine->camera()->position().length() > ORIGIN_SHIFT_THRESHOLD )
340 const QgsVector3D newOrigin = mMap.origin() + QgsVector3D( mEngine->camera()->position() );
341 QgsDebugMsgLevel( QStringLiteral(
"Rebasing scene origin from %1 to %2" ).arg( mMap.origin().toString( 1 ), newOrigin.
toString( 1 ) ), 2 );
342 mMap.setOrigin( newOrigin );
346bool Qgs3DMapScene::updateScene(
bool forceUpdate )
348 if ( !mSceneUpdatesEnabled )
354 QgsEventTracing::ScopedEvent traceEvent( QStringLiteral(
"3D" ), forceUpdate ? QStringLiteral(
"Force update scene" ) : QStringLiteral(
"Update scene" ) );
356 Qgs3DMapSceneEntity::SceneContext sceneContext;
357 Qt3DRender::QCamera *camera = mEngine->camera();
358 sceneContext.cameraFov = camera->fieldOfView();
359 sceneContext.cameraPos = camera->position();
360 const QSize size = mEngine->size();
361 sceneContext.screenSizePx = std::max( size.width(), size.height() );
369 QMatrix4x4 projMatrix;
370 switch ( mMap.projectionType() )
372 case Qt3DRender::QCameraLens::PerspectiveProjection:
374 float fovRadians = ( camera->fieldOfView() / 2.0f ) *
static_cast<float>( M_PI ) / 180.0f;
375 float fovCotan = std::cos( fovRadians ) / std::sin( fovRadians );
377 fovCotan / camera->aspectRatio(), 0, 0, 0,
384 case Qt3DRender::QCameraLens::OrthographicProjection:
386 Qt3DRender::QCameraLens *lens = camera->lens();
388 2.0f / ( lens->right() - lens->left() ),
393 2.0f / ( lens->top() - lens->bottom() ),
400 -( lens->left() + lens->right() ) / ( lens->right() - lens->left() ),
401 -( lens->top() + lens->bottom() ) / ( lens->top() - lens->bottom() ),
409 projMatrix = camera->projectionMatrix();
411 sceneContext.viewProjectionMatrix = projMatrix * camera->viewMatrix();
414 bool anyUpdated =
false;
415 for ( Qgs3DMapSceneEntity *entity : std::as_const( mSceneEntities ) )
417 if ( forceUpdate || ( entity->isEnabled() && entity->needsUpdate() ) )
420 entity->handleSceneUpdate( sceneContext );
421 if ( entity->hasReachedGpuMemoryLimit() )
431bool Qgs3DMapScene::updateCameraNearFarPlanes()
446 QMatrix4x4 viewMatrix = camera->viewMatrix();
452 for ( Qgs3DMapSceneEntity *se : std::as_const( mSceneEntities ) )
454 const QgsRange<float> depthRange = se->getNearFarPlaneRange( viewMatrix );
456 fnear = std::min( fnear, depthRange.
lower() );
457 ffar = std::max( ffar, depthRange.
upper() );
466 if ( fnear == 1e9 && ffar == 0 )
469 sceneZRange = sceneZRange.
isInfinite() ? QgsDoubleRange( 0.0, 0.0 ) : sceneZRange;
476 std::swap( fnear, ffar );
479 float newFar = ffar * 2;
480 float newNear = fnear / 2;
483 camera->setFarPlane( newFar );
484 camera->setNearPlane( newNear );
491void Qgs3DMapScene::onFrameTriggered(
float dt )
493 QgsEventTracing::addEvent( QgsEventTracing::EventType::Instant, QStringLiteral(
"3D" ), QStringLiteral(
"Frame begins" ) );
495 mCameraController->frameTriggered( dt );
500 updateCameraNearFarPlanes();
503 static int frameCount = 0;
504 static float accumulatedTime = 0.0f;
506 if ( !mMap.isFpsCounterEnabled() )
514 accumulatedTime += dt;
515 if ( accumulatedTime >= 0.2f )
517 float fps = ( float ) frameCount / accumulatedTime;
519 accumulatedTime = 0.0f;
524void Qgs3DMapScene::createTerrain()
528 mSceneEntities.removeOne( mTerrain );
536 mSceneEntities.removeOne( mGlobe );
542 if ( !mTerrainUpdateScheduled )
545 QTimer::singleShot( 0,
this, &Qgs3DMapScene::createTerrainDeferred );
546 mTerrainUpdateScheduled =
true;
555void Qgs3DMapScene::createTerrainDeferred()
557 QgsChunkedEntity *terrainOrGlobe =
nullptr;
561 mGlobe =
new QgsGlobeEntity( &mMap );
562 terrainOrGlobe = mGlobe;
564 else if ( mMap.sceneMode() ==
Qgis::SceneMode::Local && mMap.terrainRenderingEnabled() && mMap.terrainGenerator() )
566 double tile0width = mMap.terrainGenerator()->rootChunkExtent().width();
567 int maxZoomLevel =
Qgs3DUtils::maxZoomLevel( tile0width, mMap.terrainSettings()->mapTileResolution(), mMap.terrainSettings()->maximumGroundError() );
568 const QgsBox3D rootBox3D = mMap.terrainGenerator()->rootChunkBox3D( mMap );
569 float rootError = mMap.terrainGenerator()->rootChunkError( mMap );
570 const QgsBox3D clippingBox3D( mMap.extent(), rootBox3D.
zMinimum(), rootBox3D.
zMaximum() );
571 mMap.terrainGenerator()->setupQuadtree( rootBox3D, rootError, maxZoomLevel, clippingBox3D );
573 mTerrain =
new QgsTerrainEntity( &mMap );
574 terrainOrGlobe = mTerrain;
577 if ( terrainOrGlobe )
579 terrainOrGlobe->setParent(
this );
580 terrainOrGlobe->setShowBoundingBoxes( mMap.showTerrainBoundingBoxes() );
582 mSceneEntities << terrainOrGlobe;
585 connect( terrainOrGlobe, &Qgs3DMapSceneEntity::newEntityCreated,
this, [
this]( Qt3DCore::QEntity *entity ) {
587 const QList<QgsGeoTransform *> transforms = entity->findChildren<QgsGeoTransform *>();
588 for ( QgsGeoTransform *transform : transforms )
590 transform->setOrigin( mMap.origin() );
594 handleClippingOnEntity( entity );
599 const QList<QgsMapLayer *>
layers = mMap.layers();
600 for ( QgsMapLayer *layer :
layers )
603 removeLayerEntity( layer );
606 addLayerEntity( layer );
611 mTerrainUpdateScheduled =
false;
614void Qgs3DMapScene::onBackgroundColorChanged()
616 mEngine->setClearColor( mMap.backgroundColor() );
619void Qgs3DMapScene::updateLights()
621 for ( Qt3DCore::QEntity *entity : std::as_const( mLightEntities ) )
622 entity->deleteLater();
623 mLightEntities.clear();
625 const QList<QgsLightSource *> newLights = mMap.lightSources();
626 for (
const QgsLightSource *source : newLights )
628 mLightEntities.append( source->createEntity( mMap,
this ) );
631 onShadowSettingsChanged();
634void Qgs3DMapScene::updateCameraLens()
636 mEngine->camera()->lens()->setFieldOfView( mMap.fieldOfView() );
637 mEngine->camera()->lens()->setProjectionType( mMap.projectionType() );
641void Qgs3DMapScene::onLayerRenderer3DChanged()
643 QgsMapLayer *layer = qobject_cast<QgsMapLayer *>( sender() );
647 removeLayerEntity( layer );
650 addLayerEntity( layer );
653void Qgs3DMapScene::onLayersChanged()
655 QSet<QgsMapLayer *> layersBefore = qgis::listToSet( mLayerEntities.keys() );
656 QList<QgsMapLayer *> layersAdded;
657 const QList<QgsMapLayer *>
layers = mMap.layers();
658 for ( QgsMapLayer *layer :
layers )
660 if ( !layersBefore.contains( layer ) )
662 layersAdded << layer;
666 layersBefore.remove( layer );
671 for ( QgsMapLayer *layer : std::as_const( layersBefore ) )
673 removeLayerEntity( layer );
676 for ( QgsMapLayer *layer : std::as_const( layersAdded ) )
678 addLayerEntity( layer );
684 const QList<QgsMapLayer *>
layers = mLayerEntities.keys();
689 if ( temporalProperties->isActive() )
691 removeLayerEntity( layer );
692 addLayerEntity( layer );
700 Q_ASSERT( sceneNewEntity );
702 mSceneEntities.append( sceneNewEntity );
704 sceneNewEntity->setParent(
this );
706 finalizeNewEntity( sceneNewEntity );
708 connect( sceneNewEntity, &Qgs3DMapSceneEntity::newEntityCreated,
this, [
this]( Qt3DCore::QEntity *entity ) {
709 finalizeNewEntity( entity );
711 updateCameraNearFarPlanes();
721 Q_ASSERT( sceneEntity );
723 mSceneEntities.removeOne( sceneEntity );
725 sceneEntity->deleteLater();
729void Qgs3DMapScene::addLayerEntity(
QgsMapLayer *layer )
741 if ( renderer->
type() == QLatin1String(
"vector" ) )
749 mModelVectorLayers.append( layer );
753 else if ( renderer->
type() == QLatin1String(
"rulebased" ) )
756 for (
auto rule : rules )
758 const QgsPoint3DSymbol *pointSymbol =
dynamic_cast<const QgsPoint3DSymbol *
>( rule->symbol() );
761 mModelVectorLayers.append( layer );
769 QgsMeshLayer3DRenderer *meshRenderer =
static_cast<QgsMeshLayer3DRenderer *
>( renderer );
770 meshRenderer->
setLayer(
static_cast<QgsMeshLayer *
>( layer ) );
774 QgsMesh3DSymbol *sym = meshRenderer->
symbol()->
clone();
780 QgsPointCloudLayer3DRenderer *pointCloudRenderer =
static_cast<QgsPointCloudLayer3DRenderer *
>( renderer );
781 pointCloudRenderer->
setLayer(
static_cast<QgsPointCloudLayer *
>( layer ) );
785 QgsTiledSceneLayer3DRenderer *tiledSceneRenderer =
static_cast<QgsTiledSceneLayer3DRenderer *
>( renderer );
786 tiledSceneRenderer->
setLayer(
static_cast<QgsTiledSceneLayer *
>( layer ) );
790 auto annotationLayerRenderer = qgis::down_cast<QgsAnnotationLayer3DRenderer *>( renderer );
791 annotationLayerRenderer->setLayer( qobject_cast<QgsAnnotationLayer *>( layer ) );
794 Qt3DCore::QEntity *newEntity = renderer->
createEntity( &mMap );
797 mLayerEntities.insert( layer, newEntity );
799 if ( Qgs3DMapSceneEntity *sceneNewEntity = qobject_cast<Qgs3DMapSceneEntity *>( newEntity ) )
806 newEntity->setParent(
this );
807 finalizeNewEntity( newEntity );
816 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
829 QgsPointCloudLayer *pclayer = qobject_cast<QgsPointCloudLayer *>( layer );
835void Qgs3DMapScene::removeLayerEntity(
QgsMapLayer *layer )
837 Qt3DCore::QEntity *entity = mLayerEntities.take( layer );
839 if ( Qgs3DMapSceneEntity *sceneEntity = qobject_cast<Qgs3DMapSceneEntity *>( entity ) )
847 entity->deleteLater();
854 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
858 mModelVectorLayers.removeAll( layer );
868 QgsPointCloudLayer *pclayer = qobject_cast<QgsPointCloudLayer *>( layer );
875void Qgs3DMapScene::finalizeNewEntity( Qt3DCore::QEntity *newEntity )
878 const QList<QgsGeoTransform *> transforms = newEntity->findChildren<QgsGeoTransform *>();
879 for ( QgsGeoTransform *transform : transforms )
881 transform->setOrigin( mMap.origin() );
885 handleClippingOnEntity( newEntity );
889 const QList<QgsLineMaterial *> childLineMaterials = newEntity->findChildren<QgsLineMaterial *>();
890 for ( QgsLineMaterial *lm : childLineMaterials )
893 lm->setViewportSize( mEngine->size() );
896 lm->setViewportSize( mEngine->size() );
899 const QList<QgsPoint3DBillboardMaterial *> childBillboardMaterials = newEntity->findChildren<QgsPoint3DBillboardMaterial *>();
900 for ( QgsPoint3DBillboardMaterial *bm : childBillboardMaterials )
903 bm->setViewportSize( mEngine->size() );
906 bm->setViewportSize( mEngine->size() );
910 QgsFrameGraph *frameGraph = mEngine->frameGraph();
912 const QList<Qt3DRender::QMaterial *> childMaterials = newEntity->findChildren<Qt3DRender::QMaterial *>();
913 for ( Qt3DRender::QMaterial *material : childMaterials )
916 if ( Qt3DExtras::QDiffuseSpecularMaterial *ph = qobject_cast<Qt3DExtras::QDiffuseSpecularMaterial *>( material ) )
918 if ( ph->diffuse().value<QColor>().alphaF() != 1.0f )
920 Qt3DCore::QEntity *entity = qobject_cast<Qt3DCore::QEntity *>( ph->parent() );
921 if ( entity && !entity->components().contains( transparentLayer ) )
923 entity->addComponent( transparentLayer );
944 else if ( QgsPoint3DBillboardMaterial *billboardMaterial = qobject_cast<QgsPoint3DBillboardMaterial *>( material ) )
946 Qt3DCore::QEntity *entity = qobject_cast<Qt3DCore::QEntity *>( billboardMaterial->parent() );
947 if ( entity && !entity->components().contains( transparentLayer ) )
949 entity->addComponent( transparentLayer );
956 Qt3DRender::QEffect *effect = material->effect();
959 const QVector<Qt3DRender::QParameter *> parameters = effect->parameters();
960 for (
const Qt3DRender::QParameter *parameter : parameters )
962 if ( parameter->name() ==
"opacity" && parameter->value() != 1.0f )
964 Qt3DCore::QEntity *entity = qobject_cast<Qt3DCore::QEntity *>( material->parent() );
965 if ( entity && !entity->components().contains( transparentLayer ) )
967 entity->addComponent( transparentLayer );
977int Qgs3DMapScene::maximumTextureSize()
const
979 QSurface *surface = mEngine->surface();
980 QOpenGLContext context;
982 bool success = context.makeCurrent( surface );
986 QOpenGLFunctions openglFunctions = QOpenGLFunctions( &context );
989 openglFunctions.initializeOpenGLFunctions();
990 openglFunctions.glGetIntegerv( GL_MAX_TEXTURE_SIZE, &size );
999void Qgs3DMapScene::addCameraViewCenterEntity( Qt3DRender::QCamera *camera )
1001 mEntityCameraViewCenter =
new Qt3DCore::QEntity;
1003 Qt3DCore::QTransform *trCameraViewCenter =
new Qt3DCore::QTransform;
1004 mEntityCameraViewCenter->addComponent( trCameraViewCenter );
1005 connect( camera, &Qt3DRender::QCamera::viewCenterChanged,
this, [trCameraViewCenter, camera] {
1006 trCameraViewCenter->setTranslation( camera->viewCenter() );
1009 Qt3DExtras::QPhongMaterial *materialCameraViewCenter =
new Qt3DExtras::QPhongMaterial;
1010 materialCameraViewCenter->setAmbient( Qt::red );
1011 mEntityCameraViewCenter->addComponent( materialCameraViewCenter );
1013 Qt3DExtras::QSphereMesh *rendererCameraViewCenter =
new Qt3DExtras::QSphereMesh;
1014 rendererCameraViewCenter->setRadius( 10 );
1015 mEntityCameraViewCenter->addComponent( rendererCameraViewCenter );
1017 mEntityCameraViewCenter->setEnabled( mMap.showCameraViewCenter() );
1018 mEntityCameraViewCenter->setParent(
this );
1021 mEntityCameraViewCenter->setEnabled( mMap.showCameraViewCenter() );
1027 if ( mSceneState == state )
1029 mSceneState = state;
1033void Qgs3DMapScene::updateSceneState()
1035 if ( mTerrainUpdateScheduled )
1041 for ( Qgs3DMapSceneEntity *entity : std::as_const( mSceneEntities ) )
1043 if ( entity->isEnabled() && entity->pendingJobsCount() > 0 )
1050 setSceneState(
Ready );
1053void Qgs3DMapScene::onSkyboxSettingsChanged()
1055 QgsSkyboxSettings skyboxSettings = mMap.skyboxSettings();
1058 mSkybox->deleteLater();
1062 mEngine->setFrustumCullingEnabled( !mMap.isSkyboxEnabled() );
1064 if ( mMap.isSkyboxEnabled() )
1066 QMap<QString, QString> faces;
1071 mSkybox =
new QgsCubeFacesSkyboxEntity(
1072 faces[QStringLiteral(
"posX" )], faces[QStringLiteral(
"posY" )], faces[QStringLiteral(
"posZ" )],
1073 faces[QStringLiteral(
"negX" )], faces[QStringLiteral(
"negY" )], faces[QStringLiteral(
"negZ" )],
1084void Qgs3DMapScene::onShadowSettingsChanged()
1086 mEngine->frameGraph()->updateShadowSettings( mMap.shadowSettings(), mMap.lightSources() );
1089void Qgs3DMapScene::onAmbientOcclusionSettingsChanged()
1091 mEngine->frameGraph()->updateAmbientOcclusionSettings( mMap.ambientOcclusionSettings() );
1094void Qgs3DMapScene::onDebugShadowMapSettingsChanged()
1096 mEngine->frameGraph()->updateDebugShadowMapSettings( mMap );
1099void Qgs3DMapScene::onDebugDepthMapSettingsChanged()
1101 mEngine->frameGraph()->updateDebugDepthMapSettings( mMap );
1104void Qgs3DMapScene::onDebugOverlayEnabledChanged()
1106 mEngine->frameGraph()->setDebugOverlayEnabled( mMap.isDebugOverlayEnabled() );
1107 mEngine->renderSettings()->setRenderPolicy( mMap.isDebugOverlayEnabled() ? Qt3DRender::QRenderSettings::Always : Qt3DRender::QRenderSettings::OnDemand );
1110void Qgs3DMapScene::onEyeDomeShadingSettingsChanged()
1112 mEngine->frameGraph()->updateEyeDomeSettings( mMap );
1115void Qgs3DMapScene::onCameraMovementSpeedChanged()
1117 mCameraController->setCameraMovementSpeed( mMap.cameraMovementSpeed() );
1120void Qgs3DMapScene::onCameraNavigationModeChanged()
1122 mCameraController->setCameraNavigationMode( mMap.cameraNavigationMode() );
1127 QVector<QString> notParsedLayers;
1137 for (
auto it = mLayerEntities.constBegin(); it != mLayerEntities.constEnd(); ++it )
1140 Qt3DCore::QEntity *rootEntity = it.value();
1142 switch ( layerType )
1146 notParsedLayers.push_back( layer->
name() );
1156 notParsedLayers.push_back( layer->
name() );
1170 if ( !notParsedLayers.empty() )
1172 QString message = tr(
"The following layers were not exported:" ) +
"\n";
1173 for (
const QString &layerName : notParsedLayers )
1174 message += layerName +
"\n";
1183 QVector<const QgsChunkNode *> chunks;
1184 if ( !mLayerEntities.contains( layer ) )
1186 if ( QgsChunkedEntity *
c = qobject_cast<QgsChunkedEntity *>( mLayerEntities[layer] ) )
1188 const QList<QgsChunkNode *> activeNodes =
c->activeNodes();
1189 for ( QgsChunkNode *n : activeNodes )
1190 chunks.push_back( n );
1197 return mMap.extent();
1202 double zMin = std::numeric_limits<double>::max();
1203 double zMax = std::numeric_limits<double>::lowest();
1204 if ( mMap.terrainRenderingEnabled() && mTerrain && !ignoreTerrain )
1206 const QgsBox3D box3D = mTerrain->rootNode()->box3D();
1207 zMin = std::min( zMin, box3D.
zMinimum() );
1208 zMax = std::max( zMax, box3D.
zMaximum() );
1211 for (
auto it = mLayerEntities.constBegin(); it != mLayerEntities.constEnd(); it++ )
1214 switch ( layer->
type() )
1220 zMin = std::min( zMin, zRange.
lower() );
1221 zMax = std::max( zMax, zRange.
upper() );
1226 QgsMeshLayer *meshLayer = qobject_cast<QgsMeshLayer *>( layer );
1234 zMin = std::min( zMin, verticalGroupMetadata.
minimum() * verticalScale );
1235 zMax = std::max( zMax, verticalGroupMetadata.
maximum() * verticalScale );
1245 zMin = std::min( zMin, zRange.
lower() );
1246 zMax = std::max( zMax, zRange.
upper() );
1259 const QgsDoubleRange zRange( std::min( zMin, std::numeric_limits<double>::max() ), std::max( zMax, std::numeric_limits<double>::lowest() ) );
1270 mEntityRotationCenter =
new Qt3DCore::QEntity;
1272 Qt3DCore::QTransform *trRotationCenter =
new Qt3DCore::QTransform;
1273 mEntityRotationCenter->addComponent( trRotationCenter );
1274 Qt3DExtras::QPhongMaterial *materialRotationCenter =
new Qt3DExtras::QPhongMaterial;
1275 materialRotationCenter->setAmbient( Qt::blue );
1276 mEntityRotationCenter->addComponent( materialRotationCenter );
1277 Qt3DExtras::QSphereMesh *rendererRotationCenter =
new Qt3DExtras::QSphereMesh;
1278 rendererRotationCenter->setRadius( 10 );
1279 mEntityRotationCenter->addComponent( rendererRotationCenter );
1280 mEntityRotationCenter->setEnabled(
false );
1281 mEntityRotationCenter->setParent(
this );
1284 trRotationCenter->setTranslation( center );
1288 mEntityRotationCenter->setEnabled( mMap.showCameraRotationCenter() );
1292void Qgs3DMapScene::on3DAxisSettingsChanged()
1296 m3DAxis->onAxisSettingsChanged();
1300 if ( QgsWindow3DEngine *
engine =
dynamic_cast<QgsWindow3DEngine *
>( mEngine ) )
1302 m3DAxis =
new Qgs3DAxis(
static_cast<Qgs3DMapCanvas *
>(
engine->window() ),
engine->root(),
this, mCameraController, &mMap );
1307void Qgs3DMapScene::onOriginChanged()
1309 const QList<QgsGeoTransform *> geoTransforms = findChildren<QgsGeoTransform *>();
1310 for ( QgsGeoTransform *transform : geoTransforms )
1312 transform->setOrigin( mMap.origin() );
1315 const QList<QgsGeoTransform *> rubberBandGeoTransforms = mEngine->frameGraph()->rubberBandsRootEntity()->findChildren<QgsGeoTransform *>();
1316 for ( QgsGeoTransform *transform : rubberBandGeoTransforms )
1318 transform->setOrigin( mMap.origin() );
1321 const QgsVector3D oldOrigin = mCameraController->origin();
1322 mCameraController->setOrigin( mMap.origin() );
1324 if ( !mClipPlanesEquations.isEmpty() )
1333 QList<QVector4D> newPlanes;
1334 QgsVector3D originShift = mMap.origin() - oldOrigin;
1335 for ( QVector4D plane : std::as_const( mClipPlanesEquations ) )
1337 plane.setW( originShift.
x() * plane.x() + originShift.
y() * plane.y() + originShift.
z() * plane.z() + plane.w() );
1338 newPlanes.append( plane );
1344void Qgs3DMapScene::handleClippingOnEntity( QEntity *entity )
const
1346 if ( mClipPlanesEquations.isEmpty() )
1348 for ( QgsMaterial *material : entity->componentsOfType<QgsMaterial>() )
1350 material->disableClipping();
1355 for ( QgsMaterial *material : entity->componentsOfType<QgsMaterial>() )
1357 material->enableClipping( mClipPlanesEquations );
1363 for ( QObject *child : entity->children() )
1365 Qt3DCore::QEntity *childEntity = qobject_cast<Qt3DCore::QEntity *>( child );
1368 handleClippingOnEntity( childEntity );
1373void Qgs3DMapScene::handleClippingOnAllEntities()
const
1377 for (
auto it = mLayerEntities.constBegin(); it != mLayerEntities.constEnd(); ++it )
1379 handleClippingOnEntity( it.value() );
1383 handleClippingOnEntity( mTerrain );
1387 handleClippingOnEntity( mGlobe );
1395 QgsDebugMsgLevel( QStringLiteral(
"Qgs3DMapScene::enableClipping: it is not possible to use more than %1 clipping planes." ).arg( mMaxClipPlanes ), 2 );
1403 handleClippingOnAllEntities();
1408 mClipPlanesEquations.clear();
1411 mEngine->frameGraph()->removeClipPlanes();
1414 handleClippingOnAllEntities();
1417void 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)