Пример #1
0
void AnimSkeleton::buildSkeletonFromJoints(const std::vector<FBXJoint>& joints) {
    _joints = joints;

    // build a cache of bind poses
    _absoluteBindPoses.reserve(joints.size());
    _relativeBindPoses.reserve(joints.size());

    // build a chache of default poses
    _absoluteDefaultPoses.reserve(joints.size());
    _relativeDefaultPoses.reserve(joints.size());
    _relativePreRotationPoses.reserve(joints.size());
    _relativePostRotationPoses.reserve(joints.size());

    // iterate over FBXJoints and extract the bind pose information.
    for (int i = 0; i < (int)joints.size(); i++) {

        // build pre and post transforms
        glm::mat4 preRotationTransform = _joints[i].preTransform * glm::mat4_cast(_joints[i].preRotation);
        glm::mat4 postRotationTransform = glm::mat4_cast(_joints[i].postRotation) * _joints[i].postTransform;
        _relativePreRotationPoses.push_back(AnimPose(preRotationTransform));
        _relativePostRotationPoses.push_back(AnimPose(postRotationTransform));

        // build relative and absolute default poses
        glm::mat4 relDefaultMat = glm::translate(_joints[i].translation) * preRotationTransform * glm::mat4_cast(_joints[i].rotation) * postRotationTransform;
        AnimPose relDefaultPose(relDefaultMat);
        _relativeDefaultPoses.push_back(relDefaultPose);
        int parentIndex = getParentIndex(i);
        if (parentIndex >= 0) {
            _absoluteDefaultPoses.push_back(_absoluteDefaultPoses[parentIndex] * relDefaultPose);
        } else {
            _absoluteDefaultPoses.push_back(relDefaultPose);
        }

        // build relative and absolute bind poses
        if (_joints[i].bindTransformFoundInCluster) {
            // Use the FBXJoint::bindTransform, which is absolute model coordinates
            // i.e. not relative to it's parent.
            AnimPose absoluteBindPose(_joints[i].bindTransform);
            _absoluteBindPoses.push_back(absoluteBindPose);
            if (parentIndex >= 0) {
                AnimPose inverseParentAbsoluteBindPose = _absoluteBindPoses[parentIndex].inverse();
                _relativeBindPoses.push_back(inverseParentAbsoluteBindPose * absoluteBindPose);
            } else {
                _relativeBindPoses.push_back(absoluteBindPose);
            }
        } else {
            // use default transform instead
            _relativeBindPoses.push_back(relDefaultPose);
            if (parentIndex >= 0) {
                _absoluteBindPoses.push_back(_absoluteBindPoses[parentIndex] * relDefaultPose);
            } else {
                _absoluteBindPoses.push_back(relDefaultPose);
            }
        }
    }
}
Пример #2
0
// rotate bone's y-axis with target.
AnimPose boneLookAt(const glm::vec3& target, const AnimPose& bone) {
    glm::vec3 u, v, w;
    generateBasisVectors(target - bone.trans(), bone.rot() * Vectors::UNIT_X, u, v, w);
    glm::mat4 lookAt(glm::vec4(v, 0.0f),
                     glm::vec4(u, 0.0f),
                     // AJT: TODO REVISIT THIS, this could be -w.
                     glm::vec4(glm::normalize(glm::cross(v, u)), 0.0f),
                     glm::vec4(bone.trans(), 1.0f));
    return AnimPose(lookAt);
}
Пример #3
0
AnimPose AnimPose::inverse() const {
    return AnimPose(glm::inverse(static_cast<glm::mat4>(*this)));
}
Пример #4
0
//  Copyright (c) 2015 High Fidelity, Inc. All rights reserved.
//
//  Distributed under the Apache License, Version 2.0.
//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//

#include "AnimSkeleton.h"

#include <glm/gtx/transform.hpp>

#include <GLMHelpers.h>

#include "AnimationLogging.h"

const AnimPose AnimPose::identity = AnimPose(glm::vec3(1.0f),
                                             glm::quat(),
                                             glm::vec3(0.0f));

AnimPose::AnimPose(const glm::mat4& mat) {
    scale = extractScale(mat);
    rot = glm::normalize(glm::quat_cast(mat));
    trans = extractTranslation(mat);
}

glm::vec3 AnimPose::operator*(const glm::vec3& rhs) const {
    return trans + (rot * (scale * rhs));
}

glm::vec3 AnimPose::xformPoint(const glm::vec3& rhs) const {
    return *this * rhs;
}
Пример #5
0
AnimPose AnimPose::operator*(const AnimPose& rhs) const {
    return AnimPose(static_cast<glm::mat4>(*this) * static_cast<glm::mat4>(rhs));
}
Пример #6
0
void AnimSkeleton::buildSkeletonFromJoints(const std::vector<HFMJoint>& joints, const QMap<int, glm::quat> jointOffsets) {

    _joints = joints;
    _jointsSize = (int)joints.size();
    // build a cache of bind poses

    // build a chache of default poses
    _absoluteDefaultPoses.reserve(_jointsSize);
    _relativeDefaultPoses.reserve(_jointsSize);
    _relativePreRotationPoses.reserve(_jointsSize);
    _relativePostRotationPoses.reserve(_jointsSize);

    // iterate over HFMJoints and extract the bind pose information.
    for (int i = 0; i < _jointsSize; i++) {

        // build pre and post transforms
        glm::mat4 preRotationTransform = _joints[i].preTransform * glm::mat4_cast(_joints[i].preRotation);
        glm::mat4 postRotationTransform = glm::mat4_cast(_joints[i].postRotation) * _joints[i].postTransform;
        _relativePreRotationPoses.push_back(AnimPose(preRotationTransform));
        _relativePostRotationPoses.push_back(AnimPose(postRotationTransform));

        // build relative and absolute default poses
        glm::mat4 relDefaultMat = glm::translate(_joints[i].translation) * preRotationTransform * glm::mat4_cast(_joints[i].rotation) * postRotationTransform;
        AnimPose relDefaultPose(relDefaultMat);

        int parentIndex = getParentIndex(i);
        if (parentIndex >= 0) {
            _absoluteDefaultPoses.push_back(_absoluteDefaultPoses[parentIndex] * relDefaultPose);
        } else {
            _absoluteDefaultPoses.push_back(relDefaultPose);
        }
    }

    for (int k = 0; k < _jointsSize; k++) {
        if (jointOffsets.contains(k)) {
            AnimPose localOffset(jointOffsets[k], glm::vec3());
            _absoluteDefaultPoses[k] = _absoluteDefaultPoses[k] * localOffset;
        }
    }
    // re-compute relative poses
    _relativeDefaultPoses = _absoluteDefaultPoses;
    convertAbsolutePosesToRelative(_relativeDefaultPoses);

    for (int i = 0; i < _jointsSize; i++) {
        _jointIndicesByName[_joints[i].name] = i;
    }

    // build mirror map.
    _nonMirroredIndices.clear();
    _mirrorMap.reserve(_jointsSize);
    for (int i = 0; i < _jointsSize; i++) {
        if (_joints[i].name != "Hips" && _joints[i].name != "Spine" &&
            _joints[i].name != "Spine1" && _joints[i].name != "Spine2" &&
            _joints[i].name != "Neck" && _joints[i].name != "Head" &&
            !((_joints[i].name.startsWith("Left") || _joints[i].name.startsWith("Right")) &&
              _joints[i].name != "LeftEye" && _joints[i].name != "RightEye")) {
            // HACK: we don't want to mirror some joints so we remember their indices
            // so we can restore them after a future mirror operation
            _nonMirroredIndices.push_back(i);
        }
        int mirrorJointIndex = -1;
        if (_joints[i].name.startsWith("Left")) {
            QString mirrorJointName = QString(_joints[i].name).replace(0, 4, "Right");
            mirrorJointIndex = nameToJointIndex(mirrorJointName);
        } else if (_joints[i].name.startsWith("Right")) {
            QString mirrorJointName = QString(_joints[i].name).replace(0, 5, "Left");
            mirrorJointIndex = nameToJointIndex(mirrorJointName);
        }
        if (mirrorJointIndex >= 0) {
            _mirrorMap.push_back(mirrorJointIndex);
        } else {
            _mirrorMap.push_back(i);
        }
    }
}
Пример #7
0
void AnimDebugDraw::update() {

    render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
    if (!scene) {
        return;
    }
    if (!render::Item::isValidID(_itemID)) {
        return;
    }
    render::Transaction transaction;
    transaction.updateItem<AnimDebugDrawData>(_itemID, [&](AnimDebugDrawData& data) {

        const size_t VERTICES_PER_BONE = (6 + (NUM_CIRCLE_SLICES * 2) * 3);
        const size_t VERTICES_PER_LINK = 8 * 2;
        const size_t VERTICES_PER_RAY = 2;

        const float BONE_RADIUS = 0.01f; // 1 cm
        const float POSE_RADIUS = 0.1f; // 10 cm

        // figure out how many verts we will need.
        int numVerts = 0;

        for (auto& iter : _absolutePoses) {
            AnimSkeleton::ConstPointer& skeleton = std::get<0>(iter.second);
            numVerts += skeleton->getNumJoints() * VERTICES_PER_BONE;
            for (auto i = 0; i < skeleton->getNumJoints(); i++) {
                auto parentIndex = skeleton->getParentIndex(i);
                if (parentIndex >= 0) {
                    numVerts += VERTICES_PER_LINK;
                }
            }
        }

        // count marker verts from shared DebugDraw singleton
        auto markerMap = DebugDraw::getInstance().getMarkerMap();
        numVerts += (int)markerMap.size() * VERTICES_PER_BONE;
        auto myAvatarMarkerMap = DebugDraw::getInstance().getMyAvatarMarkerMap();
        numVerts += (int)myAvatarMarkerMap.size() * VERTICES_PER_BONE;
        auto rays = DebugDraw::getInstance().getRays();
        DebugDraw::getInstance().clearRays();
        numVerts += (int)rays.size() * VERTICES_PER_RAY;

        // allocate verts!
        std::vector<AnimDebugDrawData::Vertex> vertices;
        vertices.resize(numVerts);
        //Vertex* verts = (Vertex*)data._vertexBuffer->editData();
        AnimDebugDrawData::Vertex* v = nullptr;
        if (numVerts) {
            v = &vertices[0];
        }

        // draw absolute poses
        for (auto& iter : _absolutePoses) {
            AnimSkeleton::ConstPointer& skeleton = std::get<0>(iter.second);
            AnimPoseVec& absPoses = std::get<1>(iter.second);
            AnimPose rootPose = std::get<2>(iter.second);
            glm::vec4 color = std::get<3>(iter.second);

            for (int i = 0; i < skeleton->getNumJoints(); i++) {
                const float radius = BONE_RADIUS / (absPoses[i].scale().x * rootPose.scale().x);

                // draw bone
                addBone(rootPose, absPoses[i], radius, color, v);

                // draw link to parent
                auto parentIndex = skeleton->getParentIndex(i);
                if (parentIndex >= 0) {
                    assert(parentIndex < skeleton->getNumJoints());
                    addLink(rootPose, absPoses[i], absPoses[parentIndex], radius, color, v);
                }
            }
        }

        // draw markers from shared DebugDraw singleton
        for (auto& iter : markerMap) {
            glm::quat rot = std::get<0>(iter.second);
            glm::vec3 pos = std::get<1>(iter.second);
            glm::vec4 color = std::get<2>(iter.second);
            const float radius = POSE_RADIUS;
            addBone(AnimPose::identity, AnimPose(glm::vec3(1), rot, pos), radius, color, v);
        }

        AnimPose myAvatarPose(glm::vec3(1), DebugDraw::getInstance().getMyAvatarRot(), DebugDraw::getInstance().getMyAvatarPos());
        for (auto& iter : myAvatarMarkerMap) {
            glm::quat rot = std::get<0>(iter.second);
            glm::vec3 pos = std::get<1>(iter.second);
            glm::vec4 color = std::get<2>(iter.second);
            const float radius = POSE_RADIUS;
            addBone(myAvatarPose, AnimPose(glm::vec3(1), rot, pos), radius, color, v);
        }

        // draw rays from shared DebugDraw singleton
        for (auto& iter : rays) {
            addLine(std::get<0>(iter), std::get<1>(iter), std::get<2>(iter), v);
        }

        data._vertexBuffer->resize(sizeof(AnimDebugDrawData::Vertex) * numVerts);
        data._vertexBuffer->setSubData<AnimDebugDrawData::Vertex>(0, vertices);

        assert((!numVerts && !v) || (numVerts == (v - &vertices[0])));

        render::Item::Bound theBound;
        for (int i = 0; i < numVerts; i++) {
            theBound += vertices[i].pos;
        }
        data._bound = theBound;

        data._isVisible = (numVerts > 0);

        data._indexBuffer->resize(sizeof(uint16_t) * numVerts);
        for (int i = 0; i < numVerts; i++) {
            data._indexBuffer->setSubData<uint16_t>(i, (uint16_t)i);;
        }
    });
    scene->enqueueTransaction(transaction);
}
Пример #8
0
void AnimDebugDraw::update() {

    render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
    if (!scene) {
        return;
    }

    render::PendingChanges pendingChanges;
    pendingChanges.updateItem<AnimDebugDrawData>(_itemID, [&](AnimDebugDrawData& data) {

        const size_t VERTICES_PER_BONE = (6 + (NUM_CIRCLE_SLICES * 2) * 3);
        const size_t VERTICES_PER_LINK = 8 * 2;

        const float BONE_RADIUS = 0.01f; // 1 cm
        const float POSE_RADIUS = 0.1f; // 10 cm

        // figure out how many verts we will need.
        int numVerts = 0;

        for (auto& iter : _absolutePoses) {
            AnimSkeleton::ConstPointer& skeleton = std::get<0>(iter.second);
            numVerts += skeleton->getNumJoints() * VERTICES_PER_BONE;
            for (auto i = 0; i < skeleton->getNumJoints(); i++) {
                auto parentIndex = skeleton->getParentIndex(i);
                if (parentIndex >= 0) {
                    numVerts += VERTICES_PER_LINK;
                }
            }
        }

        // count marker verts from shared DebugDraw singleton
        auto markerMap = DebugDraw::getInstance().getMarkerMap();
        numVerts += (int)markerMap.size() * VERTICES_PER_BONE;
        auto myAvatarMarkerMap = DebugDraw::getInstance().getMyAvatarMarkerMap();
        numVerts += (int)myAvatarMarkerMap.size() * VERTICES_PER_BONE;

        // allocate verts!
        data._vertexBuffer->resize(sizeof(Vertex) * numVerts);
        Vertex* verts = (Vertex*)data._vertexBuffer->editData();
        Vertex* v = verts;

        // draw absolute poses
        for (auto& iter : _absolutePoses) {
            AnimSkeleton::ConstPointer& skeleton = std::get<0>(iter.second);
            AnimPoseVec& absPoses = std::get<1>(iter.second);
            AnimPose rootPose = std::get<2>(iter.second);
            glm::vec4 color = std::get<3>(iter.second);

            for (int i = 0; i < skeleton->getNumJoints(); i++) {
                const float radius = BONE_RADIUS / (absPoses[i].scale.x * rootPose.scale.x);

                // draw bone
                addBone(rootPose, absPoses[i], radius, v);

                // draw link to parent
                auto parentIndex = skeleton->getParentIndex(i);
                if (parentIndex >= 0) {
                    assert(parentIndex < skeleton->getNumJoints());
                    addLink(rootPose, absPoses[i], absPoses[parentIndex], radius, color, v);
                }
            }
        }

        // draw markers from shared DebugDraw singleton
        for (auto& iter : markerMap) {
            glm::quat rot = std::get<0>(iter.second);
            glm::vec3 pos = std::get<1>(iter.second);
            glm::vec4 color = std::get<2>(iter.second);  // TODO: currently ignored.
            Q_UNUSED(color);
            const float radius = POSE_RADIUS;
            addBone(AnimPose::identity, AnimPose(glm::vec3(1), rot, pos), radius, v);
        }

        AnimPose myAvatarPose(glm::vec3(1), DebugDraw::getInstance().getMyAvatarRot(), DebugDraw::getInstance().getMyAvatarPos());
        for (auto& iter : myAvatarMarkerMap) {
            glm::quat rot = std::get<0>(iter.second);
            glm::vec3 pos = std::get<1>(iter.second);
            glm::vec4 color = std::get<2>(iter.second);  // TODO: currently ignored.
            Q_UNUSED(color);
            const float radius = POSE_RADIUS;
            addBone(myAvatarPose, AnimPose(glm::vec3(1), rot, pos), radius, v);
        }

        assert(numVerts == (v - verts));

        data._indexBuffer->resize(sizeof(uint16_t) * numVerts);
        uint16_t* indices = (uint16_t*)data._indexBuffer->editData();
        for (int i = 0; i < numVerts; i++) {
            indices[i] = i;
        }
    });
    scene->enqueuePendingChanges(pendingChanges);
}
Пример #9
0
void AnimSkeleton::buildSkeletonFromJoints(const std::vector<FBXJoint>& joints) {
    _joints = joints;

    // build a cache of bind poses
    _absoluteBindPoses.reserve(joints.size());
    _relativeBindPoses.reserve(joints.size());

    // build a chache of default poses
    _absoluteDefaultPoses.reserve(joints.size());
    _relativeDefaultPoses.reserve(joints.size());
    _relativePreRotationPoses.reserve(joints.size());
    _relativePostRotationPoses.reserve(joints.size());

    // iterate over FBXJoints and extract the bind pose information.
    for (int i = 0; i < (int)joints.size(); i++) {

        // build pre and post transforms
        glm::mat4 preRotationTransform = _joints[i].preTransform * glm::mat4_cast(_joints[i].preRotation);
        glm::mat4 postRotationTransform = glm::mat4_cast(_joints[i].postRotation) * _joints[i].postTransform;
        _relativePreRotationPoses.push_back(AnimPose(preRotationTransform));
        _relativePostRotationPoses.push_back(AnimPose(postRotationTransform));

        // build relative and absolute default poses
        glm::mat4 relDefaultMat = glm::translate(_joints[i].translation) * preRotationTransform * glm::mat4_cast(_joints[i].rotation) * postRotationTransform;
        AnimPose relDefaultPose(relDefaultMat);
        _relativeDefaultPoses.push_back(relDefaultPose);
        int parentIndex = getParentIndex(i);
        if (parentIndex >= 0) {
            _absoluteDefaultPoses.push_back(_absoluteDefaultPoses[parentIndex] * relDefaultPose);
        } else {
            _absoluteDefaultPoses.push_back(relDefaultPose);
        }

        // build relative and absolute bind poses
        if (_joints[i].bindTransformFoundInCluster) {
            // Use the FBXJoint::bindTransform, which is absolute model coordinates
            // i.e. not relative to it's parent.
            AnimPose absoluteBindPose(_joints[i].bindTransform);
            _absoluteBindPoses.push_back(absoluteBindPose);
            if (parentIndex >= 0) {
                AnimPose inverseParentAbsoluteBindPose = _absoluteBindPoses[parentIndex].inverse();
                _relativeBindPoses.push_back(inverseParentAbsoluteBindPose * absoluteBindPose);
            } else {
                _relativeBindPoses.push_back(absoluteBindPose);
            }
        } else {
            // use default transform instead
            _relativeBindPoses.push_back(relDefaultPose);
            if (parentIndex >= 0) {
                _absoluteBindPoses.push_back(_absoluteBindPoses[parentIndex] * relDefaultPose);
            } else {
                _absoluteBindPoses.push_back(relDefaultPose);
            }
        }
    }

    // build mirror map.
    _nonMirroredIndices.clear();
    _mirrorMap.reserve(_joints.size());
    for (int i = 0; i < (int)joints.size(); i++) {
        if (_joints[i].name.endsWith("tEye")) {
            // HACK: we don't want to mirror some joints so we remember their indices
            // so we can restore them after a future mirror operation
            _nonMirroredIndices.push_back(i);
        }
        int mirrorJointIndex = -1;
        if (_joints[i].name.startsWith("Left")) {
            QString mirrorJointName = QString(_joints[i].name).replace(0, 4, "Right");
            mirrorJointIndex = nameToJointIndex(mirrorJointName);
        } else if (_joints[i].name.startsWith("Right")) {
            QString mirrorJointName = QString(_joints[i].name).replace(0, 5, "Left");
            mirrorJointIndex = nameToJointIndex(mirrorJointName);
        }
        if (mirrorJointIndex >= 0) {
            _mirrorMap.push_back(mirrorJointIndex);
        } else {
            _mirrorMap.push_back(i);
        }
    }
}
Пример #10
0
void AnimClip::copyFromNetworkAnim() {
    assert(_networkAnim && _networkAnim->isLoaded() && _skeleton);
    _anim.clear();

    // build a mapping from animation joint indices to skeleton joint indices.
    // by matching joints with the same name.
    const FBXGeometry& geom = _networkAnim->getGeometry();
    AnimSkeleton animSkeleton(geom);
    const auto animJointCount = animSkeleton.getNumJoints();
    const auto skeletonJointCount = _skeleton->getNumJoints();
    std::vector<int> jointMap;
    jointMap.reserve(animJointCount);
    for (int i = 0; i < animJointCount; i++) {
        int skeletonJoint = _skeleton->nameToJointIndex(animSkeleton.getJointName(i));
        if (skeletonJoint == -1) {
            qCWarning(animation) << "animation contains joint =" << animSkeleton.getJointName(i) << " which is not in the skeleton, url =" << _url;
        }
        jointMap.push_back(skeletonJoint);
    }

    const int frameCount = geom.animationFrames.size();
    _anim.resize(frameCount);

    for (int frame = 0; frame < frameCount; frame++) {

        const FBXAnimationFrame& fbxAnimFrame = geom.animationFrames[frame];

        // init all joints in animation to default pose
        // this will give us a resonable result for bones in the model skeleton but not in the animation.
        _anim[frame].reserve(skeletonJointCount);
        for (int skeletonJoint = 0; skeletonJoint < skeletonJointCount; skeletonJoint++) {
            _anim[frame].push_back(_skeleton->getRelativeDefaultPose(skeletonJoint));
        }

        for (int animJoint = 0; animJoint < animJointCount; animJoint++) {
            int skeletonJoint = jointMap[animJoint];

            const glm::vec3& fbxAnimTrans = fbxAnimFrame.translations[animJoint];
            const glm::quat& fbxAnimRot = fbxAnimFrame.rotations[animJoint];

            // skip joints that are in the animation but not in the skeleton.
            if (skeletonJoint >= 0 && skeletonJoint < skeletonJointCount) {

                AnimPose preRot, postRot;
                if (usePreAndPostPoseFromAnim) {
                    preRot = animSkeleton.getPreRotationPose(animJoint);
                    postRot = animSkeleton.getPostRotationPose(animJoint);
                } else {
                    // In order to support Blender, which does not have preRotation FBX support, we use the models defaultPose as the reference frame for the animations.
                    preRot = AnimPose(glm::vec3(1.0f), _skeleton->getRelativeBindPose(skeletonJoint).rot, glm::vec3());
                    postRot = AnimPose::identity;
                }

                // cancel out scale
                preRot.scale = glm::vec3(1.0f);
                postRot.scale = glm::vec3(1.0f);

                AnimPose rot(glm::vec3(1.0f), fbxAnimRot, glm::vec3());

                // adjust translation offsets, so large translation animatons on the reference skeleton
                // will be adjusted when played on a skeleton with short limbs.
                const glm::vec3& fbxZeroTrans = geom.animationFrames[0].translations[animJoint];
                const AnimPose& relDefaultPose = _skeleton->getRelativeDefaultPose(skeletonJoint);
                float boneLengthScale = 1.0f;
                const float EPSILON = 0.0001f;
                if (fabsf(glm::length(fbxZeroTrans)) > EPSILON) {
                    boneLengthScale = glm::length(relDefaultPose.trans) / glm::length(fbxZeroTrans);
                }

                AnimPose trans = AnimPose(glm::vec3(1.0f), glm::quat(), relDefaultPose.trans + boneLengthScale * (fbxAnimTrans - fbxZeroTrans));

                _anim[frame][skeletonJoint] = trans * preRot * rot * postRot;
            }
        }
    }

    // mirrorAnim will be re-built on demand, if needed.
    _mirrorAnim.clear();

    _poses.resize(skeletonJointCount);
}