Skip to content
Permalink
Browse files

Capturing of complete scene images upon request

  • Loading branch information
wonder-sk committed Jul 18, 2018
1 parent 6448000 commit 688405343c78420938551d1f9a1df1780b372093
@@ -198,6 +198,8 @@ void Qgs3DMapScene::onCameraChanged()
entity->update( _sceneState( mCameraController ) );
}

updateSceneState();

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

updateSceneState();
}

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

@@ -453,3 +458,31 @@ void Qgs3DMapScene::addCameraViewCenterEntity( Qt3DRender::QCamera *camera )
mEntityCameraViewCenter->setEnabled( mMap.showCameraViewCenter() );
} );
}

void Qgs3DMapScene::setSceneState( Qgs3DMapScene::SceneState state )
{
if ( mSceneState == state )
return;
mSceneState = state;
emit sceneStateChanged();
}

void Qgs3DMapScene::updateSceneState()
{
if ( mTerrainUpdateScheduled )
{
setSceneState( Updating );
return;
}

Q_FOREACH ( QgsChunkedEntity *entity, mChunkEntities )
{
if ( entity->isEnabled() && entity->pendingJobsCount() > 0 )
{
setSceneState( Updating );
return;
}
}

setSceneState( Ready );
}
@@ -66,11 +66,22 @@ class _3D_EXPORT Qgs3DMapScene : public Qt3DCore::QEntity
//! Returns number of pending jobs of the terrain entity
int terrainPendingJobsCount() const;

enum SceneState
{
Ready, //!< The scene is fully loaded/updated
Updating, //!< The scene is still being loaded/updated
};

//! Returns the current state of the scene
SceneState sceneState() const { return mSceneState; }

signals:
//! Emitted when the current terrain entity is replaced by a new one
void terrainEntityChanged();
//! Emitted when the number of terrain's pending jobs changes
void terrainPendingJobsCountChanged();
//! Emitted when the scene's state has changed
void sceneStateChanged();

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

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

#endif // QGS3DMAPSCENE_H
@@ -23,9 +23,53 @@
#include "qgsabstractgeometry.h"
#include "qgsvectorlayer.h"

#include "qgs3dmapscene.h"
#include "qgsabstract3dengine.h"
#include "qgsterraingenerator.h"


QImage Qgs3DUtils::captureSceneImage( QgsAbstract3DEngine &engine, Qgs3DMapScene *scene )
{
QImage resImage;
QEventLoop evLoop;

auto requestImageFcn = [&engine, scene]
{
if ( scene->sceneState() == Qgs3DMapScene::Ready )
{
qDebug() << "loaded - requesting image";
engine.requestCaptureImage();
}
};

auto saveImageFcn = [&engine, &evLoop, &resImage]( const QImage & img )
{
resImage = img;
evLoop.quit();
};

QMetaObject::Connection conn1 = QObject::connect( &engine, &QgsAbstract3DEngine::imageCaptured, saveImageFcn );
QMetaObject::Connection conn2;

if ( scene->sceneState() == Qgs3DMapScene::Ready )
{
requestImageFcn();
}
else
{
// first wait until scene is loaded
conn2 = QObject::connect( scene, &Qgs3DMapScene::sceneStateChanged, requestImageFcn );
}

evLoop.exec();

QObject::disconnect( conn1 );
if ( conn2 )
QObject::disconnect( conn2 );

return resImage;
}


int Qgs3DUtils::maxZoomLevel( double tile0width, double tileResolution, double maxError )
{
@@ -19,6 +19,9 @@
class QgsLineString;
class QgsPolygon;

class QgsAbstract3DEngine;
class Qgs3DMapScene;

#include "qgs3dmapsettings.h"
#include "qgsaabb.h"

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

/**
* Captures image of the current 3D scene of a 3D engine. The function waits
* until the scene is not fully loaded/updated before capturing the image.
* \since QGIS 3.4
*/
static QImage captureSceneImage( QgsAbstract3DEngine &engine, Qgs3DMapScene *scene );

/**
* Calculates the highest needed zoom level for tiles in quad-tree given width of the base tile (zoom level 0)
* in map units, resolution of the tile (e.g. tile's texture width) and desired maximum error in map units.
@@ -44,6 +44,8 @@ class _3D_EXPORT QgsAbstract3DEngine : public QObject
virtual Qt3DRender::QCamera *camera() = 0;
virtual QSize size() const = 0;

virtual void requestCaptureImage() = 0;

signals:
void imageCaptured( const QImage &image );
};
@@ -82,16 +82,19 @@ QgsOffscreen3DEngine::QgsOffscreen3DEngine()
// Set the root entity of the engine. This causes the engine to begin running.
mAspectEngine->setRootEntity( Qt3DCore::QEntityPtr( mRoot ) );


// start requesting renders
requestRenderCapture();
}

void QgsOffscreen3DEngine::setClearColor( const QColor &color )
{
mClearBuffers->setClearColor( color );
}

void QgsOffscreen3DEngine::setFrustumCullingEnabled( bool enabled )
{
// TODO
Q_UNUSED( enabled );
}

void QgsOffscreen3DEngine::createRenderTarget()
{
mTextureTarget = new Qt3DRender::QRenderTarget;
@@ -195,23 +198,19 @@ QSize QgsOffscreen3DEngine::size() const
return mSize;
}

//static int iii = 0;

void QgsOffscreen3DEngine::requestRenderCapture()
void QgsOffscreen3DEngine::requestCaptureImage()
{
delete mReply;
if ( mReply )
{
qDebug() << "already having a pending capture, skipping";
return;
}
mReply = mRenderCapture->requestCapture();
connect( mReply, &Qt3DRender::QRenderCaptureReply::completed, this, [ = ]
{
QImage image = mReply->image();
/*
iii++;
qDebug() << "got image!" << iii;
image.save( QString( "/tmp/3d_%1.jpg" ).arg( iii ), "jpg" );
*/
mReply->deleteLater();
mReply = nullptr;
emit imageCaptured( image );

//if (!end)
requestRenderCapture();
} );
}
@@ -41,19 +41,19 @@ class _3D_EXPORT QgsOffscreen3DEngine : public QgsAbstract3DEngine
QgsOffscreen3DEngine();

void setClearColor( const QColor &color ) override;
//void setFrustumCullingEnabled( bool enabled ) override;
void setFrustumCullingEnabled( bool enabled ) override;
void setRootEntity( Qt3DCore::QEntity *root ) override;

Qt3DRender::QRenderSettings *renderSettings() override;
Qt3DRender::QCamera *camera() override;
QSize size() const override;

void requestCaptureImage() override;

private:
void createRenderTarget();
void createFrameGraph();

void requestRenderCapture();

private:

QSize mSize;
@@ -40,7 +40,7 @@ class _3D_EXPORT QgsWindow3DEngine : public QgsAbstract3DEngine

QWindow *window();

void requestCaptureImage();
void requestCaptureImage() override;

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

0 comments on commit 6884053

Please sign in to comment.
You can’t perform that action at this time.