Skip to content

Commit

Permalink
Cache depth buffer average to improve performance
Browse files Browse the repository at this point in the history
Previously the average could be computed on every mouse move event. This
is a problem, since the loop can be slow, especially on debug builds
where nothing gets inlined.
  • Loading branch information
dvdkon committed Jan 23, 2025
1 parent 0bf42b8 commit ee6d434
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 8 deletions.
21 changes: 14 additions & 7 deletions src/3d/qgscameracontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,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 @@ -249,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 )
return mDepthBufferNonVoidAverage.data();

// 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 @@ -281,6 +285,8 @@ double QgsCameraController::sampleDepthBuffer( const QImage &buffer, int px, int
else
depth /= samplesCount;

mDepthBufferNonVoidAverage = depth;

return depth;
}

Expand Down Expand Up @@ -319,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 @@ -1026,6 +1032,7 @@ void QgsCameraController::depthBufferCaptured( const QImage &depthImage )
{
mDepthBufferImage = depthImage;
mDepthBufferIsReady = true;
mDepthBufferNonVoidAverage.setEnabled( false );

if ( mCurrentOperation == MouseOperation::ZoomWheel )
{
Expand Down
4 changes: 3 additions & 1 deletion src/3d/qgscameracontroller.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#define QGSCAMERACONTROLLER_H

#include "qgis_3d.h"
#include "qgsoptional.h"

#include <Qt3DCore/QEntity>
#include <Qt3DInput/QMouseEvent>
Expand Down Expand Up @@ -326,7 +327,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 +351,7 @@ class _3D_EXPORT QgsCameraController : public QObject

bool mDepthBufferIsReady = false;
QImage mDepthBufferImage;
QgsOptional<double> mDepthBufferNonVoidAverage;

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

Expand Down

0 comments on commit ee6d434

Please sign in to comment.