281 lines · 10.7 KB · C++
RawDownload
////  JointState.cpp//  interface/src/renderer////  Created by Andrzej Kapolka on 10/18/13.//  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 <glm/gtx/norm.hpp> #include <QThreadPool> #include <AngularConstraint.h>#include <SharedUtil.h> #include "JointState.h" JointState::JointState() :    _animationPriority(0.0f),    _transformChanged(true),    _rotationIsValid(false),    _positionInParentFrame(0.0f),    _distanceToParent(0.0f),    _fbxJoint(NULL),    _constraint(NULL) {} JointState::JointState(const JointState& other) : _constraint(NULL) {    _transformChanged = other._transformChanged;    _transform = other._transform;    _rotationIsValid = other._rotationIsValid;    _rotation = other._rotation;    _rotationInConstrainedFrame = other._rotationInConstrainedFrame;    _positionInParentFrame = other._positionInParentFrame;    _distanceToParent = other._distanceToParent;    _animationPriority = other._animationPriority;    _fbxJoint = other._fbxJoint;    // DO NOT copy _constraint} JointState::~JointState() {    delete _constraint;    _constraint = NULL;    if (_constraint) {        delete _constraint;        _constraint = NULL;    }} glm::quat JointState::getRotation() const {    if (!_rotationIsValid) {        const_cast<JointState*>(this)->_rotation = extractRotation(_transform);        const_cast<JointState*>(this)->_rotationIsValid = true;    }        return _rotation;} void JointState::setFBXJoint(const FBXJoint* joint) {    assert(joint != NULL);    _rotationInConstrainedFrame = joint->rotation;    _transformChanged = true;    _rotationIsValid = false;        // NOTE: JointState does not own the FBXJoint to which it points.    _fbxJoint = joint;    if (_constraint) {        delete _constraint;        _constraint = NULL;    }} void JointState::buildConstraint() {    if (_constraint) {        delete _constraint;        _constraint = NULL;    }    if (glm::distance2(glm::vec3(-PI), _fbxJoint->rotationMin) > EPSILON ||             glm::distance2(glm::vec3(PI), _fbxJoint->rotationMax) > EPSILON ) {        // this joint has rotation constraints        _constraint = AngularConstraint::newAngularConstraint(_fbxJoint->rotationMin, _fbxJoint->rotationMax);    }} void JointState::copyState(const JointState& state) {    _animationPriority = state._animationPriority;    _transformChanged = state._transformChanged;    _transform = state._transform;    _rotationIsValid = state._rotationIsValid;    _rotation = state._rotation;    _rotationInConstrainedFrame = state._rotationInConstrainedFrame;    _positionInParentFrame = state._positionInParentFrame;    _distanceToParent = state._distanceToParent;     _visibleTransform = state._visibleTransform;    _visibleRotation = extractRotation(_visibleTransform);    _visibleRotationInConstrainedFrame = state._visibleRotationInConstrainedFrame;    // DO NOT copy _fbxJoint or _constraint} void JointState::initTransform(const glm::mat4& parentTransform) {    computeTransform(parentTransform);    _positionInParentFrame = glm::inverse(extractRotation(parentTransform)) * (extractTranslation(_transform) - extractTranslation(parentTransform));    _distanceToParent = glm::length(_positionInParentFrame);} void JointState::computeTransform(const glm::mat4& parentTransform, bool parentTransformChanged, bool synchronousRotationCompute) {    if (!parentTransformChanged && !_transformChanged) {        return;    }        glm::quat rotationInParentFrame = _fbxJoint->preRotation * _rotationInConstrainedFrame * _fbxJoint->postRotation;    glm::mat4 transformInParentFrame = _fbxJoint->preTransform * glm::mat4_cast(rotationInParentFrame) * _fbxJoint->postTransform;    glm::mat4 newTransform = parentTransform * glm::translate(_fbxJoint->translation) * transformInParentFrame;        if (newTransform != _transform) {        _transform = newTransform;        _transformChanged = true;        _rotationIsValid = false;    }} void JointState::computeVisibleTransform(const glm::mat4& parentTransform) {    glm::quat rotationInParentFrame = _fbxJoint->preRotation * _visibleRotationInConstrainedFrame * _fbxJoint->postRotation;    glm::mat4 transformInParentFrame = _fbxJoint->preTransform * glm::mat4_cast(rotationInParentFrame) * _fbxJoint->postTransform;    _visibleTransform = parentTransform * glm::translate(_fbxJoint->translation) * transformInParentFrame;    _visibleRotation = extractRotation(_visibleTransform);} glm::quat JointState::getRotationInBindFrame() const {    return getRotation() * _fbxJoint->inverseBindRotation;} glm::quat JointState::getRotationInParentFrame() const {    return _fbxJoint->preRotation * _rotationInConstrainedFrame * _fbxJoint->postRotation;} glm::quat JointState::getVisibleRotationInParentFrame() const {    return _fbxJoint->preRotation * _visibleRotationInConstrainedFrame * _fbxJoint->postRotation;} void JointState::restoreRotation(float fraction, float priority) {    assert(_fbxJoint != NULL);    if (priority == _animationPriority || _animationPriority == 0.0f) {        setRotationInConstrainedFrameInternal(safeMix(_rotationInConstrainedFrame, _fbxJoint->rotation, fraction));        _animationPriority = 0.0f;    }} void JointState::setRotationInBindFrame(const glm::quat& rotation, float priority, bool constrain) {    // rotation is from bind- to model-frame    assert(_fbxJoint != NULL);    if (priority >= _animationPriority) {        glm::quat targetRotation = _rotationInConstrainedFrame * glm::inverse(getRotation()) * rotation * glm::inverse(_fbxJoint->inverseBindRotation);        if (constrain && _constraint) {            _constraint->softClamp(targetRotation, _rotationInConstrainedFrame, 0.5f);        }        setRotationInConstrainedFrameInternal(targetRotation);        _animationPriority = priority;    }} void JointState::clearTransformTranslation() {    _transform[3][0] = 0.0f;    _transform[3][1] = 0.0f;    _transform[3][2] = 0.0f;    _transformChanged = true;    _visibleTransform[3][0] = 0.0f;    _visibleTransform[3][1] = 0.0f;    _visibleTransform[3][2] = 0.0f;} void JointState::applyRotationDelta(const glm::quat& delta, bool constrain, float priority) {    // NOTE: delta is in model-frame    assert(_fbxJoint != NULL);    if (priority < _animationPriority || delta.null) {        return;    }    _animationPriority = priority;    glm::quat targetRotation = _rotationInConstrainedFrame * glm::inverse(getRotation()) * delta * getRotation();    if (!constrain || _constraint == NULL) {        // no constraints        _rotationInConstrainedFrame = targetRotation;        _transformChanged = true;                _rotation = delta * getRotation();        return;    }    setRotationInConstrainedFrameInternal(targetRotation);} /// Applies delta rotation to joint but mixes a little bit of the default pose as well./// This helps keep an IK solution stable.void JointState::mixRotationDelta(const glm::quat& delta, float mixFactor, float priority) {    // NOTE: delta is in model-frame    assert(_fbxJoint != NULL);    if (priority < _animationPriority) {        return;    }    _animationPriority = priority;    glm::quat targetRotation = _rotationInConstrainedFrame * glm::inverse(getRotation()) * delta * getRotation();    if (mixFactor > 0.0f && mixFactor <= 1.0f) {        targetRotation = safeMix(targetRotation, _fbxJoint->rotation, mixFactor);    }    if (_constraint) {        _constraint->softClamp(targetRotation, _rotationInConstrainedFrame, 0.5f);    }    setRotationInConstrainedFrameInternal(targetRotation);} void JointState::mixVisibleRotationDelta(const glm::quat& delta, float mixFactor) {    // NOTE: delta is in model-frame    assert(_fbxJoint != NULL);    glm::quat targetRotation = _visibleRotationInConstrainedFrame * glm::inverse(_visibleRotation) * delta * _visibleRotation;    if (mixFactor > 0.0f && mixFactor <= 1.0f) {        //targetRotation = safeMix(targetRotation, _fbxJoint->rotation, mixFactor);        targetRotation = safeMix(targetRotation, _rotationInConstrainedFrame, mixFactor);    }    setVisibleRotationInConstrainedFrame(targetRotation);} glm::quat JointState::computeParentRotation() const {    // R = Rp * Rpre * r * Rpost    // Rp = R * (Rpre * r * Rpost)^    return getRotation() * glm::inverse(_fbxJoint->preRotation * _rotationInConstrainedFrame * _fbxJoint->postRotation);} glm::quat JointState::computeVisibleParentRotation() const {    return _visibleRotation * glm::inverse(_fbxJoint->preRotation * _visibleRotationInConstrainedFrame * _fbxJoint->postRotation);} void JointState::setRotationInConstrainedFrame(glm::quat targetRotation, float priority, bool constrain) {    if (priority >= _animationPriority || _animationPriority == 0.0f) {        if (constrain && _constraint) {            _constraint->softClamp(targetRotation, _rotationInConstrainedFrame, 0.5f);        }        setRotationInConstrainedFrameInternal(targetRotation);        _animationPriority = priority;    }} void JointState::setRotationInConstrainedFrameInternal(const glm::quat& targetRotation) {    glm::quat parentRotation = computeParentRotation();    _rotationInConstrainedFrame = targetRotation;    _transformChanged = true;    // R' = Rp * Rpre * r' * Rpost    _rotation = parentRotation * _fbxJoint->preRotation * _rotationInConstrainedFrame * _fbxJoint->postRotation;} void JointState::setVisibleRotationInConstrainedFrame(const glm::quat& targetRotation) {    glm::quat parentRotation = computeVisibleParentRotation();    _visibleRotationInConstrainedFrame = targetRotation;    _visibleRotation = parentRotation * _fbxJoint->preRotation * _visibleRotationInConstrainedFrame * _fbxJoint->postRotation;} const bool JointState::rotationIsDefault(const glm::quat& rotation, float tolerance) const {    glm::quat defaultRotation = _fbxJoint->rotation;    return glm::abs(rotation.x - defaultRotation.x) < tolerance &&        glm::abs(rotation.y - defaultRotation.y) < tolerance &&        glm::abs(rotation.z - defaultRotation.z) < tolerance &&        glm::abs(rotation.w - defaultRotation.w) < tolerance;} glm::quat JointState::getDefaultRotationInParentFrame() const {    // NOTE: the result is constant and could be cached in the FBXJoint    return _fbxJoint->preRotation * _fbxJoint->rotation * _fbxJoint->postRotation;} const glm::vec3& JointState::getDefaultTranslationInConstrainedFrame() const {    assert(_fbxJoint != NULL);    return _fbxJoint->translation;} void JointState::slaveVisibleTransform() {    _visibleTransform = _transform;    _visibleRotation = getRotation();    _visibleRotationInConstrainedFrame = _rotationInConstrainedFrame;}