From 6b5b272cd755a0f79561780433b44d1584702747 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 18 Dec 2015 09:52:11 -0800 Subject: [PATCH] Added SoftAttachmentModel class. Is a subclass of Model, it overrides the updateClusterMatrices so it will pull the actual joint matrices from a different rig override. For the avatar soft attachment system, this override will be the Avatar::_skeletonModel rig. This will give us the ability for an avatar to "wear" non-rigid attachments, such as clothing. --- interface/src/avatar/SoftAttachmentModel.cpp | 83 ++++++++++++++++++++ interface/src/avatar/SoftAttachmentModel.h | 34 ++++++++ libraries/animation/src/Rig.cpp | 8 ++ libraries/animation/src/Rig.h | 1 + libraries/render-utils/src/Model.cpp | 3 + libraries/render-utils/src/Model.h | 5 +- 6 files changed, 131 insertions(+), 3 deletions(-) create mode 100644 interface/src/avatar/SoftAttachmentModel.cpp create mode 100644 interface/src/avatar/SoftAttachmentModel.h diff --git a/interface/src/avatar/SoftAttachmentModel.cpp b/interface/src/avatar/SoftAttachmentModel.cpp new file mode 100644 index 0000000000..a9f6b300ac --- /dev/null +++ b/interface/src/avatar/SoftAttachmentModel.cpp @@ -0,0 +1,83 @@ +// +// SoftAttachmentModel.cpp +// interface/src/avatar +// +// Created by Anthony J. Thibault on 12/17/15. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "SoftAttachmentModel.h" + +SoftAttachmentModel::SoftAttachmentModel(RigPointer rig, QObject* parent, RigPointer rigOverride) : + Model(rig, parent), + _rigOverride(rigOverride) { + assert(_rig); + assert(_rigOverride); +} + +SoftAttachmentModel::~SoftAttachmentModel() { +} + +// virtual +void SoftAttachmentModel::updateRig(float deltaTime, glm::mat4 parentTransform) { + _needsUpdateClusterMatrices = true; +} + +int SoftAttachmentModel::getJointIndexOverride(int i) const { + QString name = _rig->nameOfJoint(i); + if (name.isEmpty()) { + return -1; + } + return _rigOverride->indexOfJoint(name); +} + +// virtual +// use the _rigOverride matrices instead of the Model::_rig +void SoftAttachmentModel::updateClusterMatrices(glm::vec3 modelPosition, glm::quat modelOrientation) { + if (!_needsUpdateClusterMatrices) { + return; + } + _needsUpdateClusterMatrices = false; + + const FBXGeometry& geometry = _geometry->getFBXGeometry(); + + glm::mat4 modelToWorld = glm::mat4_cast(modelOrientation); + for (int i = 0; i < _meshStates.size(); i++) { + MeshState& state = _meshStates[i]; + const FBXMesh& mesh = geometry.meshes.at(i); + + for (int j = 0; j < mesh.clusters.size(); j++) { + const FBXCluster& cluster = mesh.clusters.at(j); + + // TODO: cache these look ups as an optimization + int jointIndexOverride = getJointIndexOverride(cluster.jointIndex); + glm::mat4 jointMatrix(glm::mat4::_null); + if (jointIndexOverride >= 0 && jointIndexOverride < getJointStateCount()) { + jointMatrix = _rigOverride->getJointTransform(jointIndexOverride); + } else { + jointMatrix = _rig->getJointTransform(cluster.jointIndex); + } + state.clusterMatrices[j] = modelToWorld * jointMatrix * cluster.inverseBindMatrix; + } + + // Once computed the cluster matrices, update the buffer(s) + if (mesh.clusters.size() > 1) { + if (!state.clusterBuffer) { + state.clusterBuffer = std::make_shared(state.clusterMatrices.size() * sizeof(glm::mat4), + (const gpu::Byte*) state.clusterMatrices.constData()); + } else { + state.clusterBuffer->setSubData(0, state.clusterMatrices.size() * sizeof(glm::mat4), + (const gpu::Byte*) state.clusterMatrices.constData()); + } + } + } + + // post the blender if we're not currently waiting for one to finish + if (geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) { + _blendedBlendshapeCoefficients = _blendshapeCoefficients; + DependencyManager::get()->noteRequiresBlend(this); + } +} diff --git a/interface/src/avatar/SoftAttachmentModel.h b/interface/src/avatar/SoftAttachmentModel.h new file mode 100644 index 0000000000..eda587af68 --- /dev/null +++ b/interface/src/avatar/SoftAttachmentModel.h @@ -0,0 +1,34 @@ +// +// SoftAttachmentModel.h +// interface/src/avatar +// +// Created by Anthony J. Thibault on 12/17/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_SoftAttachmentModel_h +#define hifi_SoftAttachmentModel_h + +#include + +class SoftAttachmentModel : public Model { + Q_OBJECT + +public: + + SoftAttachmentModel(RigPointer rig, QObject* parent, RigPointer rigOverride); + ~SoftAttachmentModel(); + + virtual void updateRig(float deltaTime, glm::mat4 parentTransform) override; + virtual void updateClusterMatrices(glm::vec3 modelPosition, glm::quat modelOrientation) override; + +protected: + int getJointIndexOverride(int i) const; + + RigPointer _rigOverride; +}; + +#endif // hifi_SoftAttachmentModel_h diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 68f382d2d9..bfd4888961 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -245,6 +245,14 @@ int Rig::indexOfJoint(const QString& jointName) const { } } +QString Rig::nameOfJoint(int jointIndex) const { + if (_animSkeleton) { + return _animSkeleton->getJointName(jointIndex); + } else { + return ""; + } +} + void Rig::setModelOffset(const glm::mat4& modelOffsetMat) { AnimPose newModelOffset = AnimPose(modelOffsetMat); if (!isEqual(_modelOffset.trans, newModelOffset.trans) || diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 9faf93e40b..669af2ea64 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -91,6 +91,7 @@ public: bool jointStatesEmpty(); int getJointStateCount() const; int indexOfJoint(const QString& jointName) const; + QString nameOfJoint(int jointIndex) const; void setModelOffset(const glm::mat4& modelOffsetMat); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index dbd3a6289f..efaa79ddbb 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -971,11 +971,14 @@ void Model::updateRig(float deltaTime, glm::mat4 parentTransform) { _needsUpdateClusterMatrices = true; _rig->updateAnimations(deltaTime, parentTransform); } + void Model::simulateInternal(float deltaTime) { // update the world space transforms for all joints glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset); updateRig(deltaTime, parentTransform); } + +// virtual void Model::updateClusterMatrices(glm::vec3 modelPosition, glm::quat modelOrientation) { PerformanceTimer perfTimer("Model::updateClusterMatrices"); diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index a93338e41a..3416a9b71e 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -112,7 +112,7 @@ public: bool getSnapModelToRegistrationPoint() { return _snapModelToRegistrationPoint; } virtual void simulate(float deltaTime, bool fullUpdate = true); - void updateClusterMatrices(glm::vec3 modelPosition, glm::quat modelOrientation); + virtual void updateClusterMatrices(glm::vec3 modelPosition, glm::quat modelOrientation); /// Returns a reference to the shared geometry. const QSharedPointer& getGeometry() const { return _geometry; } @@ -312,7 +312,7 @@ protected: // hook for derived classes to be notified when setUrl invalidates the current model. virtual void onInvalidate() {}; -private: +protected: void deleteGeometry(); void initJointTransforms(); @@ -370,7 +370,6 @@ private: bool _showCollisionHull = false; friend class ModelMeshPartPayload; -protected: RigPointer _rig; };