Exemple #1
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++) {

        // 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];

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

                const glm::vec3& fbxZeroTrans = geom.animationFrames[0].translations[animJoint];
#ifdef USE_PRE_ROT_FROM_ANIM
                // TODO: This is the correct way to apply the pre rotations from maya, however
                // the current animation set has incorrect preRotations for the left wrist and thumb
                // so it looks wrong if we enable this code.
                glm::quat preRotation = animSkeleton.getPreRotation(animJoint);
#else
                // TODO: This is the legacy approach, this does not work when animations and models do not
                // have the same set of pre rotations.  For example when mixing maya models with blender animations.
                glm::quat preRotation = _skeleton->getRelativeBindPose(skeletonJoint).rot;
#endif
                const AnimPose& relDefaultPose = _skeleton->getRelativeDefaultPose(skeletonJoint);

                // used to adjust translation offsets, so large translation animatons on the reference skeleton
                // will be adjusted when played on a skeleton with short limbs.
                float limbLengthScale = fabsf(glm::length(fbxZeroTrans)) <= 0.0001f ? 1.0f : (glm::length(relDefaultPose.trans) / glm::length(fbxZeroTrans));

                AnimPose& pose = _anim[frame][skeletonJoint];
                const FBXAnimationFrame& fbxAnimFrame = geom.animationFrames[frame];

                // rotation in fbxAnimationFrame is a delta from its preRotation.
                pose.rot = preRotation * fbxAnimFrame.rotations[animJoint];

                // translation in fbxAnimationFrame is not a delta.
                // convert it into a delta by subtracting from the first frame.
                const glm::vec3& fbxTrans = fbxAnimFrame.translations[animJoint];
                pose.trans = relDefaultPose.trans + limbLengthScale * (fbxTrans - fbxZeroTrans);
            }
        }
    }

    _poses.resize(skeletonJointCount);
}
Exemple #2
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);
}