Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve 3D Map View movement performance #60246

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/3d/qgs3dmapscene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -334,8 +334,7 @@ void Qgs3DMapScene::updateScene( bool forceUpdate )
return;
}

if ( forceUpdate )
QgsEventTracing::addEvent( QgsEventTracing::Instant, QStringLiteral( "3D" ), QStringLiteral( "Update Scene" ) );
QgsEventTracing::ScopedEvent traceEvent( QStringLiteral( "3D" ), forceUpdate ? QStringLiteral( "Force update scene" ) : QStringLiteral( "Update scene" ) );

Qgs3DMapSceneEntity::SceneContext sceneContext;
Qt3DRender::QCamera *camera = mEngine->camera();
Expand Down Expand Up @@ -421,6 +420,8 @@ bool Qgs3DMapScene::updateCameraNearFarPlanes()

void Qgs3DMapScene::onFrameTriggered( float dt )
{
QgsEventTracing::addEvent( QgsEventTracing::EventType::Instant, QStringLiteral( "3D" ), QStringLiteral( "Frame begins" ) );

mCameraController->frameTriggered( dt );

updateScene();
Expand Down
30 changes: 23 additions & 7 deletions src/3d/qgs3dutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include <Qt3DRender/QRenderSettings>
#include <QOpenGLContext>
#include <QOpenGLFunctions>
#include <qframeaction.h>


#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
Expand All @@ -58,6 +59,17 @@ typedef Qt3DCore::QBuffer Qt3DQBuffer;
// declared here as Qgs3DTypes has no cpp file
const char *Qgs3DTypes::PROP_NAME_3D_RENDERER_FLAG = "PROP_NAME_3D_RENDERER_FLAG";

static void waitForFrame( Qgs3DMapScene *scene )
{
// Wait for at least one frame to render
Qt3DLogic::QFrameAction *frameAction = new Qt3DLogic::QFrameAction();
scene->addComponent( frameAction );
QEventLoop evLoop;
QObject::connect( frameAction, &Qt3DLogic::QFrameAction::triggered, &evLoop, &QEventLoop::quit );
evLoop.exec();
scene->removeComponent( frameAction );
}

QImage Qgs3DUtils::captureSceneImage( QgsAbstract3DEngine &engine, Qgs3DMapScene *scene )
{
QImage resImage;
Expand All @@ -66,13 +78,7 @@ QImage Qgs3DUtils::captureSceneImage( QgsAbstract3DEngine &engine, Qgs3DMapScene
// We need to change render policy to RenderPolicy::Always, since otherwise render capture node won't work
engine.renderSettings()->setRenderPolicy( Qt3DRender::QRenderSettings::RenderPolicy::Always );

auto requestImageFcn = [&engine, scene] {
if ( scene->sceneState() == Qgs3DMapScene::Ready )
{
engine.renderSettings()->setRenderPolicy( Qt3DRender::QRenderSettings::RenderPolicy::OnDemand );
engine.requestCaptureImage();
}
};
waitForFrame( scene );

auto saveImageFcn = [&evLoop, &resImage]( const QImage &img ) {
resImage = img;
Expand All @@ -82,6 +88,14 @@ QImage Qgs3DUtils::captureSceneImage( QgsAbstract3DEngine &engine, Qgs3DMapScene
const QMetaObject::Connection conn1 = QObject::connect( &engine, &QgsAbstract3DEngine::imageCaptured, saveImageFcn );
QMetaObject::Connection conn2;

auto requestImageFcn = [&engine, scene] {
if ( scene->sceneState() == Qgs3DMapScene::Ready )
{
engine.renderSettings()->setRenderPolicy( Qt3DRender::QRenderSettings::RenderPolicy::OnDemand );
engine.requestCaptureImage();
}
};

if ( scene->sceneState() == Qgs3DMapScene::Ready )
{
requestImageFcn();
Expand Down Expand Up @@ -110,6 +124,8 @@ QImage Qgs3DUtils::captureSceneDepthBuffer( QgsAbstract3DEngine &engine, Qgs3DMa
// We need to change render policy to RenderPolicy::Always, since otherwise render capture node won't work
engine.renderSettings()->setRenderPolicy( Qt3DRender::QRenderSettings::RenderPolicy::Always );

waitForFrame( scene );

auto requestImageFcn = [&engine, scene] {
if ( scene->sceneState() == Qgs3DMapScene::Ready )
{
Expand Down
32 changes: 24 additions & 8 deletions src/3d/qgscameracontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include "qgscameracontroller.h"
#include "moc_qgscameracontroller.cpp"
#include "qgseventtracing.h"
#include "qgsvector3d.h"
#include "qgswindow3dengine.h"
#include "qgs3dmapscene.h"
Expand Down Expand Up @@ -161,6 +162,12 @@ void QgsCameraController::zoomCameraAroundPivot( const QVector3D &oldCameraPosit
void QgsCameraController::frameTriggered( float dt )
{
Q_UNUSED( dt )

if ( mCameraChanged )
{
emit cameraChanged();
mCameraChanged = false;
}
}

void QgsCameraController::resetView( float distance )
Expand Down Expand Up @@ -233,7 +240,7 @@ void QgsCameraController::readXml( const QDomElement &elem )
setLookingAtPoint( QgsVector3D( x, elev, y ), dist, pitch, yaw );
}

double QgsCameraController::sampleDepthBuffer( const QImage &buffer, int px, int py )
double QgsCameraController::sampleDepthBuffer( int px, int py )
{
double depth = 1;

Expand All @@ -242,24 +249,28 @@ double QgsCameraController::sampleDepthBuffer( const QImage &buffer, int px, int
{
for ( int y = py - 3; y <= py + 3; ++y )
{
if ( buffer.valid( x, y ) )
if ( mDepthBufferImage.valid( x, y ) )
{
depth = std::min( depth, Qgs3DUtils::decodeDepth( buffer.pixel( x, y ) ) );
depth = std::min( depth, Qgs3DUtils::decodeDepth( mDepthBufferImage.pixel( x, y ) ) );
}
}
}

if ( depth < 1 )
return depth;

// Cache the computed depth, since averaging over all pixels can be expensive
if ( mDepthBufferNonVoidAverage != -1 )
return mDepthBufferNonVoidAverage;

// Returns the average of depth values that are not 1 (void area)
depth = 0;
int samplesCount = 0;
for ( int x = 0; x < buffer.width(); ++x )
for ( int x = 0; x < mDepthBufferImage.width(); ++x )
{
for ( int y = 0; y < buffer.height(); ++y )
for ( int y = 0; y < mDepthBufferImage.height(); ++y )
{
double d = Qgs3DUtils::decodeDepth( buffer.pixel( x, y ) );
double d = Qgs3DUtils::decodeDepth( mDepthBufferImage.pixel( x, y ) );
if ( d < 1 )
{
depth += d;
Expand All @@ -274,6 +285,8 @@ double QgsCameraController::sampleDepthBuffer( const QImage &buffer, int px, int
else
depth /= samplesCount;

mDepthBufferNonVoidAverage = depth;

return depth;
}

Expand All @@ -282,7 +295,7 @@ void QgsCameraController::updateCameraFromPose()
if ( mCamera )
mCameraPose.updateCamera( mCamera );

emit cameraChanged();
mCameraChanged = true;
}

void QgsCameraController::moveCameraPositionBy( const QVector3D &posDiff )
Expand All @@ -296,6 +309,8 @@ void QgsCameraController::onPositionChanged( Qt3DInput::QMouseEvent *mouse )
if ( !mInputHandlersEnabled )
return;

QgsEventTracing::ScopedEvent traceEvent( QStringLiteral( "3D" ), QStringLiteral( "QgsCameraController::onPositionChanged" ) );

switch ( mCameraNavigationMode )
{
case Qgis::NavigationMode::TerrainBased:
Expand All @@ -310,7 +325,7 @@ void QgsCameraController::onPositionChanged( Qt3DInput::QMouseEvent *mouse )

bool QgsCameraController::screenPointToWorldPos( QPoint position, Qt3DRender::QCamera *mCameraBefore, double &depth, QVector3D &worldPosition )
{
depth = sampleDepthBuffer( mDepthBufferImage, position.x(), position.y() );
depth = sampleDepthBuffer( position.x(), position.y() );
if ( !std::isfinite( depth ) )
{
QgsDebugMsgLevel( QStringLiteral( "screenPointToWorldPos: depth is NaN or Inf. This should not happen." ), 2 );
Expand Down Expand Up @@ -1017,6 +1032,7 @@ void QgsCameraController::depthBufferCaptured( const QImage &depthImage )
{
mDepthBufferImage = depthImage;
mDepthBufferIsReady = true;
mDepthBufferNonVoidAverage = -1;

if ( mCurrentOperation == MouseOperation::ZoomWheel )
{
Expand Down
8 changes: 7 additions & 1 deletion src/3d/qgscameracontroller.h
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ class _3D_EXPORT QgsCameraController : public QObject
* Returns the minimum depth value in the square [px - 3, px + 3] * [py - 3, py + 3]
* If the value is 1, the average depth of all non void pixels is returned instead.
*/
double sampleDepthBuffer( const QImage &buffer, int px, int py );
double sampleDepthBuffer( int px, int py );

#ifndef SIP_RUN
//! Converts screen point to world position
Expand All @@ -350,6 +350,9 @@ class _3D_EXPORT QgsCameraController : public QObject

bool mDepthBufferIsReady = false;
QImage mDepthBufferImage;
// -1 when unset
// TODO: Change to std::optional<double>
double mDepthBufferNonVoidAverage;

std::unique_ptr<Qt3DRender::QCamera> mCameraBefore;

Expand Down Expand Up @@ -385,6 +388,9 @@ class _3D_EXPORT QgsCameraController : public QObject
// 3D world's origin in map coordinates
QgsVector3D mOrigin;

//! Did camera change since last frame? Need to know if we should emit cameraChanged().
bool mCameraChanged = false;

// To test the cameracontroller
friend class TestQgs3DRendering;
friend class TestQgs3DCameraController;
Expand Down
Loading