summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean Harmer <sean.harmer@kdab.com>2017-08-27 16:12:02 +0100
committerSean Harmer <sean.harmer@kdab.com>2017-10-03 09:01:43 +0000
commit81877f4e463d9da86bc65feade213da5e7226915 (patch)
tree78d963b1d678613ec0710549dd97031e3a6d95ae
parent2ff5f87bc36fa4d5e15b49a31232bed0dbecfe5e (diff)
Update the local poses of the skeleton in the animation aspect
At present it is still needlessly, and incorrectly, updating the transforms of joints for which we have no animation data by using a default value of 0 for each component. This causes the joints to be scaled to 0 which is not particularly useful. We should only update joints for which we have valid animation data and leave the other joints alone. For a skeleton this will be OK as we have the initial set of local poses available. For regular QNode properties, the animator/mapper will need to take a snapshot of the current property value when the animation is started so that we can fill in the missing values when generating property changes. This should also be fixed on the 5.9 branch. Change-Id: Ib8f28c55cdfbca3f335777028f72250641092fc9 Reviewed-by: Paul Lemire <paul.lemire@kdab.com>
-rw-r--r--src/animation/backend/animationutils.cpp49
-rw-r--r--src/animation/backend/animationutils_p.h9
-rw-r--r--src/animation/backend/skeleton.cpp9
-rw-r--r--src/animation/backend/skeleton_p.h17
-rw-r--r--src/animation/frontend/qanimationaspect.cpp1
-rw-r--r--src/core/transforms/sqt_p.h1
6 files changed, 85 insertions, 1 deletions
diff --git a/src/animation/backend/animationutils.cpp b/src/animation/backend/animationutils.cpp
index 83a9a8426..a1224f69a 100644
--- a/src/animation/backend/animationutils.cpp
+++ b/src/animation/backend/animationutils.cpp
@@ -48,6 +48,7 @@
#include <QtGui/qquaternion.h>
#include <QtGui/qcolor.h>
#include <QtCore/qvariant.h>
+#include <QtCore/qvarlengtharray.h>
#include <Qt3DAnimation/private/animationlogging_p.h>
#include <numeric>
@@ -292,13 +293,45 @@ QVector<Qt3DCore::QSceneChangePtr> preparePropertyChanges(Qt3DCore::QNodeId anim
bool finalFrame)
{
QVector<Qt3DCore::QSceneChangePtr> changes;
+ QVarLengthArray<Skeleton *, 4> dirtySkeletons;
+
// Iterate over the mappings
for (const MappingData &mappingData : mappingDataVec) {
if (!mappingData.propertyName)
continue;
+
// Build the new value from the channel/fcurve evaluation results
const QVariant v = buildPropertyValue(mappingData, channelResults);
- if (v.isValid()) {
+ if (!v.isValid())
+ continue;
+
+ // TODO: Avoid wrapping joint transform components up in a variant, just
+ // to immediately unwrap them again. Refactor buildPropertyValue() to call
+ // helper functions that we can call directly here for joints.
+ if (mappingData.skeleton && mappingData.jointIndex != -1) {
+ // Remember that this skeleton is dirty. We will ask each dirty skeleton
+ // to send its set of local poses to observers below.
+ if (!dirtySkeletons.contains(mappingData.skeleton))
+ dirtySkeletons.push_back(mappingData.skeleton);
+
+ switch (mappingData.jointTransformComponent) {
+ case MappingData::Scale:
+ mappingData.skeleton->setJointScale(mappingData.jointIndex, v.value<QVector3D>());
+ break;
+
+ case MappingData::Rotation:
+ mappingData.skeleton->setJointRotation(mappingData.jointIndex, v.value<QQuaternion>());
+ break;
+
+ case MappingData::Translation:
+ mappingData.skeleton->setJointTranslation(mappingData.jointIndex, v.value<QVector3D>());
+ break;
+
+ default:
+ Q_UNREACHABLE();
+ break;
+ }
+ } else {
// Construct a property update change, set target, property and delivery options
auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(mappingData.targetId);
e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
@@ -311,6 +344,8 @@ QVector<Qt3DCore::QSceneChangePtr> preparePropertyChanges(Qt3DCore::QNodeId anim
}
}
+ for (const auto skeleton : dirtySkeletons)
+ skeleton->sendLocalPoses();
// If it's the final frame, notify the frontend that we've stopped
if (finalFrame) {
@@ -415,6 +450,7 @@ QVector<MappingData> buildPropertyMappings(const QVector<ChannelMapping*> &chann
// Populate the data we need, easy stuff first
MappingData mappingData;
mappingData.targetId = mapping->skeletonId();
+ mappingData.skeleton = mapping->skeleton();
const int propertyCount = jointProperties.size();
for (int propertyIndex = 0; propertyIndex < propertyCount; ++propertyIndex) {
@@ -430,6 +466,17 @@ QVector<MappingData> buildPropertyMappings(const QVector<ChannelMapping*> &chann
mappingData.type = nameAndType.type;
mappingData.channelIndices = channelComponentIndices[index];
mappingData.jointIndex = jointIndex;
+
+ // Convert property name for joint transform components to
+ // an enumerated type so we can avoid the string comparisons
+ // when sending the change events after evaluation.
+ if (qstrcmp(mappingData.propertyName, "scale") == 0)
+ mappingData.jointTransformComponent = MappingData::Scale;
+ else if (qstrcmp(mappingData.propertyName, "rotation") == 0)
+ mappingData.jointTransformComponent = MappingData::Rotation;
+ else if (qstrcmp(mappingData.propertyName, "translation") == 0)
+ mappingData.jointTransformComponent = MappingData::Translation;
+
mappingDataVec.push_back(mappingData);
}
}
diff --git a/src/animation/backend/animationutils_p.h b/src/animation/backend/animationutils_p.h
index 5d84f54b0..a225e9311 100644
--- a/src/animation/backend/animationutils_p.h
+++ b/src/animation/backend/animationutils_p.h
@@ -71,8 +71,17 @@ typedef QVector<int> ComponentIndices;
struct MappingData
{
+ enum JointTransformComponent {
+ NoTransformComponent = 0,
+ Scale,
+ Rotation,
+ Translation
+ };
+
Qt3DCore::QNodeId targetId;
+ Skeleton *skeleton = nullptr;
int jointIndex = -1;
+ JointTransformComponent jointTransformComponent = NoTransformComponent;
const char *propertyName;
QAnimationCallback *callback;
QAnimationCallback::Flags callbackFlags;
diff --git a/src/animation/backend/skeleton.cpp b/src/animation/backend/skeleton.cpp
index a920e2473..dcfaf55e7 100644
--- a/src/animation/backend/skeleton.cpp
+++ b/src/animation/backend/skeleton.cpp
@@ -96,6 +96,15 @@ void Skeleton::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
BackendNode::sceneChangeEvent(e);
}
+void Skeleton::sendLocalPoses()
+{
+ auto e = QPropertyUpdatedChangePtr::create(peerId());
+ e->setDeliveryFlags(Qt3DCore::QSceneChange::BackendNodes);
+ e->setPropertyName("localPoses");
+ e->setValue(QVariant::fromValue(m_jointLocalPoses));
+ notifyObservers(e);
+}
+
} // namespace Animation
} // namespace Qt3DAnimation
diff --git a/src/animation/backend/skeleton_p.h b/src/animation/backend/skeleton_p.h
index 19da98261..e26e276d9 100644
--- a/src/animation/backend/skeleton_p.h
+++ b/src/animation/backend/skeleton_p.h
@@ -66,6 +66,23 @@ public:
int jointCount() const { return m_jointLocalPoses.size(); }
+ void setJointScale(int jointIndex, const QVector3D &scale)
+ {
+ m_jointLocalPoses[jointIndex].scale = scale;
+ }
+
+ void setJointRotation(int jointIndex, const QQuaternion &rotation)
+ {
+ m_jointLocalPoses[jointIndex].rotation = rotation;
+ }
+
+ void setJointTranslation(int jointIndex, const QVector3D &translation)
+ {
+ m_jointLocalPoses[jointIndex].translation = translation;
+ }
+
+ void sendLocalPoses();
+
#if defined(QT_BUILD_INTERNAL)
void setJointCount(int jointCount)
{
diff --git a/src/animation/frontend/qanimationaspect.cpp b/src/animation/frontend/qanimationaspect.cpp
index 14a0c4f8c..9b23a7b1d 100644
--- a/src/animation/frontend/qanimationaspect.cpp
+++ b/src/animation/frontend/qanimationaspect.cpp
@@ -95,6 +95,7 @@ QAnimationAspect::QAnimationAspect(QAnimationAspectPrivate &dd, QObject *parent)
Q_D(QAnimationAspect);
qRegisterMetaType<Qt3DAnimation::QAnimationClipLoader*>();
qRegisterMetaType<Qt3DAnimation::QChannelMapper*>();
+ qRegisterMetaType<QVector<Qt3DCore::Sqt>>();
registerBackendType<QAbstractAnimationClip>(
QSharedPointer<Animation::NodeFunctor<Animation::AnimationClip, Animation::AnimationClipLoaderManager>>::create(d->m_handler.data(),
diff --git a/src/core/transforms/sqt_p.h b/src/core/transforms/sqt_p.h
index 262e3a645..5fdefccc8 100644
--- a/src/core/transforms/sqt_p.h
+++ b/src/core/transforms/sqt_p.h
@@ -101,6 +101,7 @@ struct JointNamesAndLocalPoses
QT_END_NAMESPACE
+Q_DECLARE_METATYPE(QVector<Qt3DCore::Sqt>)
Q_DECLARE_METATYPE(Qt3DCore::JointNamesAndLocalPoses)
#endif // QT3DCORE_SQT_P_H