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/QPointLight>
25 #include <Qt3DRender/QRenderSettings>
26 #include <Qt3DRender/QSceneLoader>
27 #include <Qt3DExtras/QForwardRenderer>
28 #include <Qt3DExtras/QPhongMaterial>
29 #include <Qt3DExtras/QSkyboxEntity>
30 #include <Qt3DExtras/QSphereMesh>
31 #include <Qt3DLogic/QFrameAction>
33 #include <QOpenGLContext>
34 #include <QOpenGLFunctions>
66 onBackgroundColorChanged();
72 #if QT_VERSION >= 0x050900
74 mEngine->
renderSettings()->pickingSettings()->setPickMethod( Qt3DRender::QPickingSettings::TrianglePicking );
77 QRect viewportRect( QPoint( 0, 0 ), mEngine->
size() );
80 float aspectRatio = ( float )viewportRect.width() / viewportRect.height();
81 mEngine->
camera()->lens()->setPerspectiveProjection( mMap.
fieldOfView(), aspectRatio, 10.f, 10000.0f );
83 mFrameAction =
new Qt3DLogic::QFrameAction();
84 connect( mFrameAction, &Qt3DLogic::QFrameAction::triggered,
85 this, &Qgs3DMapScene::onFrameTriggered );
86 addComponent( mFrameAction );
94 addCameraViewCenterEntity( mEngine->
camera() );
98 createTerrainDeferred();
111 onRenderersChanged();
119 ChunkedEntity *testChunkEntity =
new ChunkedEntity( AABB( -500, 0, -500, 500, 100, 500 ), 2.f, 3.f, 7,
new TestChunkLoaderFactory );
120 testChunkEntity->setEnabled(
false );
121 testChunkEntity->setParent(
this );
122 chunkEntities << testChunkEntity;
133 Qt3DCore::QEntity *loaderEntity =
new Qt3DCore::QEntity;
134 Qt3DRender::QSceneLoader *loader =
new Qt3DRender::QSceneLoader;
135 loader->setSource( QUrl(
"file:///home/martin/Downloads/LowPolyModels/tree.dae" ) );
136 loaderEntity->addComponent( loader );
137 loaderEntity->setParent(
this );
141 Qt3DCore::QEntity *meshEntity =
new Qt3DCore::QEntity;
142 Qt3DRender::QMesh *mesh =
new Qt3DRender::QMesh;
143 mesh->setSource( QUrl(
"file:///home/martin/Downloads/LowPolyModels/tree.obj" ) );
144 meshEntity->addComponent( mesh );
145 Qt3DExtras::QPhongMaterial *material =
new Qt3DExtras::QPhongMaterial;
146 material->setAmbient( Qt::red );
147 meshEntity->addComponent( material );
148 Qt3DCore::QTransform *meshTransform =
new Qt3DCore::QTransform;
149 meshTransform->setScale( 1 );
150 meshEntity->addComponent( meshTransform );
151 meshEntity->setParent(
this );
156 Qt3DExtras::QSkyboxEntity *skybox =
new Qt3DExtras::QSkyboxEntity;
159 skybox->setParent(
this );
177 float side = std::max( extent.
width(), extent.
height() );
183 return mTerrain ? mTerrain->pendingJobsCount() : 0;
189 for ( QgsChunkedEntity *entity : qgis::as_const( mChunkEntities ) )
190 count += entity->pendingJobsCount();
196 if ( mPickHandlers.isEmpty() )
199 for ( Qt3DCore::QEntity *entity : mLayerEntities.values() )
201 if ( QgsChunkedEntity *chunkedEntity = qobject_cast<QgsChunkedEntity *>( entity ) )
202 chunkedEntity->setPickingEnabled(
true );
206 mPickHandlers.append( pickHandler );
211 mPickHandlers.removeOne( pickHandler );
213 if ( mPickHandlers.isEmpty() )
216 for ( Qt3DCore::QEntity *entity : mLayerEntities.values() )
218 if ( QgsChunkedEntity *chunkedEntity = qobject_cast<QgsChunkedEntity *>( entity ) )
219 chunkedEntity->setPickingEnabled(
false );
224 void Qgs3DMapScene::onLayerEntityPickedObject( Qt3DRender::QPickEvent *pickEvent,
QgsFeatureId fid )
226 QgsMapLayer *layer = mLayerEntities.key( qobject_cast<QgsChunkedEntity *>( sender() ) );
236 pickHandler->handlePickOnVectorLayer( vlayer, fid, pickEvent->worldIntersection(), pickEvent );
243 Qt3DRender::QCamera *camera = mCameraController->
camera();
244 float fov = camera->fieldOfView();
245 QRect rect = mCameraController->
viewport();
246 float screenSizePx = std::max( rect.width(), rect.height() );
250 float frustumWidthAtDistance = 2 * distance * tan( fov / 2 );
251 float err = frustumWidthAtDistance * epsilon / screenSizePx;
257 Qt3DRender::QCamera *camera = cameraController->
camera();
258 QgsChunkedEntity::SceneState state;
259 state.cameraFov = camera->fieldOfView();
260 state.cameraPos = camera->position();
261 QRect rect = cameraController->
viewport();
262 state.screenSizePx = std::max( rect.width(), rect.height() );
263 state.viewProjectionMatrix = camera->projectionMatrix() * camera->viewMatrix();
267 void Qgs3DMapScene::onCameraChanged()
270 bool changedCameraPlanes = updateCameraNearFarPlanes();
272 if ( changedCameraPlanes )
277 updateCameraNearFarPlanes();
281 void Qgs3DMapScene::updateScene()
283 QgsEventTracing::addEvent( QgsEventTracing::Instant, QStringLiteral(
"3D" ), QStringLiteral(
"Update Scene" ) );
285 for ( QgsChunkedEntity *entity : qgis::as_const( mChunkEntities ) )
287 if ( entity->isEnabled() )
288 entity->update(
_sceneState( mCameraController ) );
294 bool Qgs3DMapScene::updateCameraNearFarPlanes()
311 QMatrix4x4 viewMatrix = camera->viewMatrix();
315 QList<QgsChunkNode *> activeNodes = mTerrain->activeNodes();
320 if ( activeNodes.isEmpty() )
321 activeNodes << mTerrain->rootNode();
323 Q_FOREACH ( QgsChunkNode *node, activeNodes )
328 for (
int i = 0; i < 8; ++i )
330 QVector4D p( ( ( i >> 0 ) & 1 ) ? bbox.
xMin : bbox.
xMax,
331 ( ( i >> 1 ) & 1 ) ? bbox.
yMin : bbox.
yMax,
332 ( ( i >> 2 ) & 1 ) ? bbox.
zMin : bbox.
zMax, 1 );
333 QVector4D pc = viewMatrix * p;
345 if ( fnear == 1e9 && ffar == 0 )
349 qDebug() <<
"oops... this should not happen! couldn't determine near/far plane. defaulting to 1...1e9";
355 float newFar = ffar * 2;
356 float newNear = fnear / 2;
359 camera->setFarPlane( newFar );
360 camera->setNearPlane( newNear );
365 qDebug() <<
"no terrain - not setting near/far plane";
370 void Qgs3DMapScene::onFrameTriggered(
float dt )
374 for ( QgsChunkedEntity *entity : qgis::as_const( mChunkEntities ) )
376 if ( entity->isEnabled() && entity->needsUpdate() )
378 qDebug() <<
"need for update";
379 entity->update(
_sceneState( mCameraController ) );
386 void Qgs3DMapScene::createTerrain()
390 mChunkEntities.removeOne( mTerrain );
392 mTerrain->deleteLater();
398 if ( !mTerrainUpdateScheduled )
401 QTimer::singleShot( 0,
this, &Qgs3DMapScene::createTerrainDeferred );
402 mTerrainUpdateScheduled =
true;
407 void Qgs3DMapScene::createTerrainDeferred()
412 mTerrain =
new QgsTerrainEntity( maxZoomLevel, mMap );
414 mTerrain->setParent(
this );
417 mTerrain->setShowBoundingBoxes(
true );
421 mChunkEntities << mTerrain;
429 removeLayerEntity( layer );
432 addLayerEntity( layer );
435 mTerrainUpdateScheduled =
false;
443 void Qgs3DMapScene::onBackgroundColorChanged()
449 void Qgs3DMapScene::updateLights()
451 for ( Qt3DCore::QEntity *entity : qgis::as_const( mLightEntities ) )
452 entity->deleteLater();
453 mLightEntities.clear();
458 Qt3DCore::QEntity *lightEntity =
new Qt3DCore::QEntity;
459 Qt3DCore::QTransform *lightTransform =
new Qt3DCore::QTransform;
460 lightTransform->setTranslation( QVector3D( pointLightSettings.position().x(),
461 pointLightSettings.position().y(),
462 pointLightSettings.position().z() ) );
464 Qt3DRender::QPointLight *light =
new Qt3DRender::QPointLight;
465 light->setColor( pointLightSettings.color() );
466 light->setIntensity( pointLightSettings.intensity() );
468 light->setConstantAttenuation( pointLightSettings.constantAttenuation() );
469 light->setLinearAttenuation( pointLightSettings.linearAttenuation() );
470 light->setQuadraticAttenuation( pointLightSettings.quadraticAttenuation() );
472 lightEntity->addComponent( light );
473 lightEntity->addComponent( lightTransform );
474 lightEntity->setParent(
this );
475 mLightEntities << lightEntity;
479 void Qgs3DMapScene::updateCameraLens()
485 void Qgs3DMapScene::onRenderersChanged()
488 qDeleteAll( mRenderersEntities );
489 mRenderersEntities.clear();
492 const QList<QgsAbstract3DRenderer *> renderers = mMap.
renderers();
495 Qt3DCore::QEntity *newEntity = renderer->createEntity( mMap );
498 newEntity->setParent(
this );
499 finalizeNewEntity( newEntity );
500 mRenderersEntities[renderer] = newEntity;
505 void Qgs3DMapScene::onLayerRenderer3DChanged()
507 QgsMapLayer *layer = qobject_cast<QgsMapLayer *>( sender() );
511 removeLayerEntity( layer );
514 addLayerEntity( layer );
517 void Qgs3DMapScene::onLayersChanged()
519 QSet<QgsMapLayer *> layersBefore = qgis::listToSet( mLayerEntities.keys() );
520 QList<QgsMapLayer *> layersAdded;
523 if ( !layersBefore.contains( layer ) )
525 layersAdded << layer;
529 layersBefore.remove( layer );
536 removeLayerEntity( layer );
541 addLayerEntity( layer );
547 for (
auto layer : mLayerEntities.keys() )
551 removeLayerEntity( layer );
552 addLayerEntity( layer );
557 void Qgs3DMapScene::addLayerEntity(
QgsMapLayer *layer )
559 bool needsSceneUpdate =
false;
568 ( renderer->
type() == QLatin1String(
"vector" ) || renderer->
type() == QLatin1String(
"rulebased" ) ) )
584 Qt3DCore::QEntity *newEntity = renderer->
createEntity( mMap );
587 newEntity->setParent(
this );
588 mLayerEntities.insert( layer, newEntity );
590 finalizeNewEntity( newEntity );
592 if ( QgsChunkedEntity *chunkedNewEntity = qobject_cast<QgsChunkedEntity *>( newEntity ) )
594 mChunkEntities.append( chunkedNewEntity );
595 needsSceneUpdate =
true;
597 chunkedNewEntity->setPickingEnabled( !mPickHandlers.isEmpty() );
598 connect( chunkedNewEntity, &QgsChunkedEntity::pickedObject,
this, &Qgs3DMapScene::onLayerEntityPickedObject );
600 connect( chunkedNewEntity, &QgsChunkedEntity::newEntityCreated,
this, [
this]( Qt3DCore::QEntity * entity )
602 finalizeNewEntity( entity );
610 if ( needsSceneUpdate )
628 void Qgs3DMapScene::removeLayerEntity(
QgsMapLayer *layer )
630 Qt3DCore::QEntity *entity = mLayerEntities.take( layer );
632 if ( QgsChunkedEntity *chunkedEntity = qobject_cast<QgsChunkedEntity *>( entity ) )
634 mChunkEntities.removeOne( chunkedEntity );
638 entity->deleteLater();
654 void Qgs3DMapScene::finalizeNewEntity( Qt3DCore::QEntity *newEntity )
658 for ( QgsLineMaterial *lm : newEntity->findChildren<QgsLineMaterial *>() )
662 lm->setViewportSize( mCameraController->
viewport().size() );
672 bm->setViewportSize( mCameraController->
viewport().size() );
675 bm->setViewportSize( mCameraController->
viewport().size() );
679 int Qgs3DMapScene::maximumTextureSize()
const
681 QSurface *surface = mEngine->
surface();
682 QOpenGLContext context;
684 context.makeCurrent( surface );
685 QOpenGLFunctions openglFunctions( &context );
687 openglFunctions.glGetIntegerv( GL_MAX_TEXTURE_SIZE, &size );
691 void Qgs3DMapScene::addCameraViewCenterEntity( Qt3DRender::QCamera *camera )
693 mEntityCameraViewCenter =
new Qt3DCore::QEntity;
695 Qt3DCore::QTransform *trCameraViewCenter =
new Qt3DCore::QTransform;
696 mEntityCameraViewCenter->addComponent( trCameraViewCenter );
697 connect( camera, &Qt3DRender::QCamera::viewCenterChanged,
this, [trCameraViewCenter, camera]
699 trCameraViewCenter->setTranslation( camera->viewCenter() );
702 Qt3DExtras::QPhongMaterial *materialCameraViewCenter =
new Qt3DExtras::QPhongMaterial;
703 materialCameraViewCenter->setAmbient( Qt::red );
704 mEntityCameraViewCenter->addComponent( materialCameraViewCenter );
706 Qt3DExtras::QSphereMesh *rendererCameraViewCenter =
new Qt3DExtras::QSphereMesh;
707 rendererCameraViewCenter->setRadius( 10 );
708 mEntityCameraViewCenter->addComponent( rendererCameraViewCenter );
711 mEntityCameraViewCenter->setParent(
this );
721 if ( mSceneState == state )
727 void Qgs3DMapScene::updateSceneState()
729 if ( mTerrainUpdateScheduled )
735 for ( QgsChunkedEntity *entity : qgis::as_const( mChunkEntities ) )
737 if ( entity->isEnabled() && entity->pendingJobsCount() > 0 )
744 setSceneState(
Ready );