Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Initial work on animation support
- new class to store animation configuration - new class for animation configuration GUI - animation implementation using Qt3D Animation framework
- Loading branch information
Showing
with
489 additions
and 1 deletion.
- +1 −0 CMakeLists.txt
- +1 −1 src/3d/CMakeLists.txt
- +53 −0 src/app/3d/qgs3danimationsettings.cpp
- +66 −0 src/app/3d/qgs3danimationsettings.h
- +172 −0 src/app/3d/qgs3danimationwidget.cpp
- +65 −0 src/app/3d/qgs3danimationwidget.h
- +28 −0 src/app/3d/qgs3dmapcanvasdockwidget.cpp
- +3 −0 src/app/3d/qgs3dmapcanvasdockwidget.h
- +4 −0 src/app/CMakeLists.txt
- +96 −0 src/ui/3d/animation3dwidget.ui
@@ -0,0 +1,53 @@ | ||
/*************************************************************************** | ||
qgs3danimationsettings.cpp | ||
-------------------------------------- | ||
Date : July 2018 | ||
Copyright : (C) 2018 by Martin Dobias | ||
Email : wonder dot sk at gmail dot com | ||
*************************************************************************** | ||
* * | ||
* This program is free software; you can redistribute it and/or modify * | ||
* it under the terms of the GNU General Public License as published by * | ||
* the Free Software Foundation; either version 2 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
***************************************************************************/ | ||
|
||
#include "qgs3danimationsettings.h" | ||
|
||
#include <Qt3DAnimation/QKeyframeAnimation> | ||
#include <Qt3DAnimation/QAnimationGroup> | ||
|
||
Qgs3DAnimationSettings::Qgs3DAnimationSettings() | ||
{ | ||
|
||
} | ||
|
||
float Qgs3DAnimationSettings::duration() const | ||
{ | ||
return mKeyframes.isEmpty() ? 0 : mKeyframes.constLast().time; | ||
} | ||
|
||
Qt3DAnimation::QKeyframeAnimation *Qgs3DAnimationSettings::createAnimation( Qt3DCore::QNode *parent ) const | ||
{ | ||
Qt3DAnimation::QKeyframeAnimation *animation = new Qt3DAnimation::QKeyframeAnimation; | ||
|
||
QVector<float> framePositions; | ||
QVector<Qt3DCore::QTransform *> transforms; | ||
for ( const Keyframe &keyframe : mKeyframes ) | ||
{ | ||
framePositions << keyframe.time; | ||
Qt3DCore::QTransform *t = new Qt3DCore::QTransform( parent ); | ||
t->setTranslation( keyframe.position ); | ||
t->setRotation( keyframe.rotation ); | ||
transforms << t; | ||
} | ||
|
||
animation->setKeyframes( transforms ); | ||
animation->setFramePositions( framePositions ); | ||
|
||
//animation->setTarget(cam->transform()); | ||
// animation->setEasing(QEasingCurve(QEasingCurve::InOutQuad)); | ||
|
||
return animation; | ||
} |
@@ -0,0 +1,66 @@ | ||
/*************************************************************************** | ||
qgs3danimationsettings.h | ||
-------------------------------------- | ||
Date : July 2018 | ||
Copyright : (C) 2018 by Martin Dobias | ||
Email : wonder dot sk at gmail dot com | ||
*************************************************************************** | ||
* * | ||
* This program is free software; you can redistribute it and/or modify * | ||
* it under the terms of the GNU General Public License as published by * | ||
* the Free Software Foundation; either version 2 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
***************************************************************************/ | ||
|
||
#ifndef QGS3DANIMATIONSETTINGS_H | ||
#define QGS3DANIMATIONSETTINGS_H | ||
|
||
#include <QVector3D> | ||
#include <QQuaternion> | ||
|
||
namespace Qt3DCore | ||
{ | ||
class QNode; | ||
} | ||
|
||
namespace Qt3DAnimation | ||
{ | ||
class QKeyframeAnimation; | ||
} | ||
|
||
/** | ||
* Class that holds information about animation in 3D view. The animation is defined | ||
* as a series of keyframes | ||
*/ | ||
class Qgs3DAnimationSettings | ||
{ | ||
public: | ||
Qgs3DAnimationSettings(); | ||
|
||
//! keyframe definition | ||
struct Keyframe | ||
{ | ||
float time; //!< Relative time of the keyframe in seconds | ||
QVector3D position; //!< Position of the camera | ||
QQuaternion rotation; //!< Rotation of the camera | ||
}; | ||
|
||
typedef QVector<Keyframe> Keyframes; | ||
|
||
void setKeyframes( const Keyframes &keyframes ) { mKeyframes = keyframes; } | ||
Keyframes keyFrames() const { return mKeyframes; } | ||
|
||
//! Returns duration of the whole animation in seconds | ||
float duration() const; | ||
|
||
//! Returns a new object that contains Qt3D animation according to the keyframes | ||
Qt3DAnimation::QKeyframeAnimation *createAnimation( Qt3DCore::QNode *parent ) const; | ||
|
||
// TODO: read/write routines | ||
|
||
private: | ||
Keyframes mKeyframes; | ||
}; | ||
|
||
#endif // QGS3DANIMATIONSETTINGS_H |
@@ -0,0 +1,172 @@ | ||
/*************************************************************************** | ||
qgs3danimationwidget.cpp | ||
-------------------------------------- | ||
Date : July 2018 | ||
Copyright : (C) 2018 by Martin Dobias | ||
Email : wonder dot sk at gmail dot com | ||
*************************************************************************** | ||
* * | ||
* This program is free software; you can redistribute it and/or modify * | ||
* it under the terms of the GNU General Public License as published by * | ||
* the Free Software Foundation; either version 2 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
***************************************************************************/ | ||
|
||
#include "qgs3danimationwidget.h" | ||
|
||
#include "qgs3danimationsettings.h" | ||
#include "qgsapplication.h" | ||
|
||
#include <Qt3DAnimation/QAnimationController> | ||
#include <Qt3DRender/QCamera> | ||
#include <QTimer> | ||
|
||
Qgs3DAnimationWidget::Qgs3DAnimationWidget( QWidget *parent ) | ||
: QWidget( parent ) | ||
{ | ||
setupUi( this ); | ||
|
||
btnAddKeyframe->setIcon( QIcon( QgsApplication::iconPath( "symbologyAdd.svg" ) ) ); | ||
btnRemoveKeyframe->setIcon( QIcon( QgsApplication::iconPath( "symbologyRemove.svg" ) ) ); | ||
btnEditKeyframe->setIcon( QIcon( QgsApplication::iconPath( "symbologyEdit.svg" ) ) ); | ||
btnPlayPause->setIcon( QIcon( QgsApplication::iconPath( "mTaskRunning.svg" ) ) ); | ||
|
||
cboKeyframe->addItem( tr( "<none>" ) ); | ||
|
||
mAnimationTimer = new QTimer( this ); | ||
mAnimationTimer->setInterval( 10 ); | ||
connect( mAnimationTimer, &QTimer::timeout, this, &Qgs3DAnimationWidget::onAnimationTimer ); | ||
|
||
mAnimationController = new Qt3DAnimation::QAnimationController( this ); | ||
|
||
btnPlayPause->setCheckable( true ); | ||
connect( btnPlayPause, &QToolButton::clicked, this, &Qgs3DAnimationWidget::onPlayPause ); | ||
|
||
connect( sliderTime, &QSlider::valueChanged, this, &Qgs3DAnimationWidget::onSliderValueChanged ); | ||
|
||
connect( cboKeyframe, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, &Qgs3DAnimationWidget::onKeyframeChanged ); | ||
} | ||
|
||
void Qgs3DAnimationWidget::setCamera( Qt3DRender::QCamera *camera ) | ||
{ | ||
mCamera = camera; | ||
connect( mCamera, &Qt3DRender::QCamera::viewMatrixChanged, this, &Qgs3DAnimationWidget::onCameraViewMatrixChanged ); | ||
} | ||
|
||
void Qgs3DAnimationWidget::setAnimation( const Qgs3DAnimationSettings &animSettings ) | ||
{ | ||
// initialize GUI from the given animation | ||
cboKeyframe->clear(); | ||
cboKeyframe->addItem( tr( "<none>" ) ); | ||
for ( const Qgs3DAnimationSettings::Keyframe &keyframe : animSettings.keyFrames() ) | ||
{ | ||
cboKeyframe->addItem( QString( "%1 s" ).arg( keyframe.time ) ); | ||
int lastIndex = cboKeyframe->count() - 1; | ||
cboKeyframe->setItemData( lastIndex, keyframe.time, Qt::UserRole + 1 ); | ||
cboKeyframe->setItemData( lastIndex, keyframe.position, Qt::UserRole + 2 ); | ||
cboKeyframe->setItemData( lastIndex, keyframe.rotation, Qt::UserRole + 3 ); | ||
} | ||
|
||
initializeController( animSettings ); | ||
} | ||
|
||
void Qgs3DAnimationWidget::initializeController( const Qgs3DAnimationSettings &animSettings ) | ||
{ | ||
// set up animation in the controller | ||
Qt3DAnimation::QAnimationGroup *group = new Qt3DAnimation::QAnimationGroup; | ||
Qt3DAnimation::QKeyframeAnimation *animation = animSettings.createAnimation( nullptr ); // TODO: who deletes transforms? | ||
animation->setParent( group ); | ||
animation->setTarget( mCamera->transform() ); | ||
group->addAnimation( animation ); // does not delete animations later | ||
|
||
QVector<Qt3DAnimation::QAnimationGroup *> groups; | ||
groups << group; | ||
mAnimationController->setAnimationGroups( groups ); // does not delete groups later | ||
|
||
sliderTime->setMaximum( animSettings.duration() * 100 ); | ||
} | ||
|
||
Qgs3DAnimationSettings Qgs3DAnimationWidget::animation() const | ||
{ | ||
Qgs3DAnimationSettings animSettings; | ||
Qgs3DAnimationSettings::Keyframes keyframes; | ||
qDebug() << "---"; | ||
for ( int i = 1; i < cboKeyframe->count(); ++i ) | ||
{ | ||
Qgs3DAnimationSettings::Keyframe kf; | ||
kf.time = cboKeyframe->itemData( i, Qt::UserRole + 1 ).toFloat(); | ||
kf.position = cboKeyframe->itemData( i, Qt::UserRole + 2 ).value<QVector3D>(); | ||
kf.rotation = cboKeyframe->itemData( i, Qt::UserRole + 3 ).value<QQuaternion>(); | ||
keyframes << kf; | ||
qDebug() << "keyframe" << kf.time << kf.position << kf.rotation; | ||
} | ||
animSettings.setKeyframes( keyframes ); | ||
return animSettings; | ||
} | ||
|
||
void Qgs3DAnimationWidget::setDefaultAnimation() | ||
{ | ||
Qgs3DAnimationSettings animSettings; | ||
Qgs3DAnimationSettings::Keyframes kf; | ||
Qgs3DAnimationSettings::Keyframe f1, f2; | ||
f1.time = 0; | ||
f1.position = mCamera->transform()->translation(); | ||
f1.rotation = mCamera->transform()->rotation(); | ||
f2.time = 5; | ||
f2.position = f1.position + QVector3D( 0, 0, f1.position.z() / 2 ); | ||
f2.rotation = f1.rotation; | ||
kf << f1 << f2; | ||
animSettings.setKeyframes( kf ); | ||
|
||
setAnimation( animSettings ); | ||
} | ||
|
||
void Qgs3DAnimationWidget::onPlayPause() | ||
{ | ||
if ( mAnimationTimer->isActive() ) | ||
{ | ||
mAnimationTimer->stop(); | ||
cboKeyframe->setEnabled( true ); | ||
} | ||
else | ||
{ | ||
cboKeyframe->setCurrentIndex( 0 ); // unset active keyframe | ||
cboKeyframe->setEnabled( false ); | ||
mAnimationTimer->start(); | ||
} | ||
} | ||
|
||
void Qgs3DAnimationWidget::onAnimationTimer() | ||
{ | ||
float duration = sliderTime->maximum(); | ||
sliderTime->setValue( sliderTime->value() >= duration ? 0 : sliderTime->value() + 1 ); | ||
} | ||
|
||
void Qgs3DAnimationWidget::onSliderValueChanged() | ||
{ | ||
mAnimationController->setPosition( sliderTime->value() / 100. ); | ||
} | ||
|
||
void Qgs3DAnimationWidget::onCameraViewMatrixChanged() | ||
{ | ||
if ( cboKeyframe->currentIndex() <= 0 ) | ||
return; | ||
|
||
// update keyframe's camera position/rotation | ||
int i = cboKeyframe->currentIndex(); | ||
cboKeyframe->setItemData( i, mCamera->transform()->translation(), Qt::UserRole + 2 ); | ||
cboKeyframe->setItemData( i, mCamera->transform()->rotation(), Qt::UserRole + 3 ); | ||
|
||
initializeController( animation() ); | ||
} | ||
|
||
void Qgs3DAnimationWidget::onKeyframeChanged() | ||
{ | ||
if ( cboKeyframe->currentIndex() <= 0 ) | ||
return; | ||
|
||
// jump to the camera view of the keyframe | ||
float time = cboKeyframe->itemData( cboKeyframe->currentIndex(), Qt::UserRole + 1 ).toFloat(); | ||
sliderTime->setValue( time * 100 ); | ||
} |
@@ -0,0 +1,65 @@ | ||
/*************************************************************************** | ||
qgs3danimationwidget.h | ||
-------------------------------------- | ||
Date : July 2018 | ||
Copyright : (C) 2018 by Martin Dobias | ||
Email : wonder dot sk at gmail dot com | ||
*************************************************************************** | ||
* * | ||
* This program is free software; you can redistribute it and/or modify * | ||
* it under the terms of the GNU General Public License as published by * | ||
* the Free Software Foundation; either version 2 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
***************************************************************************/ | ||
|
||
#ifndef QGS3DANIMATIONWIDGET_H | ||
#define QGS3DANIMATIONWIDGET_H | ||
|
||
#include <QWidget> | ||
|
||
#include "ui_animation3dwidget.h" | ||
|
||
namespace Qt3DRender | ||
{ | ||
class QCamera; | ||
} | ||
namespace Qt3DAnimation | ||
{ | ||
class QAnimationController; | ||
} | ||
|
||
class Qgs3DAnimationSettings; | ||
|
||
class Qgs3DAnimationWidget : public QWidget, private Ui::Animation3DWidget | ||
{ | ||
Q_OBJECT | ||
public: | ||
explicit Qgs3DAnimationWidget( QWidget *parent = nullptr ); | ||
|
||
void setCamera( Qt3DRender::QCamera *camera ); | ||
|
||
void setAnimation( const Qgs3DAnimationSettings &animation ); | ||
Qgs3DAnimationSettings animation() const; | ||
|
||
void setDefaultAnimation(); | ||
|
||
signals: | ||
|
||
private slots: | ||
void onPlayPause(); | ||
void onAnimationTimer(); | ||
void onSliderValueChanged(); | ||
void onCameraViewMatrixChanged(); | ||
void onKeyframeChanged(); | ||
|
||
private: | ||
void initializeController( const Qgs3DAnimationSettings &animSettings ); | ||
|
||
private: | ||
QTimer *mAnimationTimer = nullptr; | ||
Qt3DAnimation::QAnimationController *mAnimationController = nullptr; | ||
Qt3DRender::QCamera *mCamera = nullptr; //!< Camera (not owned) | ||
}; | ||
|
||
#endif // QGS3DANIMATIONWIDGET_H |
Oops, something went wrong.