Skip to content

Commit ce93338

Browse files
committed
Initial work on animation support
- new class to store animation configuration - new class for animation configuration GUI - animation implementation using Qt3D Animation framework
1 parent 059d0e2 commit ce93338

10 files changed

+489
-1
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ IF(WITH_CORE)
315315
FIND_PACKAGE(Qt53DInput REQUIRED)
316316
FIND_PACKAGE(Qt53DLogic REQUIRED)
317317
FIND_PACKAGE(Qt53DExtras REQUIRED)
318+
FIND_PACKAGE(Qt53DAnimation REQUIRED)
318319
SET(HAVE_3D TRUE) # used in qgsconfig.h
319320
ENDIF (WITH_3D)
320321
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)
138+
TARGET_LINK_LIBRARIES(qgis_3d Qt5::3DCore Qt5::3DRender Qt5::3DInput Qt5::3DLogic Qt5::3DExtras Qt5::3DAnimation)
139139

140140
GENERATE_EXPORT_HEADER(
141141
qgis_3d

src/app/3d/qgs3danimationsettings.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/***************************************************************************
2+
qgs3danimationsettings.cpp
3+
--------------------------------------
4+
Date : July 2018
5+
Copyright : (C) 2018 by Martin Dobias
6+
Email : wonder dot sk at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#include "qgs3danimationsettings.h"
17+
18+
#include <Qt3DAnimation/QKeyframeAnimation>
19+
#include <Qt3DAnimation/QAnimationGroup>
20+
21+
Qgs3DAnimationSettings::Qgs3DAnimationSettings()
22+
{
23+
24+
}
25+
26+
float Qgs3DAnimationSettings::duration() const
27+
{
28+
return mKeyframes.isEmpty() ? 0 : mKeyframes.constLast().time;
29+
}
30+
31+
Qt3DAnimation::QKeyframeAnimation *Qgs3DAnimationSettings::createAnimation( Qt3DCore::QNode *parent ) const
32+
{
33+
Qt3DAnimation::QKeyframeAnimation *animation = new Qt3DAnimation::QKeyframeAnimation;
34+
35+
QVector<float> framePositions;
36+
QVector<Qt3DCore::QTransform *> transforms;
37+
for ( const Keyframe &keyframe : mKeyframes )
38+
{
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;
44+
}
45+
46+
animation->setKeyframes( transforms );
47+
animation->setFramePositions( framePositions );
48+
49+
//animation->setTarget(cam->transform());
50+
// animation->setEasing(QEasingCurve(QEasingCurve::InOutQuad));
51+
52+
return animation;
53+
}

src/app/3d/qgs3danimationsettings.h

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/***************************************************************************
2+
qgs3danimationsettings.h
3+
--------------------------------------
4+
Date : July 2018
5+
Copyright : (C) 2018 by Martin Dobias
6+
Email : wonder dot sk at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#ifndef QGS3DANIMATIONSETTINGS_H
17+
#define QGS3DANIMATIONSETTINGS_H
18+
19+
#include <QVector3D>
20+
#include <QQuaternion>
21+
22+
namespace Qt3DCore
23+
{
24+
class QNode;
25+
}
26+
27+
namespace Qt3DAnimation
28+
{
29+
class QKeyframeAnimation;
30+
}
31+
32+
/**
33+
* Class that holds information about animation in 3D view. The animation is defined
34+
* as a series of keyframes
35+
*/
36+
class Qgs3DAnimationSettings
37+
{
38+
public:
39+
Qgs3DAnimationSettings();
40+
41+
//! keyframe definition
42+
struct Keyframe
43+
{
44+
float time; //!< Relative time of the keyframe in seconds
45+
QVector3D position; //!< Position of the camera
46+
QQuaternion rotation; //!< Rotation of the camera
47+
};
48+
49+
typedef QVector<Keyframe> Keyframes;
50+
51+
void setKeyframes( const Keyframes &keyframes ) { mKeyframes = keyframes; }
52+
Keyframes keyFrames() const { return mKeyframes; }
53+
54+
//! Returns duration of the whole animation in seconds
55+
float duration() const;
56+
57+
//! Returns a new object that contains Qt3D animation according to the keyframes
58+
Qt3DAnimation::QKeyframeAnimation *createAnimation( Qt3DCore::QNode *parent ) const;
59+
60+
// TODO: read/write routines
61+
62+
private:
63+
Keyframes mKeyframes;
64+
};
65+
66+
#endif // QGS3DANIMATIONSETTINGS_H

src/app/3d/qgs3danimationwidget.cpp

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
/***************************************************************************
2+
qgs3danimationwidget.cpp
3+
--------------------------------------
4+
Date : July 2018
5+
Copyright : (C) 2018 by Martin Dobias
6+
Email : wonder dot sk at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#include "qgs3danimationwidget.h"
17+
18+
#include "qgs3danimationsettings.h"
19+
#include "qgsapplication.h"
20+
21+
#include <Qt3DAnimation/QAnimationController>
22+
#include <Qt3DRender/QCamera>
23+
#include <QTimer>
24+
25+
Qgs3DAnimationWidget::Qgs3DAnimationWidget( QWidget *parent )
26+
: QWidget( parent )
27+
{
28+
setupUi( this );
29+
30+
btnAddKeyframe->setIcon( QIcon( QgsApplication::iconPath( "symbologyAdd.svg" ) ) );
31+
btnRemoveKeyframe->setIcon( QIcon( QgsApplication::iconPath( "symbologyRemove.svg" ) ) );
32+
btnEditKeyframe->setIcon( QIcon( QgsApplication::iconPath( "symbologyEdit.svg" ) ) );
33+
btnPlayPause->setIcon( QIcon( QgsApplication::iconPath( "mTaskRunning.svg" ) ) );
34+
35+
cboKeyframe->addItem( tr( "<none>" ) );
36+
37+
mAnimationTimer = new QTimer( this );
38+
mAnimationTimer->setInterval( 10 );
39+
connect( mAnimationTimer, &QTimer::timeout, this, &Qgs3DAnimationWidget::onAnimationTimer );
40+
41+
mAnimationController = new Qt3DAnimation::QAnimationController( this );
42+
43+
btnPlayPause->setCheckable( true );
44+
connect( btnPlayPause, &QToolButton::clicked, this, &Qgs3DAnimationWidget::onPlayPause );
45+
46+
connect( sliderTime, &QSlider::valueChanged, this, &Qgs3DAnimationWidget::onSliderValueChanged );
47+
48+
connect( cboKeyframe, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, &Qgs3DAnimationWidget::onKeyframeChanged );
49+
}
50+
51+
void Qgs3DAnimationWidget::setCamera( Qt3DRender::QCamera *camera )
52+
{
53+
mCamera = camera;
54+
connect( mCamera, &Qt3DRender::QCamera::viewMatrixChanged, this, &Qgs3DAnimationWidget::onCameraViewMatrixChanged );
55+
}
56+
57+
void Qgs3DAnimationWidget::setAnimation( const Qgs3DAnimationSettings &animSettings )
58+
{
59+
// initialize GUI from the given animation
60+
cboKeyframe->clear();
61+
cboKeyframe->addItem( tr( "<none>" ) );
62+
for ( const Qgs3DAnimationSettings::Keyframe &keyframe : animSettings.keyFrames() )
63+
{
64+
cboKeyframe->addItem( QString( "%1 s" ).arg( keyframe.time ) );
65+
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 );
69+
}
70+
71+
initializeController( animSettings );
72+
}
73+
74+
void Qgs3DAnimationWidget::initializeController( const Qgs3DAnimationSettings &animSettings )
75+
{
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
86+
87+
sliderTime->setMaximum( animSettings.duration() * 100 );
88+
}
89+
90+
Qgs3DAnimationSettings Qgs3DAnimationWidget::animation() const
91+
{
92+
Qgs3DAnimationSettings animSettings;
93+
Qgs3DAnimationSettings::Keyframes keyframes;
94+
qDebug() << "---";
95+
for ( int i = 1; i < cboKeyframe->count(); ++i )
96+
{
97+
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>();
101+
keyframes << kf;
102+
qDebug() << "keyframe" << kf.time << kf.position << kf.rotation;
103+
}
104+
animSettings.setKeyframes( keyframes );
105+
return animSettings;
106+
}
107+
108+
void Qgs3DAnimationWidget::setDefaultAnimation()
109+
{
110+
Qgs3DAnimationSettings animSettings;
111+
Qgs3DAnimationSettings::Keyframes kf;
112+
Qgs3DAnimationSettings::Keyframe f1, f2;
113+
f1.time = 0;
114+
f1.position = mCamera->transform()->translation();
115+
f1.rotation = mCamera->transform()->rotation();
116+
f2.time = 5;
117+
f2.position = f1.position + QVector3D( 0, 0, f1.position.z() / 2 );
118+
f2.rotation = f1.rotation;
119+
kf << f1 << f2;
120+
animSettings.setKeyframes( kf );
121+
122+
setAnimation( animSettings );
123+
}
124+
125+
void Qgs3DAnimationWidget::onPlayPause()
126+
{
127+
if ( mAnimationTimer->isActive() )
128+
{
129+
mAnimationTimer->stop();
130+
cboKeyframe->setEnabled( true );
131+
}
132+
else
133+
{
134+
cboKeyframe->setCurrentIndex( 0 ); // unset active keyframe
135+
cboKeyframe->setEnabled( false );
136+
mAnimationTimer->start();
137+
}
138+
}
139+
140+
void Qgs3DAnimationWidget::onAnimationTimer()
141+
{
142+
float duration = sliderTime->maximum();
143+
sliderTime->setValue( sliderTime->value() >= duration ? 0 : sliderTime->value() + 1 );
144+
}
145+
146+
void Qgs3DAnimationWidget::onSliderValueChanged()
147+
{
148+
mAnimationController->setPosition( sliderTime->value() / 100. );
149+
}
150+
151+
void Qgs3DAnimationWidget::onCameraViewMatrixChanged()
152+
{
153+
if ( cboKeyframe->currentIndex() <= 0 )
154+
return;
155+
156+
// update keyframe's camera position/rotation
157+
int i = cboKeyframe->currentIndex();
158+
cboKeyframe->setItemData( i, mCamera->transform()->translation(), Qt::UserRole + 2 );
159+
cboKeyframe->setItemData( i, mCamera->transform()->rotation(), Qt::UserRole + 3 );
160+
161+
initializeController( animation() );
162+
}
163+
164+
void Qgs3DAnimationWidget::onKeyframeChanged()
165+
{
166+
if ( cboKeyframe->currentIndex() <= 0 )
167+
return;
168+
169+
// jump to the camera view of the keyframe
170+
float time = cboKeyframe->itemData( cboKeyframe->currentIndex(), Qt::UserRole + 1 ).toFloat();
171+
sliderTime->setValue( time * 100 );
172+
}

src/app/3d/qgs3danimationwidget.h

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/***************************************************************************
2+
qgs3danimationwidget.h
3+
--------------------------------------
4+
Date : July 2018
5+
Copyright : (C) 2018 by Martin Dobias
6+
Email : wonder dot sk at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#ifndef QGS3DANIMATIONWIDGET_H
17+
#define QGS3DANIMATIONWIDGET_H
18+
19+
#include <QWidget>
20+
21+
#include "ui_animation3dwidget.h"
22+
23+
namespace Qt3DRender
24+
{
25+
class QCamera;
26+
}
27+
namespace Qt3DAnimation
28+
{
29+
class QAnimationController;
30+
}
31+
32+
class Qgs3DAnimationSettings;
33+
34+
class Qgs3DAnimationWidget : public QWidget, private Ui::Animation3DWidget
35+
{
36+
Q_OBJECT
37+
public:
38+
explicit Qgs3DAnimationWidget( QWidget *parent = nullptr );
39+
40+
void setCamera( Qt3DRender::QCamera *camera );
41+
42+
void setAnimation( const Qgs3DAnimationSettings &animation );
43+
Qgs3DAnimationSettings animation() const;
44+
45+
void setDefaultAnimation();
46+
47+
signals:
48+
49+
private slots:
50+
void onPlayPause();
51+
void onAnimationTimer();
52+
void onSliderValueChanged();
53+
void onCameraViewMatrixChanged();
54+
void onKeyframeChanged();
55+
56+
private:
57+
void initializeController( const Qgs3DAnimationSettings &animSettings );
58+
59+
private:
60+
QTimer *mAnimationTimer = nullptr;
61+
Qt3DAnimation::QAnimationController *mAnimationController = nullptr;
62+
Qt3DRender::QCamera *mCamera = nullptr; //!< Camera (not owned)
63+
};
64+
65+
#endif // QGS3DANIMATIONWIDGET_H

0 commit comments

Comments
 (0)