Skip to content

Commit

Permalink
QgsCameraController keeps pointer to 3d scene, gets rid of viewport.
Browse files Browse the repository at this point in the history
viewportChanged signals are replaced by engine::sizeChanged() signals
  • Loading branch information
uclaros authored and wonder-sk committed Jan 31, 2023
1 parent 90bfb51 commit d2275eb
Show file tree
Hide file tree
Showing 11 changed files with 70 additions and 70 deletions.
36 changes: 17 additions & 19 deletions src/3d/qgs3dmapscene.cpp
Expand Up @@ -114,7 +114,6 @@ Qgs3DMapScene::Qgs3DMapScene( Qgs3DMapSettings &map, QgsAbstract3DEngine *engine

// Camera controlling
mCameraController = new QgsCameraController( this ); // attaches to the scene
mCameraController->setViewport( viewportRect );
mCameraController->setCamera( mEngine->camera() );
mCameraController->resetView( 1000 );

Expand Down Expand Up @@ -203,7 +202,7 @@ Qgs3DMapScene::Qgs3DMapScene( Qgs3DMapSettings &map, QgsAbstract3DEngine *engine
#endif

connect( mCameraController, &QgsCameraController::cameraChanged, this, &Qgs3DMapScene::onCameraChanged );
connect( mCameraController, &QgsCameraController::viewportChanged, this, &Qgs3DMapScene::onCameraChanged );
connect( mEngine, &QgsAbstract3DEngine::sizeChanged, this, &Qgs3DMapScene::onCameraChanged );

#if 0
// experiments with loading of existing 3D models.
Expand Down Expand Up @@ -285,13 +284,12 @@ void Qgs3DMapScene::setViewFrom2DExtent( const QgsRectangle &extent )
QVector<QgsPointXY> Qgs3DMapScene::viewFrustum2DExtent()
{
Qt3DRender::QCamera *camera = mCameraController->camera();
const QRect viewport = mCameraController->viewport();
QVector<QgsPointXY> extent;
QVector<int> pointsOrder = { 0, 1, 3, 2 };
for ( int i : pointsOrder )
{
const QPoint p( ( ( i >> 0 ) & 1 ) ? 0 : viewport.width(), ( ( i >> 1 ) & 1 ) ? 0 : viewport.height() );
QgsRay3D ray = Qgs3DUtils::rayFromScreenPoint( p, viewport.size(), camera );
const QPoint p( ( ( i >> 0 ) & 1 ) ? 0 : mEngine->size().width(), ( ( i >> 1 ) & 1 ) ? 0 : mEngine->size().height() );
QgsRay3D ray = Qgs3DUtils::rayFromScreenPoint( p, mEngine->size(), camera );
QVector3D dir = ray.direction();
if ( dir.y() == 0.0 )
dir.setY( 0.000001 );
Expand Down Expand Up @@ -376,8 +374,8 @@ float Qgs3DMapScene::worldSpaceError( float epsilon, float distance )
{
Qt3DRender::QCamera *camera = mCameraController->camera();
float fov = camera->fieldOfView();
QRect rect = mCameraController->viewport();
float screenSizePx = std::max( rect.width(), rect.height() ); // TODO: is this correct?
const QSize size = mEngine->size();
float screenSizePx = std::max( size.width(), size.height() ); // TODO: is this correct?

// in qgschunkedentity_p.cpp there is inverse calculation (world space error to screen space error)
// with explanation of the math.
Expand All @@ -386,14 +384,14 @@ float Qgs3DMapScene::worldSpaceError( float epsilon, float distance )
return err;
}

QgsChunkedEntity::SceneState _sceneState( QgsCameraController *cameraController )
QgsChunkedEntity::SceneState sceneState_( QgsAbstract3DEngine *engine )
{
Qt3DRender::QCamera *camera = cameraController->camera();
Qt3DRender::QCamera *camera = engine->camera();
QgsChunkedEntity::SceneState state;
state.cameraFov = camera->fieldOfView();
state.cameraPos = camera->position();
QRect rect = cameraController->viewport();
state.screenSizePx = std::max( rect.width(), rect.height() ); // TODO: is this correct?
const QSize size = engine->size();
state.screenSizePx = std::max( size.width(), size.height() ); // TODO: is this correct?
state.viewProjectionMatrix = camera->projectionMatrix() * camera->viewMatrix();
return state;
}
Expand Down Expand Up @@ -460,7 +458,7 @@ void Qgs3DMapScene::updateScene()
for ( QgsChunkedEntity *entity : std::as_const( mChunkEntities ) )
{
if ( entity->isEnabled() )
entity->update( _sceneState( mCameraController ) );
entity->update( sceneState_( mEngine ) );
}
updateSceneState();
}
Expand Down Expand Up @@ -569,7 +567,7 @@ void Qgs3DMapScene::onFrameTriggered( float dt )
if ( entity->isEnabled() && entity->needsUpdate() )
{
QgsDebugMsgLevel( QStringLiteral( "need for update" ), 2 );
entity->update( _sceneState( mCameraController ) );
entity->update( sceneState_( mEngine ) );
}
}

Expand Down Expand Up @@ -914,22 +912,22 @@ void Qgs3DMapScene::finalizeNewEntity( Qt3DCore::QEntity *newEntity )
// maybe this could be more generalized when other materials need some specific treatment
for ( QgsLineMaterial *lm : newEntity->findChildren<QgsLineMaterial *>() )
{
connect( mCameraController, &QgsCameraController::viewportChanged, lm, [lm, this]
connect( mEngine, &QgsAbstract3DEngine::sizeChanged, lm, [lm, this]
{
lm->setViewportSize( mCameraController->viewport().size() );
lm->setViewportSize( mEngine->size() );
} );

lm->setViewportSize( cameraController()->viewport().size() );
lm->setViewportSize( mEngine->size() );
}
// configure billboard's viewport when the viewport is changed.
for ( QgsPoint3DBillboardMaterial *bm : newEntity->findChildren<QgsPoint3DBillboardMaterial *>() )
{
connect( mCameraController, &QgsCameraController::viewportChanged, bm, [bm, this]
connect( mEngine, &QgsAbstract3DEngine::sizeChanged, bm, [bm, this]
{
bm->setViewportSize( mCameraController->viewport().size() );
bm->setViewportSize( mEngine->size() );
} );

bm->setViewportSize( mCameraController->viewport().size() );
bm->setViewportSize( mEngine->size() );
}

// Finalize adding the 3D transparent objects by adding the layer components to the entities
Expand Down
6 changes: 6 additions & 0 deletions src/3d/qgsabstract3dengine.h
Expand Up @@ -135,6 +135,12 @@ class _3D_EXPORT QgsAbstract3DEngine : public QObject
* \since QGIS 3.24
*/
void depthBufferCaptured( const QImage &image );

/**
* Emitted after a call to setSize()
* \since QGIS 3.30
*/
void sizeChanged();
protected:
QgsShadowRenderingFrameGraph *mFrameGraph = nullptr;
};
Expand Down
47 changes: 24 additions & 23 deletions src/3d/qgscameracontroller.cpp
Expand Up @@ -32,8 +32,9 @@

#include "qgslogger.h"

QgsCameraController::QgsCameraController( Qt3DCore::QNode *parent )
: Qt3DCore::QEntity( parent )
QgsCameraController::QgsCameraController( Qgs3DMapScene *scene )
: Qt3DCore::QEntity( scene )
, mScene( scene )
, mCameraBeforeRotation( new Qt3DRender::QCamera )
, mCameraBeforeDrag( new Qt3DRender::QCamera )
, mCameraBeforeZoom( new Qt3DRender::QCamera )
Expand Down Expand Up @@ -70,10 +71,12 @@ QgsCameraController::QgsCameraController( Qt3DCore::QNode *parent )
mFpsNavTimer->setInterval( 10 );
connect( mFpsNavTimer, &QTimer::timeout, this, &QgsCameraController::applyFlyModeKeyMovements );
mFpsNavTimer->start();
}

Qgs3DMapScene *scene = qobject_cast< Qgs3DMapScene * >( parent );
if ( scene )
mWindowEngine = qobject_cast<QgsWindow3DEngine *>( scene->engine() );
QWindow *QgsCameraController::window() const
{
QgsWindow3DEngine *windowEngine = qobject_cast<QgsWindow3DEngine *>( mScene->engine() );
return windowEngine ? windowEngine->window() : nullptr;
}

void QgsCameraController::setCameraNavigationMode( QgsCameraController::NavigationMode navigationMode )
Expand Down Expand Up @@ -121,15 +124,6 @@ void QgsCameraController::setCamera( Qt3DRender::QCamera *camera )
emit cameraChanged();
}

void QgsCameraController::setViewport( QRect viewport )
{
if ( mViewport == viewport )
return;

mViewport = viewport;
emit viewportChanged();
}

void QgsCameraController::rotateCamera( float diffPitch, float diffYaw )
{
const float pitch = mCameraPose.pitchAngle();
Expand Down Expand Up @@ -321,7 +315,7 @@ bool QgsCameraController::screenPointToWorldPos( QPoint position, Qt3DRender::QC
}
else
{
worldPosition = Qgs3DUtils::screenPointToWorldPos( position, depth, mViewport.size(), cameraBefore );
worldPosition = Qgs3DUtils::screenPointToWorldPos( position, depth, mScene->engine()->size(), cameraBefore );
if ( !std::isfinite( worldPosition.x() ) || !std::isfinite( worldPosition.y() ) || !std::isfinite( worldPosition.z() ) )
{
QgsDebugMsgLevel( QStringLiteral( "screenPointToWorldPos: position is NaN or Inf. This should not happen." ), 2 );
Expand Down Expand Up @@ -356,7 +350,7 @@ void QgsCameraController::onPositionChangedTerrainNavigation( Qt3DInput::QMouseE
{
// rotate/tilt using mouse (camera moves as it rotates around the clicked point)

double scale = std::max( mViewport.width(), mViewport.height() );
double scale = std::max( mScene->engine()->size().width(), mScene->engine()->size().height() );
float pitchDiff = 180 * ( mouse->y() - mMiddleButtonClickPos.y() ) / scale;
float yawDiff = -180 * ( mouse->x() - mMiddleButtonClickPos.x() ) / scale;

Expand Down Expand Up @@ -393,7 +387,7 @@ void QgsCameraController::onPositionChangedTerrainNavigation( Qt3DInput::QMouseE

// Second transformation : Shift camera position back
{
QgsRay3D ray = Qgs3DUtils::rayFromScreenPoint( QPoint( mMiddleButtonClickPos.x(), mMiddleButtonClickPos.y() ), mViewport.size(), mCamera );
QgsRay3D ray = Qgs3DUtils::rayFromScreenPoint( QPoint( mMiddleButtonClickPos.x(), mMiddleButtonClickPos.y() ), mScene->engine()->size(), mCamera );

QVector3D clickedPositionWorld = ray.origin() + mRotationDistanceFromCenter * ray.direction();

Expand Down Expand Up @@ -436,7 +430,7 @@ void QgsCameraController::onPositionChangedTerrainNavigation( Qt3DInput::QMouseE

QVector3D cameraBeforeDragPos = mCameraBeforeDrag->position();

QVector3D moveToPosition = Qgs3DUtils::screenPointToWorldPos( mMousePos, mDragDepth, mViewport.size(), mCameraBeforeDrag.get() );
QVector3D moveToPosition = Qgs3DUtils::screenPointToWorldPos( mMousePos, mDragDepth, mScene->engine()->size(), mCameraBeforeDrag.get() );
QVector3D cameraBeforeToMoveToPos = ( moveToPosition - mCameraBeforeDrag->position() ).normalized();
QVector3D cameraBeforeToDragPointPos = ( mDragPoint - mCameraBeforeDrag->position() ).normalized();

Expand Down Expand Up @@ -491,8 +485,15 @@ void QgsCameraController::onPositionChangedTerrainNavigation( Qt3DInput::QMouseE

float dist = ( mCameraBeforeDrag->position() - mDragPoint ).length();

const int yOffset = mWindowEngine->window()->mapToGlobal( QPoint( 0, 0 ) ).y();
const int screenHeight = mWindowEngine->window()->screen()->size().height();
int yOffset = 0;
int screenHeight = mScene->engine()->size().height();
QWindow *win = window();
if ( win )
{
yOffset = win->mapToGlobal( QPoint( 0, 0 ) ).y();
screenHeight = win->screen()->size().height();
}

// Applies smoothing
if ( mMousePos.y() > mDragButtonClickPos.y() ) // zoom in
{
Expand Down Expand Up @@ -522,7 +523,7 @@ void QgsCameraController::onPositionChangedTerrainNavigation( Qt3DInput::QMouseE

// Second transformation : Shift camera position back
{
QgsRay3D ray = Qgs3DUtils::rayFromScreenPoint( QPoint( mDragButtonClickPos.x(), mDragButtonClickPos.y() ), mViewport.size(), mCamera );
QgsRay3D ray = Qgs3DUtils::rayFromScreenPoint( QPoint( mDragButtonClickPos.x(), mDragButtonClickPos.y() ), mScene->engine()->size(), mCamera );
QVector3D clickedPositionWorld = ray.origin() + dist * ray.direction();

QVector3D shiftVector = clickedPositionWorld - mCamera->viewCenter();
Expand Down Expand Up @@ -582,7 +583,7 @@ void QgsCameraController::handleTerrainNavigationWheelZoom()

// Second transformation : Shift camera position back
{
QgsRay3D ray = Qgs3DUtils::rayFromScreenPoint( QPoint( mMousePos.x(), mMousePos.y() ), mViewport.size(), mCamera );
QgsRay3D ray = Qgs3DUtils::rayFromScreenPoint( QPoint( mMousePos.x(), mMousePos.y() ), mScene->engine()->size(), mCamera );
QVector3D clickedPositionWorld = ray.origin() + dist * ray.direction();

QVector3D shiftVector = clickedPositionWorld - mCamera->viewCenter();
Expand Down Expand Up @@ -971,7 +972,7 @@ void QgsCameraController::onPositionChangedFlyNavigation( Qt3DInput::QMouseEvent
mIgnoreNextMouseMove = true;

// reset cursor back to center of map widget
emit setCursorPosition( QPoint( mViewport.width() / 2, mViewport.height() / 2 ) );
emit setCursorPosition( QPoint( mScene->engine()->size().width() / 2, mScene->engine()->size().height() / 2 ) );
}
}

Expand Down
20 changes: 9 additions & 11 deletions src/3d/qgscameracontroller.h
Expand Up @@ -50,6 +50,7 @@ class QgsCameraPose;
class QgsTerrainEntity;
class QgsVector3D;
class QgsWindow3DEngine;
class Qgs3DMapScene;

#define SIP_NO_FILE

Expand All @@ -63,7 +64,6 @@ class _3D_EXPORT QgsCameraController : public Qt3DCore::QEntity
{
Q_OBJECT
Q_PROPERTY( Qt3DRender::QCamera *camera READ camera WRITE setCamera NOTIFY cameraChanged )
Q_PROPERTY( QRect viewport READ viewport WRITE setViewport NOTIFY viewportChanged )
public:

//! The navigation mode used by the camera
Expand All @@ -85,12 +85,10 @@ class _3D_EXPORT QgsCameraController : public Qt3DCore::QEntity

public:
//! Constructs the camera controller with optional parent node that will take ownership
QgsCameraController( Qt3DCore::QNode *parent = nullptr );
QgsCameraController( Qgs3DMapScene *scene );

//! Returns camera that is being controlled
Qt3DRender::QCamera *camera() const { return mCamera; }
//! Returns viewport rectangle
QRect viewport() const { return mViewport; }

/**
* Returns the navigation mode used by the camera controller.
Expand Down Expand Up @@ -131,8 +129,7 @@ class _3D_EXPORT QgsCameraController : public Qt3DCore::QEntity

//! Assigns camera that should be controlled by this class. Called internally from 3D scene.
void setCamera( Qt3DRender::QCamera *camera );
//! Sets viewport rectangle. Called internally from 3D canvas. Allows conversion of mouse coordinates.
void setViewport( QRect viewport );

//! Called internally from 3D scene when a new frame is generated. Updates camera according to keyboard/mouse input
void frameTriggered( float dt );

Expand Down Expand Up @@ -227,12 +224,13 @@ class _3D_EXPORT QgsCameraController : public Qt3DCore::QEntity
void rotateCamera( float diffPitch, float diffYaw );
void updateCameraFromPose();
void moveCameraPositionBy( const QVector3D &posDiff );
//! Returns a pointer to the scene's engine's window or nullptr if engine is QgsOffscreen3DEngine
QWindow *window() const;

signals:
//! Emitted when camera has been updated
void cameraChanged();
//! Emitted when viewport rectangle has been updated
void viewportChanged();

//! Emitted when the navigation mode is changed using the hotkey ctrl + ~
void navigationModeChanged( QgsCameraController::NavigationMode mode );

Expand Down Expand Up @@ -286,12 +284,12 @@ class _3D_EXPORT QgsCameraController : public Qt3DCore::QEntity
bool screenPointToWorldPos( QPoint position, Qt3DRender::QCamera *cameraBefore, double &depth, QVector3D &worldPosition );

private:
//! The 3d scene the controller uses
Qgs3DMapScene *mScene = nullptr;

//! Camera that is being controlled
Qt3DRender::QCamera *mCamera = nullptr;

//! used for computation of translation when dragging mouse
QRect mViewport;
QgsWindow3DEngine *mWindowEngine = nullptr;
//! height of terrain when mouse button was last pressed - for camera control
float mLastPressedHeight = 0;

Expand Down
1 change: 1 addition & 0 deletions src/3d/qgsoffscreen3dengine.cpp
Expand Up @@ -120,6 +120,7 @@ void QgsOffscreen3DEngine::setSize( QSize s )

mFrameGraph->setSize( mSize );
mCamera->setAspectRatio( float( mSize.width() ) / float( mSize.height() ) );
emit sizeChanged();
}

void QgsOffscreen3DEngine::setClearColor( const QColor &color )
Expand Down
11 changes: 6 additions & 5 deletions src/3d/qgsrubberband3d.cpp
Expand Up @@ -15,7 +15,7 @@

#include "qgsrubberband3d.h"

#include "qgscameracontroller.h"
#include "qgswindow3dengine.h"
#include "qgslinevertexdata_p.h"
#include "qgslinematerial_p.h"
#include "qgsvertexid.h"
Expand All @@ -35,12 +35,13 @@

#include <Qt3DRender/QGeometryRenderer>
#include <Qt3DRender/QMaterial>
#include <QColor>


/// @cond PRIVATE


QgsRubberBand3D::QgsRubberBand3D( Qgs3DMapSettings &map, QgsCameraController *cameraController, Qt3DCore::QEntity *parentEntity )
QgsRubberBand3D::QgsRubberBand3D( Qgs3DMapSettings &map, QgsWindow3DEngine *engine, Qt3DCore::QEntity *parentEntity )
{
mMapSettings = &map;

Expand All @@ -65,11 +66,11 @@ QgsRubberBand3D::QgsRubberBand3D( Qgs3DMapSettings &map, QgsCameraController *ca
mLineMaterial->setLineWidth( 3 );
mLineMaterial->setLineColor( Qt::red );

QObject::connect( cameraController, &QgsCameraController::viewportChanged, mLineMaterial, [this, cameraController]
QObject::connect( engine, &QgsAbstract3DEngine::sizeChanged, mLineMaterial, [this, engine]
{
mLineMaterial->setViewportSize( cameraController->viewport().size() );
mLineMaterial->setViewportSize( engine->size() );
} );
mLineMaterial->setViewportSize( cameraController->viewport().size() );
mLineMaterial->setViewportSize( engine->size() );

mEntity->addComponent( mLineMaterial );
}
Expand Down
4 changes: 2 additions & 2 deletions src/3d/qgsrubberband3d.h
Expand Up @@ -33,7 +33,7 @@

#include "qgslinestring.h"

class QgsCameraController;
class QgsWindow3DEngine;
class QgsLineMaterial;
class Qgs3DMapSettings;

Expand Down Expand Up @@ -72,7 +72,7 @@ namespace Qt3DRender
class _3D_EXPORT QgsRubberBand3D
{
public:
QgsRubberBand3D( Qgs3DMapSettings &map, QgsCameraController *cameraController, Qt3DCore::QEntity *parentEntity );
QgsRubberBand3D( Qgs3DMapSettings &map, QgsWindow3DEngine *engine, Qt3DCore::QEntity *parentEntity );
~QgsRubberBand3D();

float width() const;
Expand Down
1 change: 1 addition & 0 deletions src/3d/qgswindow3dengine.cpp
Expand Up @@ -101,4 +101,5 @@ void QgsWindow3DEngine::setSize( QSize s )
mWindow3D->setHeight( mSize.height() );
mFrameGraph->setSize( mSize );
camera()->setAspectRatio( float( mSize.width() ) / float( mSize.height() ) );
emit sizeChanged();
}

0 comments on commit d2275eb

Please sign in to comment.