31 #include <Qt3DCore/QTransform>
32 #include <Qt3DRender/QGeometryRenderer>
33 #include <Qt3DRender/QObjectPicker>
39 class TerrainMapUpdateJobFactory :
public QgsChunkQueueJobFactory
42 TerrainMapUpdateJobFactory( QgsTerrainTextureGenerator *textureGenerator )
43 : mTextureGenerator( textureGenerator )
47 QgsChunkQueueJob *createJob( QgsChunkNode *chunk )
override
49 return new TerrainMapUpdateJob( mTextureGenerator, chunk );
53 QgsTerrainTextureGenerator *mTextureGenerator =
nullptr;
60 QgsTerrainEntity::QgsTerrainEntity(
const Qgs3DMapSettings &map, Qt3DCore::QNode *parent )
61 : QgsChunkedEntity( map.maxTerrainScreenError(), map.terrainGenerator(), false, std::numeric_limits<int>::max(), parent )
75 connectToLayersRepaintRequest();
79 mTextureGenerator =
new QgsTerrainTextureGenerator( map );
81 mUpdateJobFactory.reset(
new TerrainMapUpdateJobFactory( mTextureGenerator ) );
83 mTerrainPicker =
new Qt3DRender::QObjectPicker;
86 addComponent( mTerrainPicker );
88 mTerrainTransform =
new Qt3DCore::QTransform;
89 mTerrainTransform->setScale( 1.0f );
91 addComponent( mTerrainTransform );
94 QgsTerrainEntity::~QgsTerrainEntity()
99 delete mTextureGenerator;
100 delete mTerrainToMapTransform;
103 bool QgsTerrainEntity::rayIntersection(
const QgsRayCastingUtils::Ray3D &ray, QVector3D &intersectionPoint )
113 QList<QgsChunkNode *> lst = activeNodes();
114 for ( QgsChunkNode *n : lst )
116 if ( n->entity() && ( minDist < 0 || n->bbox().distanceFromPoint( ray.origin() ) < minDist ) && QgsRayCastingUtils::rayBoxIntersection( ray, n->bbox() ) )
118 Qt3DRender::QGeometryRenderer *rend = n->entity()->findChild<Qt3DRender::QGeometryRenderer *>();
119 Qt3DRender::QGeometry *geom = rend->geometry();
120 DemTerrainTileGeometry *demGeom =
static_cast<DemTerrainTileGeometry *
>( geom );
121 Qt3DCore::QTransform *tr = n->entity()->findChild<Qt3DCore::QTransform *>();
122 QVector3D nodeIntPoint;
123 if ( demGeom->rayIntersection( ray, tr->matrix(), nodeIntPoint ) )
125 float dist = ( ray.origin() - intersectionPoint ).length();
126 if ( minDist < 0 || dist < minDist )
129 intersectionPoint = nodeIntPoint;
138 void QgsTerrainEntity::onShowBoundingBoxesChanged()
140 setShowBoundingBoxes( mMap.showTerrainBoundingBoxes() );
144 void QgsTerrainEntity::invalidateMapImages()
146 QgsEventTracing::addEvent( QgsEventTracing::Instant, QStringLiteral(
"3D" ), QStringLiteral(
"Invalidate textures" ) );
150 updateNodes( mActiveNodes, mUpdateJobFactory.get() );
154 QList<QgsChunkNode *> inactiveNodes;
155 const QList<QgsChunkNode *> descendants = mRootNode->descendants();
156 for ( QgsChunkNode *node : descendants )
158 if ( !node->entity() )
160 if ( mActiveNodes.contains( node ) )
162 inactiveNodes << node;
165 updateNodes( inactiveNodes, mUpdateJobFactory.get() );
167 setNeedsUpdate(
true );
170 void QgsTerrainEntity::onLayersChanged()
172 connectToLayersRepaintRequest();
173 invalidateMapImages();
176 void QgsTerrainEntity::connectToLayersRepaintRequest()
178 for (
QgsMapLayer *layer : std::as_const( mLayers ) )
183 mLayers = mMap.layers();
185 for (
QgsMapLayer *layer : std::as_const( mLayers ) )
191 void QgsTerrainEntity::onTerrainElevationOffsetChanged(
float newOffset )
193 mTerrainTransform->setTranslation( QVector3D( 0.0f, newOffset, 0.0f ) );
196 float QgsTerrainEntity::terrainElevationOffset()
const
198 return mMap.terrainElevationOffset();
205 TerrainMapUpdateJob::TerrainMapUpdateJob( QgsTerrainTextureGenerator *textureGenerator, QgsChunkNode *node )
206 : QgsChunkQueueJob( node )
207 , mTextureGenerator( textureGenerator )
209 QgsTerrainTileEntity *entity = qobject_cast<QgsTerrainTileEntity *>( node->entity() );
210 connect( textureGenerator, &QgsTerrainTextureGenerator::tileReady,
this, &TerrainMapUpdateJob::onTileReady );
211 mJobId = textureGenerator->render( entity->textureImage()->imageExtent(), node->tileId(), entity->textureImage()->imageDebugText() );
214 void TerrainMapUpdateJob::cancel()
217 mTextureGenerator->cancelJob( mJobId );
221 void TerrainMapUpdateJob::onTileReady(
int jobId,
const QImage &image )
223 if ( mJobId == jobId )
225 QgsTerrainTileEntity *entity = qobject_cast<QgsTerrainTileEntity *>( mNode->entity() );
226 entity->textureImage()->setImage( image );