Skip to content

Commit 2f6b569

Browse files
committedJul 8, 2018
Animate in cooperation with QgsCameraController
This is cleaner than just updating QCamera's transform. Now we interpolate values ourselves, without Qt3D Animation library.
1 parent ce93338 commit 2f6b569

10 files changed

+114
-73
lines changed
 

‎CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,6 @@ IF(WITH_CORE)
315315
FIND_PACKAGE(Qt53DInput REQUIRED)
316316
FIND_PACKAGE(Qt53DLogic REQUIRED)
317317
FIND_PACKAGE(Qt53DExtras REQUIRED)
318-
FIND_PACKAGE(Qt53DAnimation REQUIRED)
319318
SET(HAVE_3D TRUE) # used in qgsconfig.h
320319
ENDIF (WITH_3D)
321320
INCLUDE("cmake/modules/ECMQt4To5Porting.cmake")

‎src/3d/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ INCLUDE_DIRECTORIES(SYSTEM
135135

136136
ADD_LIBRARY(qgis_3d SHARED ${QGIS_3D_SRCS} ${QGIS_3D_MOC_SRCS} ${QGIS_3D_HDRS} ${QGIS_3D_RCC_SRCS})
137137

138-
TARGET_LINK_LIBRARIES(qgis_3d Qt5::3DCore Qt5::3DRender Qt5::3DInput Qt5::3DLogic Qt5::3DExtras Qt5::3DAnimation)
138+
TARGET_LINK_LIBRARIES(qgis_3d Qt5::3DCore Qt5::3DRender Qt5::3DInput Qt5::3DLogic Qt5::3DExtras)
139139

140140
GENERATE_EXPORT_HEADER(
141141
qgis_3d

‎src/3d/qgscameracontroller.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ void QgsCameraController::setViewFromTop( float worldX, float worldY, float dist
403403

404404
QgsVector3D QgsCameraController::lookingAtPoint() const
405405
{
406-
return QgsVector3D( mCameraData.x, 0, mCameraData.y );
406+
return QgsVector3D( mCameraData.x, mCameraData.elev, mCameraData.y );
407407
}
408408

409409
void QgsCameraController::setLookingAtPoint( const QgsVector3D &point, float dist )
@@ -414,6 +414,12 @@ void QgsCameraController::setLookingAtPoint( const QgsVector3D &point, float dis
414414
emit cameraChanged();
415415
}
416416

417+
void QgsCameraController::setLookingAtPoint( const QgsVector3D &point, float distance, float pitch, float yaw )
418+
{
419+
setCameraData( point.x(), point.z(), point.y(), distance, pitch, yaw );
420+
emit cameraChanged();
421+
}
422+
417423
QDomElement QgsCameraController::writeXml( QDomDocument &doc ) const
418424
{
419425
QDomElement elemCamera = doc.createElement( "camera" );

‎src/3d/qgscameracontroller.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,12 @@ class _3D_EXPORT QgsCameraController : public Qt3DCore::QEntity
7272
//! Sets the point toward which the camera is looking - this is used when world origin changes (e.g. after terrain generator changes)
7373
void setLookingAtPoint( const QgsVector3D &point, float distance = -1 );
7474

75+
void setLookingAtPoint( const QgsVector3D &point, float distance, float pitch, float yaw );
76+
77+
float distance() const { return mCameraData.dist; }
78+
float pitch() const { return mCameraData.pitch; }
79+
float yaw() const { return mCameraData.yaw; }
80+
7581
//! Writes camera configuration to the given DOM element
7682
QDomElement writeXml( QDomDocument &doc ) const;
7783
//! Reads camera configuration from the given DOM element

‎src/app/3d/qgs3danimationsettings.cpp

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,39 +15,64 @@
1515

1616
#include "qgs3danimationsettings.h"
1717

18-
#include <Qt3DAnimation/QKeyframeAnimation>
19-
#include <Qt3DAnimation/QAnimationGroup>
18+
#include <QEasingCurve>
2019

2120
Qgs3DAnimationSettings::Qgs3DAnimationSettings()
2221
{
23-
2422
}
2523

2624
float Qgs3DAnimationSettings::duration() const
2725
{
2826
return mKeyframes.isEmpty() ? 0 : mKeyframes.constLast().time;
2927
}
3028

31-
Qt3DAnimation::QKeyframeAnimation *Qgs3DAnimationSettings::createAnimation( Qt3DCore::QNode *parent ) const
29+
Qgs3DAnimationSettings::Keyframe Qgs3DAnimationSettings::interpolate( float time ) const
3230
{
33-
Qt3DAnimation::QKeyframeAnimation *animation = new Qt3DAnimation::QKeyframeAnimation;
31+
Q_ASSERT( !mKeyframes.isEmpty() );
3432

35-
QVector<float> framePositions;
36-
QVector<Qt3DCore::QTransform *> transforms;
37-
for ( const Keyframe &keyframe : mKeyframes )
33+
if ( time < 0 )
34+
{
35+
return mKeyframes.first();
36+
}
37+
else if ( time >= duration() )
3838
{
39-
framePositions << keyframe.time;
40-
Qt3DCore::QTransform *t = new Qt3DCore::QTransform( parent );
41-
t->setTranslation( keyframe.position );
42-
t->setRotation( keyframe.rotation );
43-
transforms << t;
39+
return mKeyframes.last();
4440
}
41+
else
42+
{
43+
for ( int i = 0; i < mKeyframes.size() - 1; i++ )
44+
{
45+
const Keyframe &k0 = mKeyframes.at( i );
46+
const Keyframe &k1 = mKeyframes.at( i + 1 );
47+
if ( time >= k0.time && time < k1.time )
48+
{
49+
float ip = ( time - k0.time ) / ( k1.time - k0.time );
50+
float eIp = QEasingCurve( QEasingCurve::InOutQuad ).valueForProgress( ip );
51+
float eIip = 1.0f - eIp;
4552

46-
animation->setKeyframes( transforms );
47-
animation->setFramePositions( framePositions );
53+
Keyframe kf;
54+
kf.time = time;
55+
kf.point.set( k0.point.x() * eIip + k1.point.x() * eIp,
56+
k0.point.y() * eIip + k1.point.y() * eIp,
57+
k0.point.z() * eIip + k1.point.z() * eIp );
58+
kf.dist = k0.dist * eIip + k1.dist * eIp;
59+
kf.pitch = k0.pitch * eIip + k1.pitch * eIp;
4860

49-
//animation->setTarget(cam->transform());
50-
// animation->setEasing(QEasingCurve(QEasingCurve::InOutQuad));
61+
// always use shorter angle
62+
float yaw0 = fmod( k0.yaw, 360 ), yaw1 = fmod( k1.yaw, 360 );
63+
if ( std::abs( yaw0 - yaw1 ) > 180 )
64+
{
65+
if ( yaw0 < yaw1 )
66+
yaw0 += 360;
67+
else
68+
yaw1 += 360;
69+
}
5170

52-
return animation;
71+
kf.yaw = yaw0 * eIip + yaw1 * eIp;
72+
return kf;
73+
}
74+
}
75+
}
76+
Q_ASSERT( false );
77+
return Keyframe();
5378
}

‎src/app/3d/qgs3danimationsettings.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include <QVector3D>
2020
#include <QQuaternion>
21+
#include "qgsvector3d.h"
2122

2223
namespace Qt3DCore
2324
{
@@ -42,8 +43,11 @@ class Qgs3DAnimationSettings
4243
struct Keyframe
4344
{
4445
float time; //!< Relative time of the keyframe in seconds
45-
QVector3D position; //!< Position of the camera
46-
QQuaternion rotation; //!< Rotation of the camera
46+
47+
QgsVector3D point; //!< Point towards which the camera is looking in 3D world coords
48+
float dist; //!< Distance of the camera from the focal point
49+
float pitch; //!< Tilt of the camera in degrees (0 = looking from the top, 90 = looking from the side, 180 = looking from the bottom)
50+
float yaw; //!< Horizontal rotation around the focal point in degrees
4751
};
4852

4953
typedef QVector<Keyframe> Keyframes;
@@ -54,13 +58,15 @@ class Qgs3DAnimationSettings
5458
//! Returns duration of the whole animation in seconds
5559
float duration() const;
5660

57-
//! Returns a new object that contains Qt3D animation according to the keyframes
58-
Qt3DAnimation::QKeyframeAnimation *createAnimation( Qt3DCore::QNode *parent ) const;
61+
//! Interpolates camera position and rotation at the given point in time
62+
Keyframe interpolate( float time ) const;
5963

6064
// TODO: read/write routines
6165

6266
private:
6367
Keyframes mKeyframes;
6468
};
6569

70+
Q_DECLARE_METATYPE( Qgs3DAnimationSettings::Keyframe )
71+
6672
#endif // QGS3DANIMATIONSETTINGS_H

‎src/app/3d/qgs3danimationwidget.cpp

Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717

1818
#include "qgs3danimationsettings.h"
1919
#include "qgsapplication.h"
20+
#include "qgscameracontroller.h"
2021

21-
#include <Qt3DAnimation/QAnimationController>
2222
#include <Qt3DRender/QCamera>
2323
#include <QTimer>
2424

@@ -38,8 +38,6 @@ Qgs3DAnimationWidget::Qgs3DAnimationWidget( QWidget *parent )
3838
mAnimationTimer->setInterval( 10 );
3939
connect( mAnimationTimer, &QTimer::timeout, this, &Qgs3DAnimationWidget::onAnimationTimer );
4040

41-
mAnimationController = new Qt3DAnimation::QAnimationController( this );
42-
4341
btnPlayPause->setCheckable( true );
4442
connect( btnPlayPause, &QToolButton::clicked, this, &Qgs3DAnimationWidget::onPlayPause );
4543

@@ -48,12 +46,16 @@ Qgs3DAnimationWidget::Qgs3DAnimationWidget( QWidget *parent )
4846
connect( cboKeyframe, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, &Qgs3DAnimationWidget::onKeyframeChanged );
4947
}
5048

51-
void Qgs3DAnimationWidget::setCamera( Qt3DRender::QCamera *camera )
49+
Qgs3DAnimationWidget::~Qgs3DAnimationWidget() = default;
50+
51+
52+
void Qgs3DAnimationWidget::setCameraController( QgsCameraController *cameraController )
5253
{
53-
mCamera = camera;
54-
connect( mCamera, &Qt3DRender::QCamera::viewMatrixChanged, this, &Qgs3DAnimationWidget::onCameraViewMatrixChanged );
54+
mCameraController = cameraController;
55+
connect( mCameraController, &QgsCameraController::cameraChanged, this, &Qgs3DAnimationWidget::onCameraChanged );
5556
}
5657

58+
5759
void Qgs3DAnimationWidget::setAnimation( const Qgs3DAnimationSettings &animSettings )
5860
{
5961
// initialize GUI from the given animation
@@ -63,26 +65,15 @@ void Qgs3DAnimationWidget::setAnimation( const Qgs3DAnimationSettings &animSetti
6365
{
6466
cboKeyframe->addItem( QString( "%1 s" ).arg( keyframe.time ) );
6567
int lastIndex = cboKeyframe->count() - 1;
66-
cboKeyframe->setItemData( lastIndex, keyframe.time, Qt::UserRole + 1 );
67-
cboKeyframe->setItemData( lastIndex, keyframe.position, Qt::UserRole + 2 );
68-
cboKeyframe->setItemData( lastIndex, keyframe.rotation, Qt::UserRole + 3 );
68+
cboKeyframe->setItemData( lastIndex, QVariant::fromValue<Qgs3DAnimationSettings::Keyframe>( keyframe ), Qt::UserRole + 1 );
6969
}
7070

7171
initializeController( animSettings );
7272
}
7373

7474
void Qgs3DAnimationWidget::initializeController( const Qgs3DAnimationSettings &animSettings )
7575
{
76-
// set up animation in the controller
77-
Qt3DAnimation::QAnimationGroup *group = new Qt3DAnimation::QAnimationGroup;
78-
Qt3DAnimation::QKeyframeAnimation *animation = animSettings.createAnimation( nullptr ); // TODO: who deletes transforms?
79-
animation->setParent( group );
80-
animation->setTarget( mCamera->transform() );
81-
group->addAnimation( animation ); // does not delete animations later
82-
83-
QVector<Qt3DAnimation::QAnimationGroup *> groups;
84-
groups << group;
85-
mAnimationController->setAnimationGroups( groups ); // does not delete groups later
76+
mAnimationSettings.reset( new Qgs3DAnimationSettings( animSettings ) );
8677

8778
sliderTime->setMaximum( animSettings.duration() * 100 );
8879
}
@@ -91,15 +82,11 @@ Qgs3DAnimationSettings Qgs3DAnimationWidget::animation() const
9182
{
9283
Qgs3DAnimationSettings animSettings;
9384
Qgs3DAnimationSettings::Keyframes keyframes;
94-
qDebug() << "---";
9585
for ( int i = 1; i < cboKeyframe->count(); ++i )
9686
{
9787
Qgs3DAnimationSettings::Keyframe kf;
98-
kf.time = cboKeyframe->itemData( i, Qt::UserRole + 1 ).toFloat();
99-
kf.position = cboKeyframe->itemData( i, Qt::UserRole + 2 ).value<QVector3D>();
100-
kf.rotation = cboKeyframe->itemData( i, Qt::UserRole + 3 ).value<QQuaternion>();
88+
kf = cboKeyframe->itemData( i, Qt::UserRole + 1 ).value<Qgs3DAnimationSettings::Keyframe>();
10189
keyframes << kf;
102-
qDebug() << "keyframe" << kf.time << kf.position << kf.rotation;
10390
}
10491
animSettings.setKeyframes( keyframes );
10592
return animSettings;
@@ -111,11 +98,17 @@ void Qgs3DAnimationWidget::setDefaultAnimation()
11198
Qgs3DAnimationSettings::Keyframes kf;
11299
Qgs3DAnimationSettings::Keyframe f1, f2;
113100
f1.time = 0;
114-
f1.position = mCamera->transform()->translation();
115-
f1.rotation = mCamera->transform()->rotation();
101+
f1.point = mCameraController->lookingAtPoint();
102+
f1.dist = mCameraController->distance();
103+
f1.pitch = mCameraController->pitch();
104+
f1.yaw = mCameraController->yaw();
105+
116106
f2.time = 5;
117-
f2.position = f1.position + QVector3D( 0, 0, f1.position.z() / 2 );
118-
f2.rotation = f1.rotation;
107+
f2.point = f1.point;
108+
f2.dist = f1.dist * 2;
109+
f2.pitch = f1.pitch;
110+
f2.yaw = f1.yaw;
111+
119112
kf << f1 << f2;
120113
animSettings.setKeyframes( kf );
121114

@@ -143,20 +136,30 @@ void Qgs3DAnimationWidget::onAnimationTimer()
143136
sliderTime->setValue( sliderTime->value() >= duration ? 0 : sliderTime->value() + 1 );
144137
}
145138

139+
146140
void Qgs3DAnimationWidget::onSliderValueChanged()
147141
{
148-
mAnimationController->setPosition( sliderTime->value() / 100. );
142+
// make sure we do not have an active keyframe
143+
if ( cboKeyframe->currentIndex() != 0 )
144+
cboKeyframe->setCurrentIndex( 0 );
145+
146+
Qgs3DAnimationSettings::Keyframe kf = mAnimationSettings->interpolate( sliderTime->value() / 100. );
147+
mCameraController->setLookingAtPoint( kf.point, kf.dist, kf.pitch, kf.yaw );
149148
}
150149

151-
void Qgs3DAnimationWidget::onCameraViewMatrixChanged()
150+
void Qgs3DAnimationWidget::onCameraChanged()
152151
{
153152
if ( cboKeyframe->currentIndex() <= 0 )
154153
return;
155154

156155
// update keyframe's camera position/rotation
157156
int i = cboKeyframe->currentIndex();
158-
cboKeyframe->setItemData( i, mCamera->transform()->translation(), Qt::UserRole + 2 );
159-
cboKeyframe->setItemData( i, mCamera->transform()->rotation(), Qt::UserRole + 3 );
157+
Qgs3DAnimationSettings::Keyframe kf = cboKeyframe->itemData( i, Qt::UserRole + 1 ).value<Qgs3DAnimationSettings::Keyframe>();
158+
kf.point = mCameraController->lookingAtPoint();
159+
kf.dist = mCameraController->distance();
160+
kf.pitch = mCameraController->pitch();
161+
kf.yaw = mCameraController->yaw();
162+
cboKeyframe->setItemData( i, QVariant::fromValue<Qgs3DAnimationSettings::Keyframe>( kf ), Qt::UserRole + 1 );
160163

161164
initializeController( animation() );
162165
}
@@ -167,6 +170,8 @@ void Qgs3DAnimationWidget::onKeyframeChanged()
167170
return;
168171

169172
// jump to the camera view of the keyframe
170-
float time = cboKeyframe->itemData( cboKeyframe->currentIndex(), Qt::UserRole + 1 ).toFloat();
171-
sliderTime->setValue( time * 100 );
173+
Qgs3DAnimationSettings::Keyframe kf = cboKeyframe->itemData( cboKeyframe->currentIndex(), Qt::UserRole + 1 ).value<Qgs3DAnimationSettings::Keyframe>();
174+
175+
whileBlocking( sliderTime )->setValue( kf.time * 100 );
176+
mCameraController->setLookingAtPoint( kf.point, kf.dist, kf.pitch, kf.yaw );
172177
}

‎src/app/3d/qgs3danimationwidget.h

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,27 +17,22 @@
1717
#define QGS3DANIMATIONWIDGET_H
1818

1919
#include <QWidget>
20+
#include <memory>
2021

2122
#include "ui_animation3dwidget.h"
2223

23-
namespace Qt3DRender
24-
{
25-
class QCamera;
26-
}
27-
namespace Qt3DAnimation
28-
{
29-
class QAnimationController;
30-
}
3124

3225
class Qgs3DAnimationSettings;
26+
class QgsCameraController;
3327

3428
class Qgs3DAnimationWidget : public QWidget, private Ui::Animation3DWidget
3529
{
3630
Q_OBJECT
3731
public:
3832
explicit Qgs3DAnimationWidget( QWidget *parent = nullptr );
33+
~Qgs3DAnimationWidget();
3934

40-
void setCamera( Qt3DRender::QCamera *camera );
35+
void setCameraController( QgsCameraController *cameraController );
4136

4237
void setAnimation( const Qgs3DAnimationSettings &animation );
4338
Qgs3DAnimationSettings animation() const;
@@ -50,16 +45,16 @@ class Qgs3DAnimationWidget : public QWidget, private Ui::Animation3DWidget
5045
void onPlayPause();
5146
void onAnimationTimer();
5247
void onSliderValueChanged();
53-
void onCameraViewMatrixChanged();
48+
void onCameraChanged();
5449
void onKeyframeChanged();
5550

5651
private:
5752
void initializeController( const Qgs3DAnimationSettings &animSettings );
5853

5954
private:
55+
std::unique_ptr<Qgs3DAnimationSettings> mAnimationSettings;
56+
QgsCameraController *mCameraController;
6057
QTimer *mAnimationTimer = nullptr;
61-
Qt3DAnimation::QAnimationController *mAnimationController = nullptr;
62-
Qt3DRender::QCamera *mCamera = nullptr; //!< Camera (not owned)
6358
};
6459

6560
#endif // QGS3DANIMATIONWIDGET_H

‎src/app/3d/qgs3dmapcanvasdockwidget.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ void Qgs3DMapCanvasDockWidget::setMapSettings( Qgs3DMapSettings *map )
123123

124124
connect( mCanvas->scene(), &Qgs3DMapScene::terrainPendingJobsCountChanged, this, &Qgs3DMapCanvasDockWidget::onTerrainPendingJobsCountChanged );
125125

126-
mAnimationWidget->setCamera( mCanvas->scene()->cameraController()->camera() );
126+
mAnimationWidget->setCameraController( mCanvas->scene()->cameraController() );
127127
}
128128

129129
void Qgs3DMapCanvasDockWidget::setMainCanvas( QgsMapCanvas *canvas )

‎src/app/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -763,7 +763,6 @@ ENDIF(ENABLE_MODELTEST)
763763
IF (WITH_3D)
764764
TARGET_LINK_LIBRARIES(qgis_app
765765
qgis_3d
766-
Qt5::3DAnimation
767766
)
768767
ENDIF (WITH_3D)
769768

0 commit comments

Comments
 (0)
Please sign in to comment.