Skip to content
Permalink
Browse files

Fix issues with camera view center adjustments + option to show the c…

…enter
  • Loading branch information
wonder-sk committed Jun 28, 2018
1 parent 8a15cef commit 255aa9e00bb9e10f044043bc165fb9e41fd133aa
@@ -23,6 +23,7 @@
#include <Qt3DExtras/QForwardRenderer>
#include <Qt3DExtras/QPhongMaterial>
#include <Qt3DExtras/QSkyboxEntity>
#include <Qt3DExtras/QSphereMesh>
#include <Qt3DLogic/QFrameAction>

#include <QTimer>
@@ -34,7 +35,6 @@
#include "qgscameracontroller.h"
#include "qgschunkedentity_p.h"
#include "qgschunknode_p.h"
#include "qgsraycastingutils_p.h"
#include "qgsterrainentity_p.h"
#include "qgsterraingenerator.h"
#include "qgsvectorlayer.h"
@@ -74,6 +74,8 @@ Qgs3DMapScene::Qgs3DMapScene( const Qgs3DMapSettings &map, Qt3DExtras::QForwardR
mCameraController->setCamera( camera );
mCameraController->resetView( 1000 );

addCameraViewCenterEntity( camera );

// create terrain entity

createTerrain();
@@ -255,21 +257,6 @@ void Qgs3DMapScene::onCameraChanged()
camera->setFarPlane( ffar * 2 );
camera->setNearPlane( fnear / 2 );

// figure out our distance from terrain and update the camera's view center
// so that camera tilting and rotation is around a point on terrain, not an point at fixed elevation
QVector3D intersectionPoint;
QgsRayCastingUtils::Ray3D ray = QgsRayCastingUtils::rayForViewportAndCamera(
mCameraController->viewport().size(),
mCameraController->viewport().center(),
QRectF( 0.0, 0.0, 1.0, 1.0 ),
mCameraController->camera() );
if ( mTerrain->rayIntersection( ray, intersectionPoint ) )
{
float dist = ( intersectionPoint - mCameraController->camera()->position() ).length();
mCameraController->blockSignals( true );
mCameraController->setLookingAtPoint( QgsVector3D( intersectionPoint.x(), intersectionPoint.y(), intersectionPoint.z() ), dist );
mCameraController->blockSignals( false );
}
}
else
qDebug() << "no terrain - not setting near/far plane";
@@ -321,7 +308,7 @@ void Qgs3DMapScene::createTerrainDeferred()
if ( mMap.showTerrainBoundingBoxes() )
mTerrain->setShowBoundingBoxes( true );

mCameraController->addTerrainPicker( mTerrain->terrainPicker() );
mCameraController->setTerrainEntity( mTerrain );

mChunkEntities << mTerrain;

@@ -435,3 +422,31 @@ void Qgs3DMapScene::removeLayerEntity( QgsMapLayer *layer )
disconnect( vlayer, &QgsVectorLayer::selectionChanged, this, &Qgs3DMapScene::onLayerRenderer3DChanged );
}
}

void Qgs3DMapScene::addCameraViewCenterEntity( Qt3DRender::QCamera *camera )
{
mEntityCameraViewCenter = new Qt3DCore::QEntity;

Qt3DCore::QTransform *trCameraViewCenter = new Qt3DCore::QTransform;
mEntityCameraViewCenter->addComponent( trCameraViewCenter );
connect( camera, &Qt3DRender::QCamera::viewCenterChanged, this, [trCameraViewCenter, camera]
{
trCameraViewCenter->setTranslation( camera->viewCenter() );
} );

Qt3DExtras::QPhongMaterial *materialCameraViewCenter = new Qt3DExtras::QPhongMaterial;
materialCameraViewCenter->setAmbient( Qt::red );
mEntityCameraViewCenter->addComponent( materialCameraViewCenter );

Qt3DExtras::QSphereMesh *rendererCameraViewCenter = new Qt3DExtras::QSphereMesh;
rendererCameraViewCenter->setRadius( 10 );
mEntityCameraViewCenter->addComponent( rendererCameraViewCenter );

mEntityCameraViewCenter->setEnabled( mMap.showCameraViewCenter() );
mEntityCameraViewCenter->setParent( this );

connect( &mMap, &Qgs3DMapSettings::showCameraViewCenterChanged, this, [this]
{
mEntityCameraViewCenter->setEnabled( mMap.showCameraViewCenter() );
} );
}
@@ -83,6 +83,7 @@ class _3D_EXPORT Qgs3DMapScene : public Qt3DCore::QEntity
private:
void addLayerEntity( QgsMapLayer *layer );
void removeLayerEntity( QgsMapLayer *layer );
void addCameraViewCenterEntity( Qt3DRender::QCamera *camera );

private:
const Qgs3DMapSettings &mMap;
@@ -93,6 +94,8 @@ class _3D_EXPORT Qgs3DMapScene : public Qt3DCore::QEntity
//! Forward renderer provided by 3D window
Qt3DExtras::QForwardRenderer *mForwardRenderer = nullptr;
QList<QgsChunkedEntity *> mChunkEntities;
//! Entity that shows view center - useful for debugging camera issues
Qt3DCore::QEntity *mEntityCameraViewCenter = nullptr;
//! Keeps track of entities that belong to a particular layer
QMap<QgsMapLayer *, Qt3DCore::QEntity *> mLayerEntities;
bool mTerrainUpdateScheduled = false;
@@ -38,6 +38,7 @@ Qgs3DMapSettings::Qgs3DMapSettings( const Qgs3DMapSettings &other )
, mMaxTerrainGroundError( other.mMaxTerrainGroundError )
, mShowTerrainBoundingBoxes( other.mShowTerrainBoundingBoxes )
, mShowTerrainTileInfo( other.mShowTerrainTileInfo )
, mShowCameraViewCenter( other.mShowCameraViewCenter )
, mLayers( other.mLayers )
, mSkyboxEnabled( other.mSkyboxEnabled )
, mSkyboxFileBase( other.mSkyboxFileBase )
@@ -133,6 +134,7 @@ void Qgs3DMapSettings::readXml( const QDomElement &elem, const QgsReadWriteConte
QDomElement elemDebug = elem.firstChildElement( "debug" );
mShowTerrainBoundingBoxes = elemDebug.attribute( "bounding-boxes", "0" ).toInt();
mShowTerrainTileInfo = elemDebug.attribute( "terrain-tile-info", "0" ).toInt();
mShowCameraViewCenter = elemDebug.attribute( "camera-view-center", "0" ).toInt();
}

QDomElement Qgs3DMapSettings::writeXml( QDomDocument &doc, const QgsReadWriteContext &context ) const
@@ -189,6 +191,7 @@ QDomElement Qgs3DMapSettings::writeXml( QDomDocument &doc, const QgsReadWriteCon
QDomElement elemDebug = doc.createElement( "debug" );
elemDebug.setAttribute( "bounding-boxes", mShowTerrainBoundingBoxes ? 1 : 0 );
elemDebug.setAttribute( "terrain-tile-info", mShowTerrainTileInfo ? 1 : 0 );
elemDebug.setAttribute( "camera-view-center", mShowCameraViewCenter ? 1 : 0 );
elem.appendChild( elemDebug );

return elem;
@@ -377,6 +380,15 @@ void Qgs3DMapSettings::setShowTerrainTilesInfo( bool enabled )
emit showTerrainTilesInfoChanged();
}

void Qgs3DMapSettings::setShowCameraViewCenter( bool enabled )
{
if ( mShowCameraViewCenter == enabled )
return;

mShowCameraViewCenter = enabled;
emit showCameraViewCenterChanged();
}

void Qgs3DMapSettings::setShowLabels( bool enabled )
{
if ( mShowLabels == enabled )
@@ -227,6 +227,18 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject
void setShowTerrainTilesInfo( bool enabled );
//! Returns whether to display extra tile info on top of terrain tiles (for debugging)
bool showTerrainTilesInfo() const { return mShowTerrainTileInfo; }

/**
* Sets whether to show camera's view center as a sphere (for debugging)
* \since QGIS 3.4
*/
void setShowCameraViewCenter( bool enabled );

/**
* Returns whether to show camera's view center as a sphere (for debugging)
* \since QGIS 3.4
*/
bool showCameraViewCenter() const { return mShowCameraViewCenter; }
//! Sets whether to display labels on terrain tiles
void setShowLabels( bool enabled );
//! Returns whether to display labels on terrain tiles
@@ -253,6 +265,12 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject
void showTerrainBoundingBoxesChanged();
//! Emitted when the flag whether terrain's tile info is shown has changed
void showTerrainTilesInfoChanged();

/**
* Emitted when the flag whether camera's view center is shown has changed
* \since QGIS 3.4
*/
void showCameraViewCenterChanged();
//! Emitted when the flag whether labels are displayed on terrain tiles has changed
void showLabelsChanged();

@@ -269,6 +287,7 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject
float mMaxTerrainGroundError = 1.f; //!< Maximum allowed horizontal map error in map units (determines how many zoom levels will be used)
bool mShowTerrainBoundingBoxes = false; //!< Whether to show bounding boxes of entities - useful for debugging
bool mShowTerrainTileInfo = false; //!< Whether to draw extra information about terrain tiles to the textures - useful for debugging
bool mShowCameraViewCenter = false; //!< Whether to show camera view center as a sphere - useful for debugging
bool mShowLabels = false; //!< Whether to display labels on terrain tiles
QList<QgsMapLayerRef> mLayers; //!< Layers to be rendered
QList<QgsAbstract3DRenderer *> mRenderers; //!< Extra stuff to render as 3D object
@@ -14,6 +14,8 @@
***************************************************************************/

#include "qgscameracontroller.h"
#include "qgsraycastingutils_p.h"
#include "qgsterrainentity_p.h"
#include "qgsvector3d.h"

#include "qgis.h"
@@ -129,10 +131,12 @@ QgsCameraController::QgsCameraController( Qt3DCore::QNode *parent )
addComponent( mLogicalDevice );
}

void QgsCameraController::addTerrainPicker( Qt3DRender::QObjectPicker *picker )
void QgsCameraController::setTerrainEntity( QgsTerrainEntity *te )
{
mTerrainEntity = te;

// object picker for terrain for correct map panning
connect( picker, &Qt3DRender::QObjectPicker::pressed, this, &QgsCameraController::onPickerMousePressed );
connect( te->terrainPicker(), &Qt3DRender::QObjectPicker::pressed, this, &QgsCameraController::onPickerMousePressed );
}

void QgsCameraController::setCamera( Qt3DRender::QCamera *camera )
@@ -295,6 +299,25 @@ void QgsCameraController::frameTriggered( float dt )
if ( mCameraData != oldCamData )
{
mCameraData.setCamera( mCamera );

bool viewCenterChanged = ( mCameraData.x != oldCamData.x || mCameraData.y != oldCamData.y || mCameraData.elev != oldCamData.elev );
if ( mTerrainEntity && viewCenterChanged )
{
// figure out our distance from terrain and update the camera's view center
// so that camera tilting and rotation is around a point on terrain, not an point at fixed elevation
QVector3D intersectionPoint;
QgsRayCastingUtils::Ray3D ray = QgsRayCastingUtils::rayForViewportAndCamera( mViewport.size(), QPointF( mViewport.width() / 2., mViewport.height() / 2. ), QRectF( 0.0, 0.0, 1.0, 1.0 ), mCamera );
if ( mTerrainEntity->rayIntersection( ray, intersectionPoint ) )
{
float dist = ( intersectionPoint - mCamera->position() ).length();
mCameraData.dist = dist;
mCameraData.x = intersectionPoint.x();
mCameraData.y = intersectionPoint.z();
mCameraData.elev = intersectionPoint.y();
mCameraData.setCamera( mCamera );
}
}

emit cameraChanged();
}
}
@@ -25,6 +25,7 @@
class QDomDocument;
class QDomElement;

class QgsTerrainEntity;
class QgsVector3D;

/**
@@ -48,9 +49,11 @@ class _3D_EXPORT QgsCameraController : public Qt3DCore::QEntity

/**
* 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
* This allows camera controller understand how far from the camera is the terrain under mouse cursor.
* Also it allows adjustment of camera's view center to a point on terrain.
*/
void addTerrainPicker( Qt3DRender::QObjectPicker *picker );
void setTerrainEntity( QgsTerrainEntity *te );

//! 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.
@@ -95,6 +98,8 @@ class _3D_EXPORT QgsCameraController : public Qt3DCore::QEntity
//! height of terrain when mouse button was last pressed - for camera control
float mLastPressedHeight = 0;

QPointer<QgsTerrainEntity> mTerrainEntity;

struct CameraData
{
float x = 0, y = 0, elev = 0; // ground point towards which the camera is looking
@@ -302,7 +302,7 @@ static QRect windowViewport( const QSize &area, const QRectF &relativeViewport )
return relativeViewport.toRect();
}

static QgsRayCastingUtils::Ray3D intersectionRay( const QPoint &pos, const QMatrix4x4 &viewMatrix,
static QgsRayCastingUtils::Ray3D intersectionRay( const QPointF &pos, const QMatrix4x4 &viewMatrix,
const QMatrix4x4 &projectionMatrix, const QRect &viewport )
{
QVector3D nearPos = QVector3D( pos.x(), pos.y(), 0.0f );
@@ -320,7 +320,7 @@ namespace QgsRayCastingUtils
{

Ray3D rayForViewportAndCamera( const QSize &area,
const QPoint &pos,
const QPointF &pos,
const QRectF &relativeViewport,
const Qt3DRender::QCamera *camera )
{
@@ -330,7 +330,7 @@ namespace QgsRayCastingUtils
const QRect viewport = windowViewport( area, relativeViewport );

// In GL the y is inverted compared to Qt
const QPoint glCorrectPos = QPoint( pos.x(), area.isValid() ? area.height() - pos.y() : pos.y() );
const QPointF glCorrectPos = QPointF( pos.x(), area.isValid() ? area.height() - pos.y() : pos.y() );
const auto ray = intersectionRay( glCorrectPos, viewMatrix, projectionMatrix, viewport );
return ray;
}
@@ -109,7 +109,7 @@ namespace QgsRayCastingUtils
* \since QGIS 3.4
*/
Ray3D rayForViewportAndCamera( const QSize &area,
const QPoint &pos,
const QPointF &pos,
const QRectF &relativeViewport,
const Qt3DRender::QCamera *camera );
}
@@ -60,6 +60,7 @@ Qgs3DMapConfigWidget::Qgs3DMapConfigWidget( Qgs3DMapSettings *map, QgsMapCanvas
chkShowLabels->setChecked( mMap->showLabels() );
chkShowTileInfo->setChecked( mMap->showTerrainTilesInfo() );
chkShowBoundingBoxes->setChecked( mMap->showTerrainBoundingBoxes() );
chkShowCameraViewCenter->setChecked( mMap->showCameraViewCenter() );

connect( cboTerrainLayer, static_cast<void ( QComboBox::* )( int )>( &QgsMapLayerComboBox::currentIndexChanged ), this, &Qgs3DMapConfigWidget::onTerrainLayerChanged );
connect( spinMapResolution, static_cast<void ( QSpinBox::* )( int )>( &QSpinBox::valueChanged ), this, &Qgs3DMapConfigWidget::updateMaxZoomLevel );
@@ -125,6 +126,7 @@ void Qgs3DMapConfigWidget::apply()
mMap->setShowLabels( chkShowLabels->isChecked() );
mMap->setShowTerrainTilesInfo( chkShowTileInfo->isChecked() );
mMap->setShowTerrainBoundingBoxes( chkShowBoundingBoxes->isChecked() );
mMap->setShowCameraViewCenter( chkShowCameraViewCenter->isChecked() );
}

void Qgs3DMapConfigWidget::onTerrainLayerChanged()
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>691</width>
<height>775</height>
<height>830</height>
</rect>
</property>
<property name="windowTitle">
@@ -186,6 +186,13 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="chkShowCameraViewCenter">
<property name="text">
<string>Show camera's view center</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">

0 comments on commit 255aa9e

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