Skip to content

Commit 6884053

Browse files
committed
Capturing of complete scene images upon request
1 parent 6448000 commit 6884053

File tree

8 files changed

+121
-19
lines changed

8 files changed

+121
-19
lines changed

src/3d/qgs3dmapscene.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,8 @@ void Qgs3DMapScene::onCameraChanged()
198198
entity->update( _sceneState( mCameraController ) );
199199
}
200200

201+
updateSceneState();
202+
201203
// Update near and far plane from the terrain.
202204
// this needs to be done with great care as we have kind of circular dependency here:
203205
// active nodes are culled based on the current frustum (which involves near + far plane)
@@ -279,6 +281,8 @@ void Qgs3DMapScene::onFrameTriggered( float dt )
279281
entity->update( _sceneState( mCameraController ) );
280282
}
281283
}
284+
285+
updateSceneState();
282286
}
283287

284288
void Qgs3DMapScene::createTerrain()
@@ -296,6 +300,7 @@ void Qgs3DMapScene::createTerrain()
296300
// defer re-creation of terrain: there may be multiple invocations of this slot, so create the new entity just once
297301
QTimer::singleShot( 0, this, &Qgs3DMapScene::createTerrainDeferred );
298302
mTerrainUpdateScheduled = true;
303+
setSceneState( Updating );
299304
}
300305
}
301306

@@ -453,3 +458,31 @@ void Qgs3DMapScene::addCameraViewCenterEntity( Qt3DRender::QCamera *camera )
453458
mEntityCameraViewCenter->setEnabled( mMap.showCameraViewCenter() );
454459
} );
455460
}
461+
462+
void Qgs3DMapScene::setSceneState( Qgs3DMapScene::SceneState state )
463+
{
464+
if ( mSceneState == state )
465+
return;
466+
mSceneState = state;
467+
emit sceneStateChanged();
468+
}
469+
470+
void Qgs3DMapScene::updateSceneState()
471+
{
472+
if ( mTerrainUpdateScheduled )
473+
{
474+
setSceneState( Updating );
475+
return;
476+
}
477+
478+
Q_FOREACH ( QgsChunkedEntity *entity, mChunkEntities )
479+
{
480+
if ( entity->isEnabled() && entity->pendingJobsCount() > 0 )
481+
{
482+
setSceneState( Updating );
483+
return;
484+
}
485+
}
486+
487+
setSceneState( Ready );
488+
}

src/3d/qgs3dmapscene.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,22 @@ class _3D_EXPORT Qgs3DMapScene : public Qt3DCore::QEntity
6666
//! Returns number of pending jobs of the terrain entity
6767
int terrainPendingJobsCount() const;
6868

69+
enum SceneState
70+
{
71+
Ready, //!< The scene is fully loaded/updated
72+
Updating, //!< The scene is still being loaded/updated
73+
};
74+
75+
//! Returns the current state of the scene
76+
SceneState sceneState() const { return mSceneState; }
77+
6978
signals:
7079
//! Emitted when the current terrain entity is replaced by a new one
7180
void terrainEntityChanged();
7281
//! Emitted when the number of terrain's pending jobs changes
7382
void terrainPendingJobsCountChanged();
83+
//! Emitted when the scene's state has changed
84+
void sceneStateChanged();
7485

7586
private slots:
7687
void onCameraChanged();
@@ -85,6 +96,8 @@ class _3D_EXPORT Qgs3DMapScene : public Qt3DCore::QEntity
8596
void addLayerEntity( QgsMapLayer *layer );
8697
void removeLayerEntity( QgsMapLayer *layer );
8798
void addCameraViewCenterEntity( Qt3DRender::QCamera *camera );
99+
void setSceneState( SceneState state );
100+
void updateSceneState();
88101

89102
private:
90103
const Qgs3DMapSettings &mMap;
@@ -99,6 +112,7 @@ class _3D_EXPORT Qgs3DMapScene : public Qt3DCore::QEntity
99112
//! Keeps track of entities that belong to a particular layer
100113
QMap<QgsMapLayer *, Qt3DCore::QEntity *> mLayerEntities;
101114
bool mTerrainUpdateScheduled = false;
115+
SceneState mSceneState = Ready;
102116
};
103117

104118
#endif // QGS3DMAPSCENE_H

src/3d/qgs3dutils.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,53 @@
2323
#include "qgsabstractgeometry.h"
2424
#include "qgsvectorlayer.h"
2525

26+
#include "qgs3dmapscene.h"
27+
#include "qgsabstract3dengine.h"
2628
#include "qgsterraingenerator.h"
2729

2830

31+
QImage Qgs3DUtils::captureSceneImage( QgsAbstract3DEngine &engine, Qgs3DMapScene *scene )
32+
{
33+
QImage resImage;
34+
QEventLoop evLoop;
35+
36+
auto requestImageFcn = [&engine, scene]
37+
{
38+
if ( scene->sceneState() == Qgs3DMapScene::Ready )
39+
{
40+
qDebug() << "loaded - requesting image";
41+
engine.requestCaptureImage();
42+
}
43+
};
44+
45+
auto saveImageFcn = [&engine, &evLoop, &resImage]( const QImage & img )
46+
{
47+
resImage = img;
48+
evLoop.quit();
49+
};
50+
51+
QMetaObject::Connection conn1 = QObject::connect( &engine, &QgsAbstract3DEngine::imageCaptured, saveImageFcn );
52+
QMetaObject::Connection conn2;
53+
54+
if ( scene->sceneState() == Qgs3DMapScene::Ready )
55+
{
56+
requestImageFcn();
57+
}
58+
else
59+
{
60+
// first wait until scene is loaded
61+
conn2 = QObject::connect( scene, &Qgs3DMapScene::sceneStateChanged, requestImageFcn );
62+
}
63+
64+
evLoop.exec();
65+
66+
QObject::disconnect( conn1 );
67+
if ( conn2 )
68+
QObject::disconnect( conn2 );
69+
70+
return resImage;
71+
}
72+
2973

3074
int Qgs3DUtils::maxZoomLevel( double tile0width, double tileResolution, double maxError )
3175
{

src/3d/qgs3dutils.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
class QgsLineString;
2020
class QgsPolygon;
2121

22+
class QgsAbstract3DEngine;
23+
class Qgs3DMapScene;
24+
2225
#include "qgs3dmapsettings.h"
2326
#include "qgsaabb.h"
2427

@@ -50,6 +53,13 @@ class _3D_EXPORT Qgs3DUtils
5053
{
5154
public:
5255

56+
/**
57+
* Captures image of the current 3D scene of a 3D engine. The function waits
58+
* until the scene is not fully loaded/updated before capturing the image.
59+
* \since QGIS 3.4
60+
*/
61+
static QImage captureSceneImage( QgsAbstract3DEngine &engine, Qgs3DMapScene *scene );
62+
5363
/**
5464
* Calculates the highest needed zoom level for tiles in quad-tree given width of the base tile (zoom level 0)
5565
* in map units, resolution of the tile (e.g. tile's texture width) and desired maximum error in map units.

src/3d/qgsabstract3dengine.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ class _3D_EXPORT QgsAbstract3DEngine : public QObject
4444
virtual Qt3DRender::QCamera *camera() = 0;
4545
virtual QSize size() const = 0;
4646

47+
virtual void requestCaptureImage() = 0;
48+
4749
signals:
4850
void imageCaptured( const QImage &image );
4951
};

src/3d/qgsoffscreen3dengine.cpp

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -82,16 +82,19 @@ QgsOffscreen3DEngine::QgsOffscreen3DEngine()
8282
// Set the root entity of the engine. This causes the engine to begin running.
8383
mAspectEngine->setRootEntity( Qt3DCore::QEntityPtr( mRoot ) );
8484

85-
86-
// start requesting renders
87-
requestRenderCapture();
8885
}
8986

9087
void QgsOffscreen3DEngine::setClearColor( const QColor &color )
9188
{
9289
mClearBuffers->setClearColor( color );
9390
}
9491

92+
void QgsOffscreen3DEngine::setFrustumCullingEnabled( bool enabled )
93+
{
94+
// TODO
95+
Q_UNUSED( enabled );
96+
}
97+
9598
void QgsOffscreen3DEngine::createRenderTarget()
9699
{
97100
mTextureTarget = new Qt3DRender::QRenderTarget;
@@ -195,23 +198,19 @@ QSize QgsOffscreen3DEngine::size() const
195198
return mSize;
196199
}
197200

198-
//static int iii = 0;
199-
200-
void QgsOffscreen3DEngine::requestRenderCapture()
201+
void QgsOffscreen3DEngine::requestCaptureImage()
201202
{
202-
delete mReply;
203+
if ( mReply )
204+
{
205+
qDebug() << "already having a pending capture, skipping";
206+
return;
207+
}
203208
mReply = mRenderCapture->requestCapture();
204209
connect( mReply, &Qt3DRender::QRenderCaptureReply::completed, this, [ = ]
205210
{
206211
QImage image = mReply->image();
207-
/*
208-
iii++;
209-
qDebug() << "got image!" << iii;
210-
image.save( QString( "/tmp/3d_%1.jpg" ).arg( iii ), "jpg" );
211-
*/
212+
mReply->deleteLater();
213+
mReply = nullptr;
212214
emit imageCaptured( image );
213-
214-
//if (!end)
215-
requestRenderCapture();
216215
} );
217216
}

src/3d/qgsoffscreen3dengine.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,19 @@ class _3D_EXPORT QgsOffscreen3DEngine : public QgsAbstract3DEngine
4141
QgsOffscreen3DEngine();
4242

4343
void setClearColor( const QColor &color ) override;
44-
//void setFrustumCullingEnabled( bool enabled ) override;
44+
void setFrustumCullingEnabled( bool enabled ) override;
4545
void setRootEntity( Qt3DCore::QEntity *root ) override;
4646

4747
Qt3DRender::QRenderSettings *renderSettings() override;
4848
Qt3DRender::QCamera *camera() override;
4949
QSize size() const override;
5050

51+
void requestCaptureImage() override;
52+
5153
private:
5254
void createRenderTarget();
5355
void createFrameGraph();
5456

55-
void requestRenderCapture();
56-
5757
private:
5858

5959
QSize mSize;

src/3d/qgswindow3dengine.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class _3D_EXPORT QgsWindow3DEngine : public QgsAbstract3DEngine
4040

4141
QWindow *window();
4242

43-
void requestCaptureImage();
43+
void requestCaptureImage() override;
4444

4545
void setClearColor( const QColor &color ) override;
4646
void setFrustumCullingEnabled( bool enabled ) override;

0 commit comments

Comments
 (0)