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.
This commit is contained in:
Anthony J. Thibault 2015-12-18 09:52:11 -08:00
parent 1bb6ddb99f
commit 6b5b272cd7
6 changed files with 131 additions and 3 deletions

View file

@ -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<gpu::Buffer>(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<ModelBlender>()->noteRequiresBlend(this);
}
}

View file

@ -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 <Model.h>
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

View file

@ -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) ||

View file

@ -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);

View file

@ -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");

View file

@ -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<NetworkGeometry>& 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;
};