Merge pull request #5 from sethalves/rig

Rig
This commit is contained in:
Howard Stearns 2015-07-23 17:32:41 -05:00
commit 878f7129f4
9 changed files with 137 additions and 140 deletions

View file

@ -103,11 +103,8 @@ MyAvatar::MyAvatar(RigPointer rig) :
_realWorldFieldOfView("realWorldFieldOfView",
DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES),
_rig(rig),
_firstPersonSkeletonModel(this, nullptr, rig),
_prevShouldDrawHead(true)
{
_firstPersonSkeletonModel.setIsFirstPerson(true);
ShapeCollider::initDispatchTable();
for (int i = 0; i < MAX_DRIVE_KEYS; i++) {
_driveKeys[i] = 0.0f;
@ -141,7 +138,6 @@ QByteArray MyAvatar::toByteArray() {
void MyAvatar::reset() {
_skeletonModel.reset();
_firstPersonSkeletonModel.reset();
getHead()->reset();
_targetVelocity = glm::vec3(0.0f);
@ -200,7 +196,6 @@ void MyAvatar::simulate(float deltaTime) {
{
PerformanceTimer perfTimer("skeleton");
_skeletonModel.simulate(deltaTime);
_firstPersonSkeletonModel.simulate(deltaTime);
}
if (!_skeletonModel.hasSkeleton()) {
@ -1028,15 +1023,8 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
if (_useFullAvatar) {
_skeletonModel.setVisibleInScene(_prevShouldDrawHead, scene);
const QUrl DEFAULT_SKELETON_MODEL_URL = QUrl::fromLocalFile(PathUtils::resourcesPath() + "meshes/defaultAvatar_body.fst");
_firstPersonSkeletonModel.setURL(_skeletonModelURL, DEFAULT_SKELETON_MODEL_URL, true, !isMyAvatar());
_firstPersonSkeletonModel.setVisibleInScene(!_prevShouldDrawHead, scene);
} else {
_skeletonModel.setVisibleInScene(true, scene);
_firstPersonSkeletonModel.setVisibleInScene(false, scene);
_firstPersonSkeletonModel.reset();
}
}
@ -1254,23 +1242,14 @@ void MyAvatar::preRender(RenderArgs* renderArgs) {
const bool shouldDrawHead = shouldRenderHead(renderArgs);
_skeletonModel.initWhenReady(scene);
if (_useFullAvatar) {
_firstPersonSkeletonModel.initWhenReady(scene);
}
if (shouldDrawHead != _prevShouldDrawHead) {
if (_useFullAvatar) {
if (shouldDrawHead) {
_skeletonModel.setVisibleInScene(true, scene);
_firstPersonSkeletonModel.setVisibleInScene(false, scene);
} else {
_skeletonModel.setVisibleInScene(false, scene);
_firstPersonSkeletonModel.setVisibleInScene(true, scene);
}
_skeletonModel.setVisibleInScene(true, scene);
_rig->setFirstPerson(!shouldDrawHead);
} else {
getHead()->getFaceModel().setVisibleInScene(shouldDrawHead, scene);
}
}
_prevShouldDrawHead = shouldDrawHead;
}

View file

@ -287,8 +287,6 @@ private:
QString _fullAvatarModelName;
RigPointer _rig;
// used for rendering when in first person view or when in an HMD.
SkeletonModel _firstPersonSkeletonModel;
bool _prevShouldDrawHead;
};

View file

@ -40,8 +40,7 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent, RigPointer r
_standingFoot(NO_FOOT),
_standingOffset(0.0f),
_clampedFootPosition(0.0f),
_headClipDistance(DEFAULT_NEAR_CLIP),
_isFirstPerson(false)
_headClipDistance(DEFAULT_NEAR_CLIP)
{
assert(_rig);
assert(_owningAvatar);
@ -54,7 +53,7 @@ SkeletonModel::~SkeletonModel() {
void SkeletonModel::initJointStates(QVector<JointState> states) {
const FBXGeometry& geometry = _geometry->getFBXGeometry();
glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset;
_boundingRadius = _rig->initJointStates(states, parentTransform);
_boundingRadius = _rig->initJointStates(states, parentTransform, geometry.neckJointIndex);
// Determine the default eye position for avatar scale = 1.0
int headJointIndex = _geometry->getFBXGeometry().headJointIndex;
@ -98,6 +97,29 @@ void SkeletonModel::initJointStates(QVector<JointState> states) {
const float PALM_PRIORITY = DEFAULT_PRIORITY;
const float LEAN_PRIORITY = DEFAULT_PRIORITY;
void SkeletonModel::updateClusterMatrices() {
const FBXGeometry& geometry = _geometry->getFBXGeometry();
glm::mat4 modelToWorld = glm::mat4_cast(_rotation);
for (int i = 0; i < _meshStates.size(); i++) {
MeshState& state = _meshStates[i];
const FBXMesh& mesh = geometry.meshes.at(i);
if (_showTrueJointTransforms) {
for (int j = 0; j < mesh.clusters.size(); j++) {
const FBXCluster& cluster = mesh.clusters.at(j);
state.clusterMatrices[j] =
modelToWorld * _rig->getJointTransform(cluster.jointIndex) * cluster.inverseBindMatrix;
}
} else {
for (int j = 0; j < mesh.clusters.size(); j++) {
const FBXCluster& cluster = mesh.clusters.at(j);
state.clusterMatrices[j] =
modelToWorld * _rig->getJointVisibleTransform(cluster.jointIndex) * cluster.inverseBindMatrix;
}
}
}
}
void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
setTranslation(_owningAvatar->getSkeletonPosition());
static const glm::quat refOrientation = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f));
@ -154,8 +176,11 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
}
}
if (_isFirstPerson) {
cauterizeHead();
// if (_isFirstPerson) {
// cauterizeHead();
// updateClusterMatrices();
// }
if (_rig->getJointsAreDirty()) {
updateClusterMatrices();
}
@ -766,7 +791,7 @@ void SkeletonModel::resetShapePositionsToDefaultPose() {
// geometry or joints have not yet been created
return;
}
const FBXGeometry& geometry = _geometry->getFBXGeometry();
if (geometry.joints.isEmpty()) {
return;
@ -822,7 +847,7 @@ void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float alpha
// draw a green cylinder between the two points
glm::vec3 origin(0.0f);
Avatar::renderJointConnectingCone(batch, origin, axis, _boundingShape.getRadius(), _boundingShape.getRadius(),
Avatar::renderJointConnectingCone(batch, origin, axis, _boundingShape.getRadius(), _boundingShape.getRadius(),
glm::vec4(0.6f, 0.8f, 0.6f, alpha));
}
@ -830,56 +855,5 @@ bool SkeletonModel::hasSkeleton() {
return isActive() ? _geometry->getFBXGeometry().rootJointIndex != -1 : false;
}
void SkeletonModel::initHeadBones() {
_headBones.clear();
const FBXGeometry& fbxGeometry = _geometry->getFBXGeometry();
const int neckJointIndex = fbxGeometry.neckJointIndex;
std::queue<int> q;
q.push(neckJointIndex);
_headBones.push_back(neckJointIndex);
// fbxJoints only hold links to parents not children, so we have to do a bit of extra work here.
while (q.size() > 0) {
int jointIndex = q.front();
for (int i = 0; i < fbxGeometry.joints.size(); i++) {
const FBXJoint& fbxJoint = fbxGeometry.joints[i];
if (jointIndex == fbxJoint.parentIndex) {
_headBones.push_back(i);
q.push(i);
}
}
q.pop();
}
}
void SkeletonModel::invalidateHeadBones() {
_headBones.clear();
}
void SkeletonModel::cauterizeHead() {
if (isActive()) {
const FBXGeometry& geometry = _geometry->getFBXGeometry();
const int neckJointIndex = geometry.neckJointIndex;
if (neckJointIndex > 0 && neckJointIndex < _rig->getJointStateCount()) {
// lazy init of headBones
if (_headBones.size() == 0) {
initHeadBones();
}
// preserve the translation for the neck
// glm::vec4 trans = _jointStates[neckJointIndex].getTransform()[3];
glm::vec4 trans = _rig->getJointTransform(neckJointIndex)[3];
glm::vec4 zero(0, 0, 0, 0);
for (const int &i : _headBones) {
glm::mat4 newXform(zero, zero, zero, trans);
_rig->setJointTransform(i, newXform);
_rig->setJointVisibleTransform(i, newXform);
}
}
}
}
void SkeletonModel::onInvalidate() {
invalidateHeadBones();
}

View file

@ -112,9 +112,6 @@ public:
float getHeadClipDistance() const { return _headClipDistance; }
void setIsFirstPerson(bool value) { _isFirstPerson = value; }
bool getIsFirstPerson() const { return _isFirstPerson; }
virtual void onInvalidate() override;
signals:
@ -138,6 +135,7 @@ protected:
void maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, int index);
void maybeUpdateEyeRotation(const JointState& parentState, const FBXJoint& joint, int index);
void updateClusterMatrices();
void cauterizeHead();
void initHeadBones();
void invalidateHeadBones();
@ -174,9 +172,6 @@ private:
glm::vec3 _clampedFootPosition;
float _headClipDistance; // Near clip distance to use if no separate head model
bool _isFirstPerson;
std::vector<int> _headBones;
};
#endif // hifi_SkeletonModel_h

View file

@ -176,8 +176,7 @@ void AnimationHandle::replaceMatchingPriorities(float newPriority) {
for (int i = 0; i < _jointMappings.size(); i++) {
int mapping = _jointMappings.at(i);
if (mapping != -1) {
JointState state = _rig->getJointState(mapping);
if (_priority == state._animationPriority) {
if (_priority == _rig->getJointAnimatinoPriority(mapping)) {
_rig->setJointAnimatinoPriority(mapping, newPriority);
}
}
@ -188,8 +187,7 @@ void AnimationHandle::restoreJoints() {
for (int i = 0; i < _jointMappings.size(); i++) {
int mapping = _jointMappings.at(i);
if (mapping != -1) {
JointState state = _rig->getJointState(mapping);
_rig->restoreJointRotation(mapping, 1.0f, state._animationPriority);
_rig->restoreJointRotation(mapping, 1.0f, _rig->getJointAnimatinoPriority(mapping));
}
}
}

View file

@ -9,6 +9,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <queue>
#include "AnimationHandle.h"
#include "Rig.h"
@ -48,9 +50,9 @@ void Rig::deleteAnimations() {
}
}
float Rig::initJointStates(QVector<JointState> states, glm::mat4 parentTransform) {
float Rig::initJointStates(QVector<JointState> states, glm::mat4 parentTransform, int neckJointIndex) {
_jointStates = states;
_neckJointIndex = neckJointIndex;
initJointTransforms(parentTransform);
int numStates = _jointStates.size();
@ -66,6 +68,8 @@ float Rig::initJointStates(QVector<JointState> states, glm::mat4 parentTransform
_jointStates[i].slaveVisibleTransform();
}
initHeadBones();
return radius;
}
@ -106,7 +110,8 @@ JointState Rig::getJointState(int jointIndex) const {
if (jointIndex == -1 || jointIndex >= _jointStates.size()) {
return JointState();
}
return _jointStates[jointIndex];
// return _jointStates[jointIndex];
return maybeCauterizeHead(jointIndex);
}
bool Rig::getJointStateRotation(int index, glm::quat& rotation) const {
@ -144,6 +149,13 @@ void Rig::clearJointAnimationPriority(int index) {
}
}
float Rig::getJointAnimatinoPriority(int index) {
if (index != -1 && index < _jointStates.size()) {
return _jointStates[index]._animationPriority;
}
return 0.0f;
}
void Rig::setJointAnimatinoPriority(int index, float newPriority) {
if (index != -1 && index < _jointStates.size()) {
_jointStates[index]._animationPriority = newPriority;
@ -173,7 +185,8 @@ bool Rig::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position,
return false;
}
// position is in world-frame
position = translation + rotation * _jointStates[jointIndex].getPosition();
// position = translation + rotation * _jointStates[jointIndex].getPosition();
position = translation + rotation * maybeCauterizeHead(jointIndex).getPosition();
return true;
}
@ -182,7 +195,7 @@ bool Rig::getJointPosition(int jointIndex, glm::vec3& position) const {
return false;
}
// position is in model-frame
position = extractTranslation(_jointStates[jointIndex].getTransform());
position = extractTranslation(maybeCauterizeHead(jointIndex).getTransform());
return true;
}
@ -190,7 +203,7 @@ bool Rig::getJointRotationInWorldFrame(int jointIndex, glm::quat& result, const
if (jointIndex == -1 || jointIndex >= _jointStates.size()) {
return false;
}
result = rotation * _jointStates[jointIndex].getRotation();
result = rotation * maybeCauterizeHead(jointIndex).getRotation();
return true;
}
@ -198,7 +211,7 @@ bool Rig::getJointRotation(int jointIndex, glm::quat& rotation) const {
if (jointIndex == -1 || jointIndex >= _jointStates.size()) {
return false;
}
rotation = _jointStates[jointIndex].getRotation();
rotation = maybeCauterizeHead(jointIndex).getRotation();
return true;
}
@ -206,7 +219,7 @@ bool Rig::getJointCombinedRotation(int jointIndex, glm::quat& result, const glm:
if (jointIndex == -1 || jointIndex >= _jointStates.size()) {
return false;
}
result = rotation * _jointStates[jointIndex].getRotation();
result = rotation * maybeCauterizeHead(jointIndex).getRotation();
return true;
}
@ -217,7 +230,7 @@ bool Rig::getVisibleJointPositionInWorldFrame(int jointIndex, glm::vec3& positio
return false;
}
// position is in world-frame
position = translation + rotation * _jointStates[jointIndex].getVisiblePosition();
position = translation + rotation * maybeCauterizeHead(jointIndex).getVisiblePosition();
return true;
}
@ -225,7 +238,7 @@ bool Rig::getVisibleJointRotationInWorldFrame(int jointIndex, glm::quat& result,
if (jointIndex == -1 || jointIndex >= _jointStates.size()) {
return false;
}
result = rotation * _jointStates[jointIndex].getVisibleRotation();
result = rotation * maybeCauterizeHead(jointIndex).getVisibleRotation();
return true;
}
@ -233,14 +246,14 @@ glm::mat4 Rig::getJointTransform(int jointIndex) const {
if (jointIndex == -1 || jointIndex >= _jointStates.size()) {
return glm::mat4();
}
return _jointStates[jointIndex].getTransform();
return maybeCauterizeHead(jointIndex).getTransform();
}
glm::mat4 Rig::getJointVisibleTransform(int jointIndex) const {
if (jointIndex == -1 || jointIndex >= _jointStates.size()) {
return glm::mat4();
}
return _jointStates[jointIndex].getVisibleTransform();
return maybeCauterizeHead(jointIndex).getVisibleTransform();
}
void Rig::simulateInternal(float deltaTime, glm::mat4 parentTransform) {
@ -492,7 +505,7 @@ glm::vec3 Rig::getJointDefaultTranslationInConstrainedFrame(int jointIndex) {
if (jointIndex == -1 || _jointStates.isEmpty()) {
return glm::vec3();
}
return _jointStates[jointIndex].getDefaultTranslationInConstrainedFrame();
return maybeCauterizeHead(jointIndex).getDefaultTranslationInConstrainedFrame();
}
glm::quat Rig::setJointRotationInConstrainedFrame(int jointIndex, glm::quat targetRotation, float priority, bool constrain) {
@ -537,5 +550,53 @@ glm::quat Rig::getJointDefaultRotationInParentFrame(int jointIndex) {
if (jointIndex == -1 || _jointStates.isEmpty()) {
return glm::quat();
}
return _jointStates[jointIndex].getDefaultRotationInParentFrame();
return maybeCauterizeHead(jointIndex).getDefaultRotationInParentFrame();
}
void Rig::initHeadBones() {
if (_neckJointIndex == -1) {
return;
}
_headBones.clear();
std::queue<int> q;
q.push(_neckJointIndex);
_headBones.push_back(_neckJointIndex);
// fbxJoints only hold links to parents not children, so we have to do a bit of extra work here.
while (q.size() > 0) {
int jointIndex = q.front();
for (int i = 0; i < _jointStates.size(); i++) {
const FBXJoint& fbxJoint = _jointStates[i].getFBXJoint();
if (jointIndex == fbxJoint.parentIndex) {
_headBones.push_back(i);
q.push(i);
}
}
q.pop();
}
}
JointState Rig::maybeCauterizeHead(int jointIndex) const {
// if (_headBones.contains(jointIndex)) {
// XXX fix this... make _headBones a hash? add a flag to JointState?
if (_neckJointIndex != -1 &&
_isFirstPerson &&
std::find(_headBones.begin(), _headBones.end(), jointIndex) != _headBones.end()) {
glm::vec4 trans = _jointStates[jointIndex].getTransform()[3];
glm::vec4 zero(0, 0, 0, 0);
glm::mat4 newXform(zero, zero, zero, trans);
JointState jointStateCopy = _jointStates[jointIndex];
jointStateCopy.setTransform(newXform);
jointStateCopy.setVisibleTransform(newXform);
return jointStateCopy;
} else {
return _jointStates[jointIndex];
}
}
void Rig::setFirstPerson(bool isFirstPerson) {
if (_isFirstPerson != isFirstPerson) {
_isFirstPerson = isFirstPerson;
_jointsAreDirty = true;
}
}

View file

@ -11,14 +11,18 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
/* TBD:
- What iare responsibilities of Animation/AnimationPointer/AnimationCache/AnimationDetails/AnimationObject/AnimationLoop?
- What are responsibilities of Animation/AnimationPointer/AnimationCache/AnimationDetails/AnimationObject/AnimationLoop?
Is there common/copied code (e.g., ScriptableAvatar::update)?
- How do attachments interact with the physics of the attached entity? E.g., do hand joints need to reflect held object physics?
- Is there any current need (i.e., for initial campatability) to have multiple animations per role (e.g., idle) with the system choosing randomly?
- How do attachments interact with the physics of the attached entity? E.g., do hand joints need to reflect held object
physics?
- Is there any current need (i.e., for initial campatability) to have multiple animations per role (e.g., idle) with the
system choosing randomly?
- Distribute some doc from here to the right files if it turns out to be correct:
- AnimationDetails is a script-useable copy of animation state, analogous to EntityItemProperties, but without anything equivalent to editEntity.
But what's the intended difference vs AnimationObjection? Maybe AnimationDetails is to Animation as AnimationObject is to AnimationPointer?
- AnimationDetails is a script-useable copy of animation state, analogous to EntityItemProperties, but without anything
equivalent to editEntity.
But what's the intended difference vs AnimationObjection? Maybe AnimationDetails is to Animation as AnimationObject
is to AnimationPointer?
*/
#ifndef __hifi__Rig__
@ -51,7 +55,7 @@ public:
const QList<AnimationHandlePointer>& getRunningAnimations() const { return _runningAnimations; }
void deleteAnimations();
float initJointStates(QVector<JointState> states, glm::mat4 parentTransform);
float initJointStates(QVector<JointState> states, glm::mat4 parentTransform, int neckJointIndex);
bool jointStatesEmpty() { return _jointStates.isEmpty(); };
int getJointStateCount() const { return _jointStates.size(); }
@ -60,11 +64,12 @@ public:
void reset(const QVector<FBXJoint>& fbxJoints);
bool getJointStateRotation(int index, glm::quat& rotation) const;
void applyJointRotationDelta(int jointIndex, const glm::quat& delta, bool constrain, float priority);
JointState getJointState(int jointIndex) const;
JointState getJointState(int jointIndex) const; // XXX
bool getVisibleJointState(int index, glm::quat& rotation) const;
void clearJointState(int index);
void clearJointStates();
void clearJointAnimationPriority(int index);
float getJointAnimatinoPriority(int index);
void setJointAnimatinoPriority(int index, float newPriority);
void setJointState(int index, bool valid, const glm::quat& rotation, float priority);
void restoreJointRotation(int index, float fraction, float priority);
@ -102,11 +107,23 @@ public:
virtual void updateJointState(int index, glm::mat4 parentTransform) = 0;
virtual void updateFaceJointState(int index, glm::mat4 parentTransform) = 0;
virtual void setFirstPerson(bool isFirstPerson);
virtual bool getIsFirstPerson() const { return _isFirstPerson; }
bool getJointsAreDirty() { return _jointsAreDirty; }
protected:
QVector<JointState> _jointStates;
QSet<AnimationHandlePointer> _animationHandles;
QList<AnimationHandlePointer> _runningAnimations;
JointState maybeCauterizeHead(int jointIndex) const;
void initHeadBones();
bool _isFirstPerson = false;
std::vector<int> _headBones;
bool _jointsAreDirty = false;
int _neckJointIndex = -1;
};
#endif /* defined(__hifi__Rig__) */

View file

@ -478,7 +478,7 @@ bool Model::updateGeometry() {
void Model::initJointStates(QVector<JointState> states) {
const FBXGeometry& geometry = _geometry->getFBXGeometry();
glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset;
_boundingRadius = _rig->initJointStates(states, parentTransform);
_boundingRadius = _rig->initJointStates(states, parentTransform, geometry.neckJointIndex);
}
bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance,
@ -1341,28 +1341,6 @@ void Model::simulate(float deltaTime, bool fullUpdate) {
}
}
void Model::updateClusterMatrices() {
const FBXGeometry& geometry = _geometry->getFBXGeometry();
glm::mat4 modelToWorld = glm::mat4_cast(_rotation);
for (int i = 0; i < _meshStates.size(); i++) {
MeshState& state = _meshStates[i];
const FBXMesh& mesh = geometry.meshes.at(i);
if (_showTrueJointTransforms) {
for (int j = 0; j < mesh.clusters.size(); j++) {
const FBXCluster& cluster = mesh.clusters.at(j);
state.clusterMatrices[j] =
modelToWorld * _rig->getJointTransform(cluster.jointIndex) * cluster.inverseBindMatrix;
}
} else {
for (int j = 0; j < mesh.clusters.size(); j++) {
const FBXCluster& cluster = mesh.clusters.at(j);
state.clusterMatrices[j] =
modelToWorld * _rig->getJointVisibleTransform(cluster.jointIndex) * cluster.inverseBindMatrix;
}
}
}
}
void Model::simulateInternal(float deltaTime) {
// update the world space transforms for all joints

View file

@ -308,9 +308,6 @@ protected:
_calculatedMeshTrianglesValid = false;
}
// rebuild the clusterMatrices from the current jointStates
void updateClusterMatrices();
// hook for derived classes to be notified when setUrl invalidates the current model.
virtual void onInvalidate() {};