Skip to content
Permalink
Browse files

initial fly mode implementation

  • Loading branch information
NEDJIMAbelgacem authored and nyalldawson committed Jan 13, 2021
1 parent 33cbe39 commit 44d39becf37a99d59f4ad4a8ae3f101737dbadb6
@@ -554,6 +554,20 @@ Sets the camera lens' field of view



QgsCameraController::NavigationMode cameraNavigationMode() const;
%Docstring
Returns the navigation mode used by the camera

.. versionadded:: 3.18
%End

void setCameraNavigationMode( QgsCameraController::NavigationMode navigationMode );
%Docstring
Sets the navigation mode for the camera

.. versionadded:: 3.18
%End

void setOutputDpi( const double dpi );
%Docstring
Sets DPI used for conversion between real world units (e.g. mm) and pixels
@@ -783,6 +797,13 @@ Emitted when the camera lens field of view changes
%Docstring
Emitted when the camera lens projection type changes

.. versionadded:: 3.18
%End

void cameraNavigationModeChanged();
%Docstring
Emitted when the camera navigation mode was changed

.. versionadded:: 3.18
%End

@@ -142,6 +142,7 @@ Qgs3DMapScene::Qgs3DMapScene( const Qgs3DMapSettings &map, QgsAbstract3DEngine *
connect( &map, &Qgs3DMapSettings::debugShadowMapSettingsChanged, this, &Qgs3DMapScene::onDebugShadowMapSettingsChanged );
connect( &map, &Qgs3DMapSettings::debugDepthMapSettingsChanged, this, &Qgs3DMapScene::onDebugDepthMapSettingsChanged );
connect( &map, &Qgs3DMapSettings::fpsCounterEnabledChanged, this, &Qgs3DMapScene::fpsCounterEnabledChanged );
connect( &map, &Qgs3DMapSettings::cameraNavigationModeChanged, this, &Qgs3DMapScene::onCameraNavigationModeChanged );

connect( QgsApplication::instance()->sourceCache(), &QgsSourceCache::remoteSourceFetched, this, [ = ]( const QString & url )
{
@@ -230,6 +231,8 @@ Qgs3DMapScene::Qgs3DMapScene( const Qgs3DMapSettings &map, QgsAbstract3DEngine *
// force initial update of debugging setting of preview quads
onDebugShadowMapSettingsChanged();
onDebugDepthMapSettingsChanged();

onCameraNavigationModeChanged();
}

void Qgs3DMapScene::viewZoomFull()
@@ -1055,6 +1058,11 @@ void Qgs3DMapScene::onEyeDomeShadingSettingsChanged()
shadowRenderingFrameGraph->setupEyeDomeLighting( edlEnabled, edlStrength, edlDistance );
}

void Qgs3DMapScene::onCameraNavigationModeChanged()
{
mCameraController->setCameraNavigationMode( mMap.cameraNavigationMode() );
}

void Qgs3DMapScene::exportScene( const Qgs3DMapExportSettings &exportSettings )
{
QVector<QString> notParsedLayers;
@@ -161,6 +161,7 @@ class _3D_EXPORT Qgs3DMapScene : public Qt3DCore::QEntity
void onEyeDomeShadingSettingsChanged();
void onDebugShadowMapSettingsChanged();
void onDebugDepthMapSettingsChanged();
void onCameraNavigationModeChanged();

private:
void addLayerEntity( QgsMapLayer *layer );
@@ -100,6 +100,11 @@ void Qgs3DMapSettings::readXml( const QDomElement &elem, const QgsReadWriteConte
{
mFieldOfView = elemCamera.attribute( QStringLiteral( "field-of-view" ), QStringLiteral( "45" ) ).toFloat();
mProjectionType = static_cast< Qt3DRender::QCameraLens::ProjectionType >( elemCamera.attribute( QStringLiteral( "projection-type" ), QStringLiteral( "1" ) ).toInt() );
QString cameraNavigationMode = elemCamera.attribute( QStringLiteral( "camera-navigation-mode" ), QStringLiteral( "basic-navigation" ) );
if ( cameraNavigationMode == QStringLiteral( "basic-navigation" ) )
mCameraNavigationMode = QgsCameraController::NavigationMode::BasicNavigation;
else if ( cameraNavigationMode == QStringLiteral( "fps-navigation" ) )
mCameraNavigationMode = QgsCameraController::NavigationMode::FPSNavigation;
}

QDomElement elemColor = elem.firstChildElement( QStringLiteral( "color" ) );
@@ -293,6 +298,10 @@ QDomElement Qgs3DMapSettings::writeXml( QDomDocument &doc, const QgsReadWriteCon
QDomElement elemCamera = doc.createElement( QStringLiteral( "camera" ) );
elemCamera.setAttribute( QStringLiteral( "field-of-view" ), mFieldOfView );
elemCamera.setAttribute( QStringLiteral( "projection-type" ), static_cast< int >( mProjectionType ) );
if ( mCameraNavigationMode == QgsCameraController::BasicNavigation )
elemCamera.setAttribute( QStringLiteral( "camera-navigation-mode" ), QStringLiteral( "basic-navigation" ) );
else if ( mCameraNavigationMode == QgsCameraController::FPSNavigation )
elemCamera.setAttribute( QStringLiteral( "camera-navigation-mode" ), QStringLiteral( "fps-navigation" ) );
elem.appendChild( elemCamera );

QDomElement elemColor = doc.createElement( QStringLiteral( "color" ) );
@@ -757,6 +766,15 @@ void Qgs3DMapSettings::setProjectionType( const Qt3DRender::QCameraLens::Project
emit projectionTypeChanged();
}

void Qgs3DMapSettings::setCameraNavigationMode( QgsCameraController::NavigationMode navigationMode )
{
if ( mCameraNavigationMode == navigationMode )
return;

mCameraNavigationMode = navigationMode;
emit cameraNavigationModeChanged();
}

void Qgs3DMapSettings::setSkyboxSettings( const QgsSkyboxSettings &skyboxSettings )
{
mSkyboxSettings = skyboxSettings;
@@ -33,6 +33,7 @@
#include "qgsvector3d.h"
#include "qgsskyboxsettings.h"
#include "qgsshadowsettings.h"
#include "qgscameracontroller.h"

class QgsMapLayer;
class QgsRasterLayer;
@@ -476,6 +477,18 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject, public QgsTemporalRangeObjec
*/
void setProjectionType( const Qt3DRender::QCameraLens::ProjectionType projectionType ) SIP_SKIP;

/**
* Returns the navigation mode used by the camera
* \since QGIS 3.18
*/
QgsCameraController::NavigationMode cameraNavigationMode() const { return mCameraNavigationMode; }

/**
* Sets the navigation mode for the camera
* \since QGIS 3.18
*/
void setCameraNavigationMode( QgsCameraController::NavigationMode navigationMode );

/**
* Sets DPI used for conversion between real world units (e.g. mm) and pixels
* \param dpi the number of dot per inch
@@ -678,6 +691,12 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject, public QgsTemporalRangeObjec
*/
void projectionTypeChanged();

/**
* Emitted when the camera navigation mode was changed
* \since QGIS 3.18
*/
void cameraNavigationModeChanged();

/**
* Emitted when skybox settings are changed
* \since QGIS 3.16
@@ -726,6 +745,7 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject, public QgsTemporalRangeObjec
QList<QgsDirectionalLightSettings> mDirectionalLights; //!< List of directional lights defined for the scene
float mFieldOfView = 45.0f; //<! Camera lens field of view value
Qt3DRender::QCameraLens::ProjectionType mProjectionType = Qt3DRender::QCameraLens::PerspectiveProjection; //<! Camera lens projection type
QgsCameraController::NavigationMode mCameraNavigationMode = QgsCameraController::NavigationMode::BasicNavigation;
QList<QgsMapLayerRef> mLayers; //!< Layers to be rendered
QList<QgsMapLayerRef> mTerrainLayers; //!< Terrain layers to be rendered
QList<QgsAbstract3DRenderer *> mRenderers; //!< Extra stuff to render as 3D object
@@ -60,6 +60,11 @@ QgsCameraController::QgsCameraController( Qt3DCore::QNode *parent )
mKeyboardHandler, &Qt3DInput::QMouseHandler::setEnabled );
}

void QgsCameraController::setCameraNavigationMode( QgsCameraController::NavigationMode navigationMode )
{
mCameraNavigationMode = navigationMode;
}

void QgsCameraController::setTerrainEntity( QgsTerrainEntity *te )
{
mTerrainEntity = te;
@@ -289,8 +294,31 @@ void QgsCameraController::updateCameraFromPose( bool centerPointChanged )
emit cameraChanged();
}

void QgsCameraController::moveCameraPositionBy( const QVector3D &posDiff )
{
mCameraPose.setCenterPoint( mCameraPose.centerPoint() + posDiff );

if ( mCameraPose.pitchAngle() > 180 )
mCameraPose.setPitchAngle( 180 ); // prevent going over the head
if ( mCameraPose.pitchAngle() < 0 )
mCameraPose.setPitchAngle( 0 ); // prevent going over the head
if ( mCameraPose.distanceFromCenterPoint() < 10 )
mCameraPose.setDistanceFromCenterPoint( 10 );

if ( mCamera )
mCameraPose.updateCamera( mCamera );

emit cameraChanged();

}

void QgsCameraController::onPositionChanged( Qt3DInput::QMouseEvent *mouse )
{
if ( mCameraNavigationMode == FPSNavigation )
{
onPositionChangedFPSNavigation( mouse );
return;
}
int dx = mouse->x() - mMousePos.x();
int dy = mouse->y() - mMousePos.y();

@@ -342,6 +370,19 @@ void QgsCameraController::onPositionChanged( Qt3DInput::QMouseEvent *mouse )
mMousePos = QPoint( mouse->x(), mouse->y() );
}

void QgsCameraController::onPositionChangedFPSNavigation( Qt3DInput::QMouseEvent *mouse )
{
if ( !mMousePressed )
return;
int dx = mouse->x() - mMousePos.x();
int dy = mouse->y() - mMousePos.y();
float diffPitch = 0.2f * dy;
float diffYaw = - 0.2f * dx;
rotateCamera( diffPitch, diffYaw );
updateCameraFromPose( false );
mMousePos = QPoint( mouse->x(), mouse->y() );
}

void QgsCameraController::zoom( float factor )
{
// zoom in/out
@@ -364,15 +405,27 @@ void QgsCameraController::onMousePressed( Qt3DInput::QMouseEvent *mouse )
{
Q_UNUSED( mouse )
mKeyboardHandler->setFocus( true );
if ( mouse->button() == Qt3DInput::QMouseEvent::Buttons::LeftButton )
{
mMousePos = QPoint( mouse->x(), mouse->y() );
mMousePressed = true;
}
}

void QgsCameraController::onMouseReleased( Qt3DInput::QMouseEvent *mouse )
{
Q_UNUSED( mouse )
mMousePressed = false;
}

void QgsCameraController::onKeyPressed( Qt3DInput::QKeyEvent *event )
{
if ( mCameraNavigationMode == NavigationMode::FPSNavigation )
{
onKeyPressedFPSNavigation( event );
return;
}

bool hasShift = ( event->modifiers() & Qt::ShiftModifier );
bool hasCtrl = ( event->modifiers() & Qt::ControlModifier );

@@ -432,6 +485,48 @@ void QgsCameraController::onKeyPressed( Qt3DInput::QKeyEvent *event )
}
}

void QgsCameraController::onKeyPressedFPSNavigation( Qt3DInput::QKeyEvent *event )
{
QVector3D cameraUp = mCamera->upVector().normalized();
QVector3D cameraFront = ( QVector3D( mCameraPose.centerPoint().x(), mCameraPose.centerPoint().y(), mCameraPose.centerPoint().z() ) - mCamera->position() ).normalized();
QVector3D cameraLeft = QVector3D::crossProduct( cameraUp, cameraFront );

QVector3D cameraPosDiff( 0.0f, 0.0f, 0.0f );
float movementSpeed = 5.0f;

switch ( event->key() )
{
case Qt::Key_Left:
case Qt::Key_A:
cameraPosDiff = movementSpeed * cameraLeft;
break;
case Qt::Key_Right:
case Qt::Key_D:
cameraPosDiff = - movementSpeed * cameraLeft;
break;

case Qt::Key_Up:
case Qt::Key_W:
cameraPosDiff = movementSpeed * cameraFront;
break;
case Qt::Key_Down:
case Qt::Key_S:
cameraPosDiff = - movementSpeed * cameraFront;
break;

case Qt::Key_PageUp:
case Qt::Key_Q:
cameraPosDiff = movementSpeed * cameraUp;
break;
case Qt::Key_PageDown:
case Qt::Key_E:
cameraPosDiff = - movementSpeed * cameraUp;
break;
}

moveCameraPositionBy( cameraPosDiff );
}

void QgsCameraController::onKeyReleased( Qt3DInput::QKeyEvent *event )
{
Q_UNUSED( event )
@@ -61,6 +61,13 @@ 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:
enum NavigationMode
{
BasicNavigation,
FPSNavigation
};

public:
//! Constructs the camera controller with optional parent node that will take ownership
QgsCameraController( Qt3DCore::QNode *parent = nullptr );
@@ -70,6 +77,18 @@ class _3D_EXPORT QgsCameraController : public Qt3DCore::QEntity
//! Returns viewport rectangle
QRect viewport() const { return mViewport; }

/**
* Returns the nvigtion mode used by the camera controller
* \since QGIS 3.18
*/
QgsCameraController::NavigationMode cameraNavigationMode() { return mCameraNavigationMode; }

/**
* Sets the nvigtion mode used by the camera controller
* \since QGIS 3.18
*/
void setCameraNavigationMode( QgsCameraController::NavigationMode navigationMode );

/**
* Connects to object picker attached to terrain entity. Called internally from 3D scene.
* This allows camera controller understand how far from the camera is the terrain under mouse cursor.
@@ -152,6 +171,7 @@ class _3D_EXPORT QgsCameraController : public Qt3DCore::QEntity
private:
void rotateCamera( float diffPitch, float diffYaw );
void updateCameraFromPose( bool centerPointChanged = false );
void moveCameraPositionBy( const QVector3D &posDiff );

signals:
//! Emitted when camera has been updated
@@ -168,6 +188,10 @@ class _3D_EXPORT QgsCameraController : public Qt3DCore::QEntity
void onKeyReleased( Qt3DInput::QKeyEvent *event );
void onPickerMousePressed( Qt3DRender::QPickEvent *pick );

private:
void onKeyPressedFPSNavigation( Qt3DInput::QKeyEvent *mouse );
void onPositionChangedFPSNavigation( Qt3DInput::QMouseEvent *mouse );

private:
//! Camera that is being controlled
Qt3DRender::QCamera *mCamera = nullptr;
@@ -183,14 +207,18 @@ class _3D_EXPORT QgsCameraController : public Qt3DCore::QEntity

//! Last mouse position recorded
QPoint mMousePos;
bool mMousePressed = false;

//! Delegates mouse events to the attached MouseHandler objects
Qt3DInput::QMouseDevice *mMouseDevice = nullptr;
Qt3DInput::QKeyboardDevice *mKeyboardDevice = nullptr;

Qt3DInput::QMouseHandler *mMouseHandler = nullptr;
Qt3DInput::QKeyboardHandler *mKeyboardHandler = nullptr;

NavigationMode mCameraNavigationMode = NavigationMode::BasicNavigation;
double mDeltaTime = 0.0f;
QVector<double> mPastDeltaTime;
double mDeltaTimeAverage = 0.0f;
};

#endif // QGSCAMERACONTROLLER_H
@@ -134,6 +134,7 @@ Qgs3DMapConfigWidget::Qgs3DMapConfigWidget( Qgs3DMapSettings *map, QgsMapCanvas

spinCameraFieldOfView->setValue( mMap->fieldOfView() );
cboCameraProjectionType->setCurrentIndex( cboCameraProjectionType->findData( mMap->projectionType() ) );
mCameraNavigationMode->setCurrentIndex( mMap->cameraNavigationMode() );
spinTerrainScale->setValue( mMap->terrainVerticalScale() );
spinMapResolution->setValue( mMap->mapTileResolution() );
spinScreenError->setValue( mMap->maxTerrainScreenError() );
@@ -317,6 +318,7 @@ void Qgs3DMapConfigWidget::apply()

mMap->setFieldOfView( spinCameraFieldOfView->value() );
mMap->setProjectionType( cboCameraProjectionType->currentData().value< Qt3DRender::QCameraLens::ProjectionType >() );
mMap->setCameraNavigationMode( static_cast<QgsCameraController::NavigationMode>( mCameraNavigationMode->currentIndex() ) );
mMap->setTerrainVerticalScale( spinTerrainScale->value() );
mMap->setMapTileResolution( spinMapResolution->value() );
mMap->setMaxTerrainScreenError( spinScreenError->value() );

0 comments on commit 44d39be

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