Skip to content

Commit a45ecfa

Browse files
dvdkonwonder-sk
authored andcommitted
Fix camera rotation in 3D globe view
1 parent ac9f54a commit a45ecfa

File tree

1 file changed

+44
-20
lines changed

1 file changed

+44
-20
lines changed

src/3d/qgscameracontroller.cpp

Lines changed: 44 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <Qt3DRender/QCamera>
2828
#include <Qt3DInput>
2929
#include <QStringLiteral>
30+
#include <QQuaternion>
3031
#include <cmath>
3132

3233
#include "qgslogger.h"
@@ -104,30 +105,53 @@ void QgsCameraController::setVerticalAxisInversion( Qgis::VerticalAxisInversion
104105

105106
void QgsCameraController::rotateCamera( float diffPitch, float diffHeading )
106107
{
107-
const float oldPitch = mCameraPose.pitchAngle();
108-
const float oldHeading = mCameraPose.headingAngle();
109-
float newPitch = oldPitch + diffPitch;
110-
float newHeading = oldHeading + diffHeading;
108+
float newPitch = mCameraPose.pitchAngle() + diffPitch;
109+
float newHeading = mCameraPose.headingAngle() + diffHeading;
111110

112111
newPitch = std::clamp( newPitch, 0.f, 180.f ); // prevent going over the head
113112

114-
// First undo the previously applied rotation, then apply the new rotation
115-
// (We can't just apply our euler angles difference because the camera may be already rotated)
116-
const QQuaternion qNew = Qgs3DUtils::rotationFromPitchHeadingAngles( newPitch, newHeading );
117-
const QQuaternion qOld = Qgs3DUtils::rotationFromPitchHeadingAngles( oldPitch, oldHeading );
118-
const QQuaternion q = qNew * qOld.conjugated();
119-
120-
// get camera's view vector, rotate it to get new view center
121-
const QVector3D position = mCamera->position();
122-
QVector3D viewCenter = mCamera->viewCenter();
123-
const QVector3D viewVector = viewCenter - position;
124-
const QVector3D cameraToCenter = q * viewVector;
125-
viewCenter = position + cameraToCenter;
113+
switch ( mScene->mapSettings()->sceneMode() )
114+
{
115+
case Qgis::SceneMode::Globe:
116+
{
117+
// When on a globe, we need to calculate "where is up" (the normal of a tangent plane).
118+
// Also it uses different axes than the standard plane-based view.
119+
// See QgsCameraPose::updateCameraGlobe(), we basically want to make sure
120+
// that after an update, the camera stays in the same spot.
121+
QgsVector3D viewCenterLatLon;
122+
try
123+
{
124+
viewCenterLatLon = mGlobeCrsToLatLon.transform( mCameraPose.centerPoint() + mOrigin );
125+
}
126+
catch ( const QgsCsException & )
127+
{
128+
QgsDebugError( QStringLiteral( "rotateCamera: ECEF -> lat,lon transform failed!" ) );
129+
return;
130+
}
131+
QQuaternion qLatLon = QQuaternion::fromAxisAndAngle( QVector3D( 0, 0, 1 ), static_cast<float>( viewCenterLatLon.x() ) )
132+
* QQuaternion::fromAxisAndAngle( QVector3D( 0, -1, 0 ), static_cast<float>( viewCenterLatLon.y() ) );
133+
QQuaternion qPitchHeading = QQuaternion::fromAxisAndAngle( QVector3D( 1, 0, 0 ), newHeading )
134+
* QQuaternion::fromAxisAndAngle( QVector3D( 0, 1, 0 ), newPitch );
135+
QVector3D newCameraToCenter = ( qLatLon * qPitchHeading * QVector3D( -1, 0, 0 ) ) * mCameraPose.distanceFromCenterPoint();
136+
137+
mCameraPose.setCenterPoint( mCamera->position() + newCameraToCenter );
138+
mCameraPose.setPitchAngle( newPitch );
139+
mCameraPose.setHeadingAngle( newHeading );
140+
updateCameraFromPose();
141+
return;
142+
}
126143

127-
mCameraPose.setCenterPoint( viewCenter );
128-
mCameraPose.setPitchAngle( newPitch );
129-
mCameraPose.setHeadingAngle( newHeading );
130-
updateCameraFromPose();
144+
case Qgis::SceneMode::Local:
145+
{
146+
QQuaternion q = Qgs3DUtils::rotationFromPitchHeadingAngles( newPitch, newHeading );
147+
QVector3D newCameraToCenter = q * QVector3D( 0, 0, -mCameraPose.distanceFromCenterPoint() );
148+
mCameraPose.setCenterPoint( mCamera->position() + newCameraToCenter );
149+
mCameraPose.setPitchAngle( newPitch );
150+
mCameraPose.setHeadingAngle( newHeading );
151+
updateCameraFromPose();
152+
return;
153+
}
154+
}
131155
}
132156

133157
void QgsCameraController::rotateCameraAroundPivot( float newPitch, float newHeading, const QVector3D &pivotPoint )

0 commit comments

Comments
 (0)