Skip to content

Commit

Permalink
qgs3daxis: Define only only one viewport in the framegraph
Browse files Browse the repository at this point in the history
The axis framegraph has two distinct branches : one for the main
object (the axis or the cube) and one for the axis labels. Each of
those branches have a dedicated viewport. However, only one viewport
is needed since the two branches need the same part of the
window.

With this change, the first node of the axis' framegraph is now the
viewport (mViewport) and the two branches inherit from it:

- viewport
  <-- object branch -->
  - layerfilter (axisLayerFilter)
  - cameraselector
  - sortPolicy
  - clearBuffers

  <-- labels branch -->
  - layerfilter (twoDLayerFilter)
  - cameraselector
  - sortPolicy
  - clearBuffers

`from3DTo2DLabelPosition()` is also simplified to compute the
billboard position of the axis labels. Indeed, the viewport of the
labels had the dimensions of the main window (0, 0, 1, 1) while the
objects viewport has only the dimensions the relevant part of the
window. Therefore, `from3DTo2DLabelPosition()` needed to take into
this into account and recenter the computer coordinates. This is not
needed anymore.
  • Loading branch information
ptitjano authored and nyalldawson committed Jun 27, 2024
1 parent 642df95 commit 7fcc94d
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 74 deletions.
90 changes: 28 additions & 62 deletions src/3d/qgs3daxis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,10 @@ Qgs3DAxis::Qgs3DAxis( Qgs3DMapCanvas *canvas,
, mCameraController( cameraCtrl )
, mCrs( map->crs() )
{
mAxisViewport = constructAxisViewport( parent3DScene );
mAxisViewport->setParent( mCanvas->activeFrameGraph() );
mViewport = constructAxisScene( parent3DScene );
mViewport->setParent( mCanvas->activeFrameGraph() );

mTwoDLabelViewport = constructLabelViewport( parent3DScene, QRectF( 0.0f, 0.0f, 1.0f, 1.0f ) );
mTwoDLabelViewport->setParent( mCanvas->activeFrameGraph() );
constructLabelsScene( parent3DScene );

connect( cameraCtrl, &QgsCameraController::cameraChanged, this, &Qgs3DAxis::onCameraUpdate );
connect( mCanvas, &Qgs3DMapCanvas::widthChanged, this, &Qgs3DAxis::onAxisViewportSizeUpdate );
Expand Down Expand Up @@ -142,11 +141,11 @@ bool Qgs3DAxis::eventFilter( QObject *watched, QEvent *event )
if ( 2 <= QgsLogger::debugLevel() && event->type() == QEvent::MouseButtonRelease )
{
std::ostringstream os;
os << "QGS3DAxis: normalized pos: " << normalizedPos << " / viewport: " << mAxisViewport->normalizedRect();
os << "QGS3DAxis: normalized pos: " << normalizedPos << " / viewport: " << mViewport->normalizedRect();
QgsDebugMsgLevel( os.str().c_str(), 2 );
}

if ( mAxisViewport->normalizedRect().contains( normalizedPos ) )
if ( mViewport->normalizedRect().contains( normalizedPos ) )
{
mLastClickedButton = mouseEvent->button();
mLastClickedPos = mouseEvent->pos();
Expand Down Expand Up @@ -286,7 +285,7 @@ void Qgs3DAxis::onTouchedByRay( const Qt3DRender::QAbstractRayCaster::Hits &hits
}
}

Qt3DRender::QViewport *Qgs3DAxis::constructAxisViewport( Qt3DCore::QEntity *parent3DScene )
Qt3DRender::QViewport *Qgs3DAxis::constructAxisScene( Qt3DCore::QEntity *parent3DScene )
{
Qt3DRender::QViewport *axisViewport = new Qt3DRender::QViewport;
// parent will be set later
Expand Down Expand Up @@ -331,23 +330,16 @@ Qt3DRender::QViewport *Qgs3DAxis::constructAxisViewport( Qt3DCore::QEntity *pare
return axisViewport;
}

Qt3DRender::QViewport *Qgs3DAxis::constructLabelViewport( Qt3DCore::QEntity *parent3DScene, const QRectF &parentViewportSize )
void Qgs3DAxis::constructLabelsScene( Qt3DCore::QEntity *parent3DScene )
{
Qt3DRender::QViewport *twoDViewport = new Qt3DRender::QViewport;
// parent will be set later
twoDViewport->setNormalizedRect( parentViewportSize );

mTwoDLabelSceneEntity = new Qt3DCore::QEntity;
mTwoDLabelSceneEntity->setParent( parent3DScene );
mTwoDLabelSceneEntity->setEnabled( true );

mTwoDLabelCamera = new Qt3DRender::QCamera;
mTwoDLabelCamera->setParent( mTwoDLabelSceneEntity );
mTwoDLabelCamera->setProjectionType( Qt3DRender::QCameraLens::ProjectionType::OrthographicProjection );
mTwoDLabelCamera->lens()->setOrthographicProjection(
-mCanvas->width() / 2.0f, mCanvas->width() / 2.0f,
-mCanvas->height() / 2.0f, mCanvas->height() / 2.0f,
-10.0f, 100.0f );
// the camera lens parameters are defined by onAxisViewportSizeUpdate()

mTwoDLabelCamera->setUpVector( QVector3D( 0.0f, 0.0f, 1.0f ) );
mTwoDLabelCamera->setViewCenter( QVector3D( 0.0f, 0.0f, 0.0f ) );
Expand All @@ -359,7 +351,7 @@ Qt3DRender::QViewport *Qgs3DAxis::constructLabelViewport( Qt3DCore::QEntity *par
twoDLayer->setRecursive( true );
mTwoDLabelSceneEntity->addComponent( twoDLayer );

Qt3DRender::QLayerFilter *twoDLayerFilter = new Qt3DRender::QLayerFilter( twoDViewport );
Qt3DRender::QLayerFilter *twoDLayerFilter = new Qt3DRender::QLayerFilter;
twoDLayerFilter->addLayer( twoDLayer );

Qt3DRender::QCameraSelector *twoDCameraSelector = new Qt3DRender::QCameraSelector;
Expand All @@ -376,40 +368,18 @@ Qt3DRender::QViewport *Qgs3DAxis::constructLabelViewport( Qt3DCore::QEntity *par
Qt3DRender::QClearBuffers *clearBuffers = new Qt3DRender::QClearBuffers( sortPolicy );
clearBuffers->setBuffers( Qt3DRender::QClearBuffers::DepthBuffer );

// cppcheck-suppress memleak
return twoDViewport;
twoDLayerFilter->setParent( mViewport );
}

QVector3D Qgs3DAxis::from3DTo2DLabelPosition( const QVector3D &sourcePos,
Qt3DRender::QCamera *sourceCamera, Qt3DRender::QViewport *sourceViewport,
Qt3DRender::QCamera *destCamera, Qt3DRender::QViewport *destViewport,
const QSize &destSize )
QVector3D Qgs3DAxis::from3DTo2DLabelPosition( const QVector3D &sourcePos, Qt3DRender::QCamera *sourceCamera, Qt3DRender::QCamera *destCamera )
{
QVector3D destPos = sourcePos.project( sourceCamera->viewMatrix(),
destCamera->projectionMatrix(),
QRect( 0.0f, 0.0f,
destViewport->normalizedRect().width() * destSize.width(),
destViewport->normalizedRect().height() * destSize.height() ) );
QPointF axisCenter = sourceViewport->normalizedRect().center();
QPointF labelCenter = destViewport->normalizedRect().center();
QVector3D viewTranslation = QVector3D( ( axisCenter - labelCenter ).x() * destSize.width(),
( axisCenter - labelCenter ).y() * destSize.height(),
0.0f );
destPos -= QVector3D( labelCenter.x() * destSize.width(),
labelCenter.y() * destSize.height(),
0.0f );
destPos.setX( destPos.x() + viewTranslation.x() );
destPos.setY( destPos.y() - viewTranslation.y() );
destPos.setZ( 0.0f );
const int viewportWidth = static_cast<int>( std::round( mTwoDLabelCamera->lens()->right() - mTwoDLabelCamera->lens()->left() ) );
const int viewportHeight = static_cast<int>( std::round( mTwoDLabelCamera->lens()->top() - mTwoDLabelCamera->lens()->bottom() ) );
QRect viewportRect( static_cast<int>( std::round( mTwoDLabelCamera->lens()->left() ) ), static_cast<int>( std::round( mTwoDLabelCamera->lens()->bottom() ) ),
viewportWidth, viewportHeight );

if ( 2 <= QgsLogger::debugLevel() )
{
std::ostringstream os;
os << "Qgs3DAxis::from3DTo2DLabelPosition: sourcePos: " << sourcePos.toPoint()
<< " with translation: " << viewTranslation.toPoint()
<< " corrected to pos: " << destPos.toPoint();
QgsDebugMsgLevel( os.str().c_str(), 2 );
}
QVector3D destPos = sourcePos.project( sourceCamera->viewMatrix(), destCamera->projectionMatrix(), viewportRect );
destPos.setZ( 0.0f );
return destPos;
}

Expand Down Expand Up @@ -1096,7 +1066,7 @@ void Qgs3DAxis::onAxisViewportSizeUpdate( int )
{
QgsDebugMsgLevel( "viewport takes too much place into the 3d view, disabling it", 2 );
// take too much place into the 3d view
mAxisViewport->setEnabled( false );
mViewport->setEnabled( false );
setEnableCube( false );
setEnableAxis( false );
}
Expand All @@ -1106,14 +1076,14 @@ void Qgs3DAxis::onAxisViewportSizeUpdate( int )
mAxisScaleFactor = viewportPixelSize / defaultViewportPixelSize;
QgsDebugMsgLevel( QString( "3DAxis viewport mAxisScaleFactor %1" ).arg( mAxisScaleFactor ), 2 );

if ( ! mAxisViewport->isEnabled() )
if ( ! mViewport->isEnabled() )
{
if ( settings.mode() == Qgs3DAxisSettings::Mode::Crs )
setEnableAxis( true );
else if ( settings.mode() == Qgs3DAxisSettings::Mode::Cube )
setEnableCube( true );
}
mAxisViewport->setEnabled( true );
mViewport->setEnabled( true );

float xRatio = 1.0f;
float yRatio = 1.0f;
Expand All @@ -1132,13 +1102,15 @@ void Qgs3DAxis::onAxisViewportSizeUpdate( int )
yRatio = 1.0f - heightRatio;

QgsDebugMsgLevel( QString( "Qgs3DAxis: update viewport: %1 x %2 x %3 x %4" ).arg( xRatio ).arg( yRatio ).arg( widthRatio ).arg( heightRatio ), 2 );
mAxisViewport->setNormalizedRect( QRectF( xRatio, yRatio, widthRatio, heightRatio ) );
mViewport->setNormalizedRect( QRectF( xRatio, yRatio, widthRatio, heightRatio ) );

if ( settings.mode() == Qgs3DAxisSettings::Mode::Crs )
{
const float halfWidthSize = static_cast<float>( windowWidth * widthRatio / 2.0 );
const float halfHeightSize = static_cast<float>( windowWidth * widthRatio / 2.0 );
mTwoDLabelCamera->lens()->setOrthographicProjection(
-windowWidth / 2.0f, windowWidth / 2.0f,
-windowHeight / 2.0f, windowHeight / 2.0f,
-halfWidthSize, halfWidthSize,
-halfHeightSize, halfHeightSize,
mTwoDLabelCamera->lens()->nearPlane(), mTwoDLabelCamera->lens()->farPlane() );

updateAxisLabelPosition();
Expand Down Expand Up @@ -1182,19 +1154,13 @@ void Qgs3DAxis::updateAxisLabelPosition()
{
if ( mTextTransformX && mTextTransformY && mTextTransformZ )
{
mTextTransformX->setTranslation( from3DTo2DLabelPosition( mTextCoordX * mAxisScaleFactor, mAxisCamera,
mAxisViewport, mTwoDLabelCamera, mTwoDLabelViewport,
mCanvas->size() ) );
mTextTransformX->setTranslation( from3DTo2DLabelPosition( mTextCoordX * static_cast<float>( mAxisScaleFactor ), mAxisCamera, mTwoDLabelCamera ) );
updateAxisLabelText( mTextX, mTextX->text() );

mTextTransformY->setTranslation( from3DTo2DLabelPosition( mTextCoordY * mAxisScaleFactor, mAxisCamera,
mAxisViewport, mTwoDLabelCamera, mTwoDLabelViewport,
mCanvas->size() ) );
mTextTransformY->setTranslation( from3DTo2DLabelPosition( mTextCoordY * static_cast<float>( mAxisScaleFactor ), mAxisCamera, mTwoDLabelCamera ) );
updateAxisLabelText( mTextY, mTextY->text() );

mTextTransformZ->setTranslation( from3DTo2DLabelPosition( mTextCoordZ * mAxisScaleFactor, mAxisCamera,
mAxisViewport, mTwoDLabelCamera, mTwoDLabelViewport,
mCanvas->size() ) );
mTextTransformZ->setTranslation( from3DTo2DLabelPosition( mTextCoordZ * static_cast<float>( mAxisScaleFactor ), mAxisCamera, mTwoDLabelCamera ) );
updateAxisLabelText( mTextZ, mTextZ->text() );
}
}
Expand Down
19 changes: 7 additions & 12 deletions src/3d/qgs3daxis.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,20 +69,15 @@ class _3D_EXPORT Qgs3DAxis : public QObject
~Qgs3DAxis() override;

/**
* \brief project a 3D position from sourceCamera (in sourceViewport) to a 2D position for destCamera (in destViewport). destCamera and the destViewport act as a billboarding layer. The labels displayed by this process will always face the camera.
* \brief project a 3D position from sourceCamera to a 2D position for destCamera. destCamera acts as a billboarding layer. The labels displayed by this process will always face the camera.
*
* \param sourcePos 3D label coordinates
* @param sourceCamera main view camera
* @param sourceViewport main viewport
* @param destCamera billboarding camera
* @param destViewport billboarding viewport
* @param destSize main qt3d window size
* @return
*/
QVector3D from3DTo2DLabelPosition( const QVector3D &sourcePos,
Qt3DRender::QCamera *sourceCamera, Qt3DRender::QViewport *sourceViewport,
Qt3DRender::QCamera *destCamera, Qt3DRender::QViewport *destViewport,
const QSize &destSize );
QVector3D from3DTo2DLabelPosition( const QVector3D &sourcePos, Qt3DRender::QCamera *sourceCamera, Qt3DRender::QCamera *destCamera );


public slots:

Expand Down Expand Up @@ -121,8 +116,8 @@ class _3D_EXPORT Qgs3DAxis : public QObject
void updateAxisLabelText( Qt3DExtras::QText2DEntity *textEntity, const QString &text );
QFont createFont( int pointSize );

Qt3DRender::QViewport *constructAxisViewport( Qt3DCore::QEntity *parent3DScene );
Qt3DRender::QViewport *constructLabelViewport( Qt3DCore::QEntity *parent3DScene, const QRectF &parentViewportSize );
Qt3DRender::QViewport *constructAxisScene( Qt3DCore::QEntity *parent3DScene );
void constructLabelsScene( Qt3DCore::QEntity *parent3DScene );

Qt3DExtras::QText2DEntity *addCubeText( const QString &text, float textHeight, float textWidth, const QFont &font, const QMatrix4x4 &rotation, const QVector3D &translation );

Expand All @@ -142,10 +137,11 @@ class _3D_EXPORT Qgs3DAxis : public QObject
float mCylinderLength = 40.0f;
int mFontSize = 12;

Qt3DRender::QViewport *mViewport = nullptr;

Qt3DCore::QEntity *mAxisSceneEntity = nullptr;
Qt3DRender::QLayer *mAxisObjectLayer = nullptr;
Qt3DRender::QCamera *mAxisCamera = nullptr;
Qt3DRender::QViewport *mAxisViewport = nullptr;

Qt3DCore::QEntity *mAxisRoot = nullptr;
Qt3DCore::QEntity *mCubeRoot = nullptr;
Expand All @@ -166,7 +162,6 @@ class _3D_EXPORT Qgs3DAxis : public QObject

Qt3DRender::QCamera *mTwoDLabelCamera = nullptr;
Qt3DCore::QEntity *mTwoDLabelSceneEntity = nullptr;
Qt3DRender::QViewport *mTwoDLabelViewport = nullptr;

// axis picking and menu
Qt3DRender::QScreenRayCaster *mScreenRayCaster = nullptr;
Expand Down

0 comments on commit 7fcc94d

Please sign in to comment.