18 #include <Qt3DRender/QCamera>
19 #include <Qt3DRender/QMesh>
20 #include <Qt3DRender/QObjectPicker>
21 #include <Qt3DRender/QPickEvent>
22 #include <Qt3DRender/QPickingSettings>
23 #include <Qt3DRender/QPickTriangleEvent>
24 #include <Qt3DRender/QRenderSettings>
25 #include <Qt3DRender/QSceneLoader>
26 #include <Qt3DExtras/QForwardRenderer>
27 #include <Qt3DExtras/QPhongMaterial>
28 #include <Qt3DExtras/QPhongAlphaMaterial>
29 #include <Qt3DExtras/QDiffuseSpecularMaterial>
30 #include <Qt3DExtras/QSphereMesh>
31 #include <Qt3DLogic/QFrameAction>
32 #include <Qt3DRender/QEffect>
33 #include <Qt3DRender/QTechnique>
34 #include <Qt3DRender/QRenderPass>
35 #include <Qt3DRender/QRenderState>
36 #include <Qt3DRender/QCullFace>
37 #include <Qt3DRender/QDepthTest>
42 #include <QOpenGLContext>
43 #include <QOpenGLFunctions>
94 onBackgroundColorChanged();
99 mEngine->
renderSettings()->setRenderPolicy( Qt3DRender::QRenderSettings::OnDemand );
102 mEngine->
renderSettings()->pickingSettings()->setPickMethod( Qt3DRender::QPickingSettings::TrianglePicking );
104 QRect viewportRect( QPoint( 0, 0 ), mEngine->
size() );
107 float aspectRatio = ( float )viewportRect.width() / viewportRect.height();
108 mEngine->
camera()->lens()->setPerspectiveProjection( mMap.
fieldOfView(), aspectRatio, 10.f, 10000.0f );
110 mFrameAction =
new Qt3DLogic::QFrameAction();
111 connect( mFrameAction, &Qt3DLogic::QFrameAction::triggered,
112 this, &Qgs3DMapScene::onFrameTriggered );
113 addComponent( mFrameAction );
121 addCameraViewCenterEntity( mEngine->
camera() );
122 addCameraRotationCenterEntity( mCameraController );
127 createTerrainDeferred();
155 const QList<QgsMapLayer *> modelVectorLayers = mModelVectorLayers;
161 if ( renderer->
type() == QLatin1String(
"vector" ) )
164 if ( pointSymbol->
shapeProperties()[QStringLiteral(
"model" )].toString() == url )
166 removeLayerEntity( layer );
167 addLayerEntity( layer );
170 else if ( renderer->
type() == QLatin1String(
"rulebased" ) )
173 for (
auto rule : rules )
176 if ( pointSymbol->
shapeProperties()[QStringLiteral(
"model" )].toString() == url )
178 removeLayerEntity( layer );
179 addLayerEntity( layer );
190 onRenderersChanged();
197 ChunkedEntity *testChunkEntity =
new ChunkedEntity( AABB( -500, 0, -500, 500, 100, 500 ), 2.f, 3.f, 7,
new TestChunkLoaderFactory );
198 testChunkEntity->setEnabled(
false );
199 testChunkEntity->setParent(
this );
200 chunkEntities << testChunkEntity;
211 Qt3DCore::QEntity *loaderEntity =
new Qt3DCore::QEntity;
212 Qt3DRender::QSceneLoader *loader =
new Qt3DRender::QSceneLoader;
213 loader->setSource( QUrl(
"file:///home/martin/Downloads/LowPolyModels/tree.dae" ) );
214 loaderEntity->addComponent( loader );
215 loaderEntity->setParent(
this );
219 Qt3DCore::QEntity *meshEntity =
new Qt3DCore::QEntity;
220 Qt3DRender::QMesh *mesh =
new Qt3DRender::QMesh;
221 mesh->setSource( QUrl(
"file:///home/martin/Downloads/LowPolyModels/tree.obj" ) );
222 meshEntity->addComponent( mesh );
223 Qt3DExtras::QPhongMaterial *material =
new Qt3DExtras::QPhongMaterial;
224 material->setAmbient( Qt::red );
225 meshEntity->addComponent( material );
226 Qt3DCore::QTransform *meshTransform =
new Qt3DCore::QTransform;
227 meshTransform->setScale( 1 );
228 meshEntity->addComponent( meshTransform );
229 meshEntity->setParent(
this );
231 onSkyboxSettingsChanged();
236 onEyeDomeShadingSettingsChanged();
238 onDebugShadowMapSettingsChanged();
239 onDebugDepthMapSettingsChanged();
242 onCameraMovementSpeedChanged();
244 on3DAxisSettingsChanged();
250 float side = std::max( extent.
width(), extent.
height() );
251 float a = side / 2.0f / std::sin( qDegreesToRadians(
cameraController()->camera()->fieldOfView() ) / 2.0f );
253 mCameraController->
resetView( 1.5 * std::sqrt( a * a - side * side ) );
263 float xSide = std::abs( p1.
x() - p2.
x() );
264 float ySide = std::abs( p1.
z() - p2.
z() );
267 float fov = 2 * std::atan( std::tan( qDegreesToRadians(
cameraController()->camera()->fieldOfView() ) / 2 ) *
cameraController()->camera()->aspectRatio() );
268 float r = xSide / 2.0f / std::tan( fov / 2.0f );
273 float fov = qDegreesToRadians(
cameraController()->camera()->fieldOfView() );
274 float r = ySide / 2.0f / std::tan( fov / 2.0f );
281 Qt3DRender::QCamera *camera = mCameraController->
camera();
282 const QRect viewport = mCameraController->
viewport();
283 QVector<QgsPointXY> extent;
284 QVector<int> pointsOrder = { 0, 1, 3, 2 };
285 for (
int i : pointsOrder )
287 const QPoint p( ( ( i >> 0 ) & 1 ) ? 0 : viewport.width(), ( ( i >> 1 ) & 1 ) ? 0 : viewport.height() );
290 if ( dir.y() == 0.0 )
291 dir.setY( 0.000001 );
292 double t = - ray.
origin().y() / dir.y();
296 t = camera->farPlane();
301 t = std::min<float>( t, camera->farPlane() );
303 QVector3D planePoint = ray.
origin() + t * dir;
312 return mTerrain ? mTerrain->pendingJobsCount() : 0;
318 for ( QgsChunkedEntity *entity : std::as_const( mChunkEntities ) )
319 count += entity->pendingJobsCount();
325 if ( mPickHandlers.isEmpty() )
328 for ( Qt3DCore::QEntity *entity : mLayerEntities.values() )
330 if ( QgsChunkedEntity *chunkedEntity = qobject_cast<QgsChunkedEntity *>( entity ) )
331 chunkedEntity->setPickingEnabled(
true );
335 mPickHandlers.append( pickHandler );
340 mPickHandlers.removeOne( pickHandler );
342 if ( mPickHandlers.isEmpty() )
345 for ( Qt3DCore::QEntity *entity : mLayerEntities.values() )
347 if ( QgsChunkedEntity *chunkedEntity = qobject_cast<QgsChunkedEntity *>( entity ) )
348 chunkedEntity->setPickingEnabled(
false );
353 void Qgs3DMapScene::onLayerEntityPickedObject( Qt3DRender::QPickEvent *pickEvent,
QgsFeatureId fid )
355 QgsMapLayer *layer = mLayerEntities.key( qobject_cast<QgsChunkedEntity *>( sender() ) );
365 pickHandler->handlePickOnVectorLayer( vlayer, fid, pickEvent->worldIntersection(), pickEvent );
371 Qt3DRender::QCamera *camera = mCameraController->
camera();
372 float fov = camera->fieldOfView();
373 QRect rect = mCameraController->
viewport();
374 float screenSizePx = std::max( rect.width(), rect.height() );
378 float frustumWidthAtDistance = 2 * distance * tan( fov / 2 );
379 float err = frustumWidthAtDistance * epsilon / screenSizePx;
385 Qt3DRender::QCamera *camera = cameraController->
camera();
386 QgsChunkedEntity::SceneState state;
387 state.cameraFov = camera->fieldOfView();
388 state.cameraPos = camera->position();
389 QRect rect = cameraController->
viewport();
390 state.screenSizePx = std::max( rect.width(), rect.height() );
391 state.viewProjectionMatrix = camera->projectionMatrix() * camera->viewMatrix();
395 void Qgs3DMapScene::onCameraChanged()
397 if ( mMap.
projectionType() == Qt3DRender::QCameraLens::OrthographicProjection )
399 QRect viewportRect( QPoint( 0, 0 ), mEngine->
size() );
400 const float viewWidthFromCenter = mCameraController->
distance();
401 const float viewHeightFromCenter = viewportRect.height() * viewWidthFromCenter / viewportRect.width();
402 mEngine->
camera()->lens()->setOrthographicProjection( -viewWidthFromCenter, viewWidthFromCenter, -viewHeightFromCenter, viewHeightFromCenter, mEngine->
camera()->nearPlane(), mEngine->
camera()->farPlane() );
406 bool changedCameraPlanes = updateCameraNearFarPlanes();
408 if ( changedCameraPlanes )
413 updateCameraNearFarPlanes();
416 onShadowSettingsChanged();
424 QVector<Qt3DCore::QComponent *> toBeRemovedComponents;
425 for ( Qt3DCore::QComponent *component : entity->components() )
427 Qt3DRender::QLayer *layer = qobject_cast<Qt3DRender::QLayer *>( component );
428 if ( layer !=
nullptr )
429 toBeRemovedComponents.push_back( layer );
431 for ( Qt3DCore::QComponent *component : toBeRemovedComponents )
432 entity->removeComponent( component );
433 for ( Qt3DCore::QEntity *obj : entity->findChildren<Qt3DCore::QEntity *>() )
435 if ( obj !=
nullptr )
442 for ( Qt3DRender::QLayer *layer : layers )
443 entity->addComponent( layer );
444 for ( Qt3DCore::QEntity *child : entity->findChildren<Qt3DCore::QEntity *>() )
446 if ( child !=
nullptr )
451 void Qgs3DMapScene::updateScene()
453 QgsEventTracing::addEvent( QgsEventTracing::Instant, QStringLiteral(
"3D" ), QStringLiteral(
"Update Scene" ) );
454 for ( QgsChunkedEntity *entity : std::as_const( mChunkEntities ) )
456 if ( entity->isEnabled() )
457 entity->update(
_sceneState( mCameraController ) );
462 static void _updateNearFarPlane(
const QList<QgsChunkNode *> &activeNodes,
const QMatrix4x4 &viewMatrix,
float &fnear,
float &ffar )
464 for ( QgsChunkNode *node : activeNodes )
469 for (
int i = 0; i < 8; ++i )
471 QVector4D p( ( ( i >> 0 ) & 1 ) ? bbox.
xMin : bbox.
xMax,
472 ( ( i >> 1 ) & 1 ) ? bbox.
yMin : bbox.
yMax,
473 ( ( i >> 2 ) & 1 ) ? bbox.
zMin : bbox.
zMax, 1 );
475 QVector4D pc = viewMatrix * p;
479 fnear = std::min( fnear, dst );
480 ffar = std::max( ffar, dst );
485 bool Qgs3DMapScene::updateCameraNearFarPlanes()
500 QMatrix4x4 viewMatrix = camera->viewMatrix();
503 QList<QgsChunkNode *> activeNodes;
505 activeNodes = mTerrain->activeNodes();
510 if ( mTerrain && activeNodes.isEmpty() )
511 activeNodes << mTerrain->rootNode();
513 _updateNearFarPlane( activeNodes, viewMatrix, fnear, ffar );
517 for ( QgsChunkedEntity *e : std::as_const( mChunkEntities ) )
521 QList<QgsChunkNode *> activeEntityNodes = e->activeNodes();
522 if ( activeEntityNodes.empty() )
523 activeEntityNodes << e->rootNode();
524 _updateNearFarPlane( activeEntityNodes, viewMatrix, fnear, ffar );
533 std::swap( fnear, ffar );
535 if ( fnear == 1e9 && ffar == 0 )
539 qWarning() <<
"oops... this should not happen! couldn't determine near/far plane. defaulting to 1...1e9";
545 float newFar = ffar * 2;
546 float newNear = fnear / 2;
549 camera->setFarPlane( newFar );
550 camera->setNearPlane( newNear );
557 void Qgs3DMapScene::onFrameTriggered(
float dt )
561 for ( QgsChunkedEntity *entity : std::as_const( mChunkEntities ) )
563 if ( entity->isEnabled() && entity->needsUpdate() )
566 entity->update(
_sceneState( mCameraController ) );
573 static int frameCount = 0;
574 static float accumulatedTime = 0.0f;
584 accumulatedTime += dt;
585 if ( accumulatedTime >= 0.2f )
587 float fps = ( float )frameCount / accumulatedTime;
589 accumulatedTime = 0.0f;
594 void Qgs3DMapScene::createTerrain()
598 mChunkEntities.removeOne( mTerrain );
600 mTerrain->deleteLater();
604 if ( !mTerrainUpdateScheduled )
607 QTimer::singleShot( 0,
this, &Qgs3DMapScene::createTerrainDeferred );
608 mTerrainUpdateScheduled =
true;
617 void Qgs3DMapScene::createTerrainDeferred()
625 mMap.
terrainGenerator()->setupQuadtree( rootBbox, rootError, maxZoomLevel );
627 mTerrain =
new QgsTerrainEntity( mMap );
628 mTerrain->setParent(
this );
633 mChunkEntities << mTerrain;
645 const QList<QgsMapLayer *> layers = mMap.
layers();
649 removeLayerEntity( layer );
652 addLayerEntity( layer );
657 mTerrainUpdateScheduled =
false;
660 void Qgs3DMapScene::onBackgroundColorChanged()
665 void Qgs3DMapScene::updateLights()
667 for ( Qt3DCore::QEntity *entity : std::as_const( mLightEntities ) )
668 entity->deleteLater();
669 mLightEntities.clear();
671 const QList< QgsLightSource * > newLights = mMap.
lightSources();
674 mLightEntities.append( source->createEntity( mMap,
this ) );
677 onShadowSettingsChanged();
680 void Qgs3DMapScene::updateCameraLens()
687 void Qgs3DMapScene::onRenderersChanged()
690 qDeleteAll( mRenderersEntities );
691 mRenderersEntities.clear();
694 const QList<QgsAbstract3DRenderer *> renderers = mMap.
renderers();
697 Qt3DCore::QEntity *newEntity = renderer->createEntity( mMap );
700 newEntity->setParent(
this );
701 finalizeNewEntity( newEntity );
702 mRenderersEntities[renderer] = newEntity;
707 void Qgs3DMapScene::onLayerRenderer3DChanged()
709 QgsMapLayer *layer = qobject_cast<QgsMapLayer *>( sender() );
713 removeLayerEntity( layer );
716 addLayerEntity( layer );
719 void Qgs3DMapScene::onLayersChanged()
721 QSet<QgsMapLayer *> layersBefore = qgis::listToSet( mLayerEntities.keys() );
722 QList<QgsMapLayer *> layersAdded;
723 const QList<QgsMapLayer *> layers = mMap.
layers();
726 if ( !layersBefore.contains( layer ) )
728 layersAdded << layer;
732 layersBefore.remove( layer );
737 for (
QgsMapLayer *layer : std::as_const( layersBefore ) )
739 removeLayerEntity( layer );
742 for (
QgsMapLayer *layer : std::as_const( layersAdded ) )
744 addLayerEntity( layer );
750 for (
auto layer : mLayerEntities.keys() )
754 removeLayerEntity( layer );
755 addLayerEntity( layer );
760 void Qgs3DMapScene::addLayerEntity(
QgsMapLayer *layer )
762 bool needsSceneUpdate =
false;
771 ( renderer->
type() == QLatin1String(
"vector" ) || renderer->
type() == QLatin1String(
"rulebased" ) ) )
774 if ( renderer->
type() == QLatin1String(
"vector" ) )
782 mModelVectorLayers.append( layer );
786 else if ( renderer->
type() == QLatin1String(
"rulebased" ) )
789 for (
auto rule : rules )
794 mModelVectorLayers.append( layer );
817 Qt3DCore::QEntity *newEntity = renderer->
createEntity( mMap );
820 newEntity->setParent(
this );
821 mLayerEntities.insert( layer, newEntity );
823 finalizeNewEntity( newEntity );
825 if ( QgsChunkedEntity *chunkedNewEntity = qobject_cast<QgsChunkedEntity *>( newEntity ) )
827 mChunkEntities.append( chunkedNewEntity );
828 needsSceneUpdate =
true;
830 chunkedNewEntity->setPickingEnabled( !mPickHandlers.isEmpty() );
831 connect( chunkedNewEntity, &QgsChunkedEntity::pickedObject,
this, &Qgs3DMapScene::onLayerEntityPickedObject );
833 connect( chunkedNewEntity, &QgsChunkedEntity::newEntityCreated,
this, [
this]( Qt3DCore::QEntity * entity )
835 finalizeNewEntity( entity );
843 if ( needsSceneUpdate )
868 void Qgs3DMapScene::removeLayerEntity(
QgsMapLayer *layer )
870 Qt3DCore::QEntity *entity = mLayerEntities.take( layer );
872 if ( QgsChunkedEntity *chunkedEntity = qobject_cast<QgsChunkedEntity *>( entity ) )
874 mChunkEntities.removeOne( chunkedEntity );
878 entity->deleteLater();
887 mModelVectorLayers.removeAll( layer );
903 void Qgs3DMapScene::finalizeNewEntity( Qt3DCore::QEntity *newEntity )
907 for ( QgsLineMaterial *lm : newEntity->findChildren<QgsLineMaterial *>() )
911 lm->setViewportSize( mCameraController->
viewport().size() );
921 bm->setViewportSize( mCameraController->
viewport().size() );
924 bm->setViewportSize( mCameraController->
viewport().size() );
931 for ( Qt3DExtras::QDiffuseSpecularMaterial *ph : newEntity->findChildren<Qt3DExtras::QDiffuseSpecularMaterial *>() )
933 if ( ph->diffuse().value<QColor>().alphaF() == 1.0f )
935 Qt3DCore::QEntity *entity = qobject_cast<Qt3DCore::QEntity *>( ph->parent() );
938 if ( entity->components().contains( layer ) )
940 entity->addComponent( layer );
944 int Qgs3DMapScene::maximumTextureSize()
const
946 QSurface *surface = mEngine->
surface();
947 QOpenGLContext context;
949 bool success = context.makeCurrent( surface );
953 QOpenGLFunctions openglFunctions = QOpenGLFunctions( &context );
956 openglFunctions.initializeOpenGLFunctions();
957 openglFunctions.glGetIntegerv( GL_MAX_TEXTURE_SIZE, &size );
967 void Qgs3DMapScene::addCameraViewCenterEntity( Qt3DRender::QCamera *camera )
969 mEntityCameraViewCenter =
new Qt3DCore::QEntity;
971 Qt3DCore::QTransform *trCameraViewCenter =
new Qt3DCore::QTransform;
972 mEntityCameraViewCenter->addComponent( trCameraViewCenter );
973 connect( camera, &Qt3DRender::QCamera::viewCenterChanged,
this, [trCameraViewCenter, camera]
975 trCameraViewCenter->setTranslation( camera->viewCenter() );
978 Qt3DExtras::QPhongMaterial *materialCameraViewCenter =
new Qt3DExtras::QPhongMaterial;
979 materialCameraViewCenter->setAmbient( Qt::red );
980 mEntityCameraViewCenter->addComponent( materialCameraViewCenter );
982 Qt3DExtras::QSphereMesh *rendererCameraViewCenter =
new Qt3DExtras::QSphereMesh;
983 rendererCameraViewCenter->setRadius( 10 );
984 mEntityCameraViewCenter->addComponent( rendererCameraViewCenter );
987 mEntityCameraViewCenter->setParent(
this );
997 if ( mSceneState == state )
1003 void Qgs3DMapScene::updateSceneState()
1005 if ( mTerrainUpdateScheduled )
1011 for ( QgsChunkedEntity *entity : std::as_const( mChunkEntities ) )
1013 if ( entity->isEnabled() && entity->pendingJobsCount() > 0 )
1020 setSceneState(
Ready );
1023 void Qgs3DMapScene::onSkyboxSettingsChanged()
1026 if ( mSkybox !=
nullptr )
1028 mSkybox->deleteLater();
1036 QMap<QString, QString> faces;
1042 faces[QStringLiteral(
"posX" )], faces[QStringLiteral(
"posY" )], faces[QStringLiteral(
"posZ" )],
1043 faces[QStringLiteral(
"negX" )], faces[QStringLiteral(
"negY" )], faces[QStringLiteral(
"negZ" )],
1054 void Qgs3DMapScene::onShadowSettingsChanged()
1058 const QList< QgsLightSource * > lightSources = mMap.
lightSources();
1059 QList< QgsDirectionalLightSettings * > directionalLightSources;
1064 directionalLightSources << qgis::down_cast< QgsDirectionalLightSettings * >( source );
1070 if ( shadowSettings.
renderShadows() && selectedLight >= 0 && selectedLight < directionalLightSources.count() )
1082 void Qgs3DMapScene::onDebugShadowMapSettingsChanged()
1088 void Qgs3DMapScene::onDebugDepthMapSettingsChanged()
1094 void Qgs3DMapScene::onDebugOverlayEnabledChanged()
1100 void Qgs3DMapScene::onEyeDomeShadingSettingsChanged()
1110 void Qgs3DMapScene::onCameraMovementSpeedChanged()
1115 void Qgs3DMapScene::onCameraNavigationModeChanged()
1122 QVector<QString> notParsedLayers;
1132 for (
auto it = mLayerEntities.constBegin(); it != mLayerEntities.constEnd(); ++it )
1135 Qt3DCore::QEntity *rootEntity = it.value();
1137 switch ( layerType )
1141 notParsedLayers.push_back( layer->
name() );
1150 notParsedLayers.push_back( layer->
name() );
1160 if ( !notParsedLayers.empty() )
1162 QString message = tr(
"The following layers were not exported:" ) +
"\n";
1163 for (
const QString &layerName : notParsedLayers )
1164 message += layerName +
"\n";
1171 QVector<const QgsChunkNode *> chunks;
1172 if ( !mLayerEntities.contains( layer ) )
return chunks;
1173 if ( QgsChunkedEntity *
c = qobject_cast<QgsChunkedEntity *>( mLayerEntities[ layer ] ) )
1175 for ( QgsChunkNode *n :
c->activeNodes() )
1176 chunks.push_back( n );
1186 for (
QgsMapLayer *layer : mLayerEntities.keys() )
1188 Qt3DCore::QEntity *layerEntity = mLayerEntities[ layer ];
1189 QgsChunkedEntity *
c = qobject_cast<QgsChunkedEntity *>( layerEntity );
1192 QgsChunkNode *chunkNode =
c->rootNode();
1193 QgsAABB bbox = chunkNode->bbox();
1202 QgsRectangle terrainExtent = terrainGenerator->extent();
1215 mEntityRotationCenter =
new Qt3DCore::QEntity;
1217 Qt3DCore::QTransform *trCameraViewCenter =
new Qt3DCore::QTransform;
1218 mEntityRotationCenter->addComponent( trCameraViewCenter );
1219 Qt3DExtras::QPhongMaterial *materialCameraViewCenter =
new Qt3DExtras::QPhongMaterial;
1220 materialCameraViewCenter->setAmbient( Qt::blue );
1221 mEntityRotationCenter->addComponent( materialCameraViewCenter );
1222 Qt3DExtras::QSphereMesh *rendererCameraViewCenter =
new Qt3DExtras::QSphereMesh;
1223 rendererCameraViewCenter->setRadius( 10 );
1224 mEntityRotationCenter->addComponent( rendererCameraViewCenter );
1225 mEntityRotationCenter->setEnabled(
true );
1226 mEntityRotationCenter->setParent(
this );
1230 trCameraViewCenter->setTranslation( center );
1241 void Qgs3DMapScene::on3DAxisSettingsChanged()
1247 m3DAxis =
new Qgs3DAxis(
static_cast<Qt3DExtras::Qt3DWindow *
>(
engine->window() ),