Search in sources :

Example 6 with BoneTrack

use of com.jme3.animation.BoneTrack in project jmonkeyengine by jMonkeyEngine.

the class SimulationNode method computeAnimationTimeBoundaries.

/**
     * Computes the maximum frame and time for the animation. Different tracks
     * can have different lengths so here the maximum one is being found.
     * 
     * @param animation
     *            the animation
     * @return maximum frame and time of the animation
     */
private float[] computeAnimationTimeBoundaries(Animation animation) {
    int maxFrame = Integer.MIN_VALUE;
    float maxTime = -Float.MAX_VALUE;
    for (Track track : animation.getTracks()) {
        if (track instanceof BoneTrack) {
            maxFrame = Math.max(maxFrame, ((BoneTrack) track).getTranslations().length);
            maxTime = Math.max(maxTime, ((BoneTrack) track).getTimes()[((BoneTrack) track).getTimes().length - 1]);
        } else if (track instanceof SpatialTrack) {
            maxFrame = Math.max(maxFrame, ((SpatialTrack) track).getTranslations().length);
            maxTime = Math.max(maxTime, ((SpatialTrack) track).getTimes()[((SpatialTrack) track).getTimes().length - 1]);
        } else {
            throw new IllegalStateException("Unsupported track type for simuation: " + track);
        }
    }
    return new float[] { maxFrame, maxTime };
}
Also used : SpatialTrack(com.jme3.animation.SpatialTrack) BoneTrack(com.jme3.animation.BoneTrack) SpatialTrack(com.jme3.animation.SpatialTrack) BoneTrack(com.jme3.animation.BoneTrack) Track(com.jme3.animation.Track)

Example 7 with BoneTrack

use of com.jme3.animation.BoneTrack in project jmonkeyengine by jMonkeyEngine.

the class Ipo method calculateTrack.

/**
     * This method calculates the value of the curves as a bone track between
     * the specified frames.
     * 
     * @param targetIndex
     *            the index of the target for which the method calculates the
     *            tracks IMPORTANT! Aet to -1 (or any negative number) if you
     *            want to load spatial animation.
     * @param localTranslation
     *            the local translation of the object/bone that will be animated by
     *            the track
     * @param localRotation
     *            the local rotation of the object/bone that will be animated by
     *            the track
     * @param localScale
     *            the local scale of the object/bone that will be animated by
     *            the track
     * @param startFrame
     *            the first frame of tracks (inclusive)
     * @param stopFrame
     *            the last frame of the tracks (inclusive)
     * @param fps
     *            frame rate (frames per second)
     * @param spatialTrack
     *            this flag indicates if the track belongs to a spatial or to a
     *            bone; the difference is important because it appears that bones
     *            in blender have the same type of coordinate system (Y as UP)
     *            as jme while other features have different one (Z is UP)
     * @return bone track for the specified bone
     */
public Track calculateTrack(int targetIndex, BoneContext boneContext, Vector3f localTranslation, Quaternion localRotation, Vector3f localScale, int startFrame, int stopFrame, int fps, boolean spatialTrack) {
    if (calculatedTrack == null) {
        // preparing data for track
        int framesAmount = stopFrame - startFrame;
        float timeBetweenFrames = 1.0f / fps;
        float[] times = new float[framesAmount + 1];
        Vector3f[] translations = new Vector3f[framesAmount + 1];
        float[] translation = new float[3];
        Quaternion[] rotations = new Quaternion[framesAmount + 1];
        float[] quaternionRotation = new float[] { localRotation.getX(), localRotation.getY(), localRotation.getZ(), localRotation.getW() };
        float[] eulerRotation = localRotation.toAngles(null);
        Vector3f[] scales = new Vector3f[framesAmount + 1];
        float[] scale = new float[] { localScale.x, localScale.y, localScale.z };
        float degreeToRadiansFactor = 1;
        if (blenderVersion < 250) {
            // in blender earlier than 2.50 the values are stored in degrees
            // the values in blender are divided by 10, so we need to mult it here
            degreeToRadiansFactor *= FastMath.DEG_TO_RAD * 10;
        }
        int yIndex = 1, zIndex = 2;
        boolean swapAxes = spatialTrack && fixUpAxis;
        if (swapAxes) {
            yIndex = 2;
            zIndex = 1;
        }
        boolean eulerRotationUsed = false, queternionRotationUsed = false;
        // calculating track data
        for (int frame = startFrame; frame <= stopFrame; ++frame) {
            boolean translationSet = false;
            translation[0] = translation[1] = translation[2] = 0;
            int index = frame - startFrame;
            // start + (frame - 1) * timeBetweenFrames;
            times[index] = index * timeBetweenFrames;
            for (int j = 0; j < bezierCurves.length; ++j) {
                double value = bezierCurves[j].evaluate(frame, BezierCurve.Y_VALUE);
                switch(bezierCurves[j].getType()) {
                    // LOCATION
                    case AC_LOC_X:
                        translation[0] = (float) value;
                        translationSet = true;
                        break;
                    case AC_LOC_Y:
                        if (swapAxes && value != 0) {
                            value = -value;
                        }
                        translation[yIndex] = (float) value;
                        translationSet = true;
                        break;
                    case AC_LOC_Z:
                        translation[zIndex] = (float) value;
                        translationSet = true;
                        break;
                    // EULER ROTATION
                    case OB_ROT_X:
                        eulerRotationUsed = true;
                        eulerRotation[0] = (float) value * degreeToRadiansFactor;
                        break;
                    case OB_ROT_Y:
                        eulerRotationUsed = true;
                        if (swapAxes && value != 0) {
                            value = -value;
                        }
                        eulerRotation[yIndex] = (float) value * degreeToRadiansFactor;
                        break;
                    case OB_ROT_Z:
                        eulerRotationUsed = true;
                        eulerRotation[zIndex] = (float) value * degreeToRadiansFactor;
                        break;
                    // SIZE
                    case AC_SIZE_X:
                        scale[0] = (float) value;
                        break;
                    case AC_SIZE_Y:
                        scale[yIndex] = (float) value;
                        break;
                    case AC_SIZE_Z:
                        scale[zIndex] = (float) value;
                        break;
                    // QUATERNION ROTATION (used with bone animation)
                    case AC_QUAT_W:
                        queternionRotationUsed = true;
                        quaternionRotation[3] = (float) value;
                        break;
                    case AC_QUAT_X:
                        queternionRotationUsed = true;
                        quaternionRotation[0] = (float) value;
                        break;
                    case AC_QUAT_Y:
                        queternionRotationUsed = true;
                        if (swapAxes && value != 0) {
                            value = -value;
                        }
                        quaternionRotation[yIndex] = (float) value;
                        break;
                    case AC_QUAT_Z:
                        quaternionRotation[zIndex] = (float) value;
                        break;
                    default:
                        LOGGER.log(Level.WARNING, "Unknown ipo curve type: {0}.", bezierCurves[j].getType());
                }
            }
            if (translationSet) {
                translations[index] = localRotation.multLocal(new Vector3f(translation[0], translation[1], translation[2]));
            } else {
                translations[index] = new Vector3f();
            }
            if (boneContext != null) {
                if (boneContext.getBone().getParent() == null && boneContext.is(BoneContext.NO_LOCAL_LOCATION)) {
                    float temp = translations[index].z;
                    translations[index].z = -translations[index].y;
                    translations[index].y = temp;
                }
            }
            if (queternionRotationUsed) {
                rotations[index] = new Quaternion(quaternionRotation[0], quaternionRotation[1], quaternionRotation[2], quaternionRotation[3]);
            } else {
                rotations[index] = new Quaternion().fromAngles(eulerRotation);
            }
            scales[index] = new Vector3f(scale[0], scale[1], scale[2]);
        }
        if (spatialTrack) {
            calculatedTrack = new SpatialTrack(times, translations, rotations, scales);
        } else {
            calculatedTrack = new BoneTrack(targetIndex, times, translations, rotations, scales);
        }
        if (queternionRotationUsed && eulerRotationUsed) {
            LOGGER.warning("Animation uses both euler and quaternion tracks for rotations. Quaternion rotation is applied. Make sure that this is what you wanted!");
        }
    }
    return calculatedTrack;
}
Also used : SpatialTrack(com.jme3.animation.SpatialTrack) BoneTrack(com.jme3.animation.BoneTrack) Quaternion(com.jme3.math.Quaternion) Vector3f(com.jme3.math.Vector3f)

Example 8 with BoneTrack

use of com.jme3.animation.BoneTrack in project jmonkeyengine by jMonkeyEngine.

the class SceneLoader method buildAnimations.

private void buildAnimations() {
    if (skeleton == null)
        return;
    if (animList == null || animList.list.size() == 0) {
        animList = new AnimationList();
        for (long layerId : alayerMap.keySet()) {
            FbxObject layer = alayerMap.get(layerId);
            animList.add(layer.name, layer.name, 0, -1);
        }
    }
    // Extract aminations
    HashMap<String, Animation> anims = new HashMap<String, Animation>();
    for (AnimInverval animInfo : animList.list) {
        float realLength = 0;
        float length = (animInfo.lastFrame - animInfo.firstFrame) / this.animFrameRate;
        float animStart = animInfo.firstFrame / this.animFrameRate;
        float animStop = animInfo.lastFrame / this.animFrameRate;
        Animation anim = new Animation(animInfo.name, length);
        // Search source layer for animation nodes
        long sourceLayerId = 0L;
        for (long layerId : alayerMap.keySet()) {
            FbxObject layer = alayerMap.get(layerId);
            if (layer.name.equals(animInfo.layerName)) {
                sourceLayerId = layerId;
                break;
            }
        }
        // Build bone tracks
        for (FbxNode limb : limbMap.values()) {
            // Animation channels may have different keyframes (non-baked animation).
            //   So we have to restore intermediate values for all channels cause of JME requires
            //   a bone track as a single channel with collective transformation for each keyframe
            // Sorted unique timestamps
            Set<Long> stamps = new TreeSet<Long>();
            FbxAnimNode animTranslation = limb.animTranslation(sourceLayerId);
            FbxAnimNode animRotation = limb.animRotation(sourceLayerId);
            FbxAnimNode animScale = limb.animScale(sourceLayerId);
            boolean haveTranslation = haveAnyChannel(animTranslation);
            boolean haveRotation = haveAnyChannel(animRotation);
            boolean haveScale = haveAnyChannel(animScale);
            // Collect keyframes stamps
            if (haveTranslation)
                animTranslation.exportTimes(stamps);
            if (haveRotation)
                animRotation.exportTimes(stamps);
            if (haveScale)
                animScale.exportTimes(stamps);
            if (stamps.isEmpty())
                continue;
            long[] keyTimes = new long[stamps.size()];
            int cnt = 0;
            for (long t : stamps) keyTimes[cnt++] = t;
            // Calculate keys interval by animation time interval
            int firstKeyIndex = 0;
            int lastKeyIndex = keyTimes.length - 1;
            for (int i = 0; i < keyTimes.length; ++i) {
                // Translate into seconds
                float time = (float) (((double) keyTimes[i]) * secondsPerUnit);
                if (time <= animStart)
                    firstKeyIndex = i;
                if (time >= animStop && animStop >= 0) {
                    lastKeyIndex = i;
                    break;
                }
            }
            int keysCount = lastKeyIndex - firstKeyIndex + 1;
            if (keysCount <= 0)
                continue;
            float[] times = new float[keysCount];
            Vector3f[] translations = new Vector3f[keysCount];
            Quaternion[] rotations = new Quaternion[keysCount];
            Vector3f[] scales = null;
            // Calculate keyframes times
            for (int i = 0; i < keysCount; ++i) {
                int keyIndex = firstKeyIndex + i;
                // Translate into seconds
                float time = (float) (((double) keyTimes[keyIndex]) * secondsPerUnit);
                times[i] = time - animStart;
                realLength = Math.max(realLength, times[i]);
            }
            // Load keyframes from animation curves
            if (haveTranslation) {
                for (int i = 0; i < keysCount; ++i) {
                    int keyIndex = firstKeyIndex + i;
                    FbxAnimNode n = animTranslation;
                    // Why do it here but not in other places? FBX magic?
                    Vector3f tvec = n.getValue(keyTimes[keyIndex], n.value).subtractLocal(n.value);
                    translations[i] = tvec.divideLocal(unitSize);
                }
            } else {
                for (int i = 0; i < keysCount; ++i) translations[i] = Vector3f.ZERO;
            }
            RotationOrder ro = RotationOrder.EULER_XYZ;
            if (haveRotation) {
                for (int i = 0; i < keysCount; ++i) {
                    int keyIndex = firstKeyIndex + i;
                    FbxAnimNode n = animRotation;
                    Vector3f tvec = n.getValue(keyTimes[keyIndex], n.value);
                    rotations[i] = ro.rotate(tvec);
                }
            } else {
                for (int i = 0; i < keysCount; ++i) rotations[i] = Quaternion.IDENTITY;
            }
            if (haveScale) {
                scales = new Vector3f[keysCount];
                for (int i = 0; i < keysCount; ++i) {
                    int keyIndex = firstKeyIndex + i;
                    FbxAnimNode n = animScale;
                    Vector3f tvec = n.getValue(keyTimes[keyIndex], n.value);
                    scales[i] = tvec;
                }
            }
            BoneTrack track = null;
            if (haveScale)
                track = new BoneTrack(limb.boneIndex, times, translations, rotations, scales);
            else
                track = new BoneTrack(limb.boneIndex, times, translations, rotations);
            anim.addTrack(track);
        }
        if (realLength != length && animInfo.lastFrame == -1) {
            Track[] tracks = anim.getTracks();
            if (tracks == null || tracks.length == 0)
                continue;
            anim = new Animation(animInfo.name, realLength);
            for (Track track : tracks) anim.addTrack(track);
        }
        anims.put(anim.getName(), anim);
    }
    animControl.setAnimations(anims);
}
Also used : FbxObject(com.jme3.scene.plugins.fbx.objects.FbxObject) HashMap(java.util.HashMap) Quaternion(com.jme3.math.Quaternion) FbxAnimNode(com.jme3.scene.plugins.fbx.objects.FbxAnimNode) FbxNode(com.jme3.scene.plugins.fbx.objects.FbxNode) TreeSet(java.util.TreeSet) BoneTrack(com.jme3.animation.BoneTrack) AnimInverval(com.jme3.scene.plugins.fbx.AnimationList.AnimInverval) Vector3f(com.jme3.math.Vector3f) Animation(com.jme3.animation.Animation) BoneTrack(com.jme3.animation.BoneTrack) Track(com.jme3.animation.Track)

Example 9 with BoneTrack

use of com.jme3.animation.BoneTrack in project jmonkeyengine by jMonkeyEngine.

the class SkeletonLoader method endElement.

public void endElement(String uri, String name, String qName) {
    if (qName.equals("translate") || qName.equals("position") || qName.equals("scale")) {
    } else if (qName.equals("axis")) {
    } else if (qName.equals("rotate") || qName.equals("rotation")) {
        rotation = new Quaternion();
        axis.normalizeLocal();
        rotation.fromAngleNormalAxis(angle, axis);
        angle = 0;
        axis = null;
    } else if (qName.equals("bone")) {
        bone.setBindTransforms(position, rotation, scale);
        bone = null;
        position = null;
        rotation = null;
        scale = null;
    } else if (qName.equals("bonehierarchy")) {
        Bone[] bones = new Bone[indexToBone.size()];
        // also assign the bones to the bonelist
        for (Map.Entry<Integer, Bone> entry : indexToBone.entrySet()) {
            Bone bone = entry.getValue();
            bones[entry.getKey()] = bone;
        }
        indexToBone.clear();
        skeleton = new Skeleton(bones);
    } else if (qName.equals("animation")) {
        animations.add(animation);
        animation = null;
    } else if (qName.equals("track")) {
        if (track != null) {
            // if track has keyframes
            tracks.add(track);
            track = null;
        }
    } else if (qName.equals("tracks")) {
        BoneTrack[] trackList = tracks.toArray(new BoneTrack[tracks.size()]);
        animation.setTracks(trackList);
        tracks.clear();
    } else if (qName.equals("keyframe")) {
        assert time >= 0;
        assert position != null;
        assert rotation != null;
        times.add(time);
        translations.add(position);
        rotations.add(rotation);
        if (scale != null) {
            scales.add(scale);
        } else {
            scales.add(new Vector3f(1, 1, 1));
        }
        time = -1;
        position = null;
        rotation = null;
        scale = null;
    } else if (qName.equals("keyframes")) {
        if (times.size() > 0) {
            float[] timesArray = new float[times.size()];
            for (int i = 0; i < timesArray.length; i++) {
                timesArray[i] = times.get(i);
            }
            Vector3f[] transArray = translations.toArray(new Vector3f[translations.size()]);
            Quaternion[] rotArray = rotations.toArray(new Quaternion[rotations.size()]);
            Vector3f[] scalesArray = scales.toArray(new Vector3f[scales.size()]);
            track.setKeyframes(timesArray, transArray, rotArray, scalesArray);
        //track.setKeyframes(timesArray, transArray, rotArray);
        } else {
            track = null;
        }
        times.clear();
        translations.clear();
        rotations.clear();
        scales.clear();
    } else if (qName.equals("skeleton")) {
        nameToBone.clear();
    }
    assert elementStack.peek().equals(qName);
    elementStack.pop();
}
Also used : BoneTrack(com.jme3.animation.BoneTrack) Quaternion(com.jme3.math.Quaternion) Vector3f(com.jme3.math.Vector3f) Skeleton(com.jme3.animation.Skeleton) Bone(com.jme3.animation.Bone) HashMap(java.util.HashMap) Map(java.util.Map)

Aggregations

BoneTrack (com.jme3.animation.BoneTrack)9 Animation (com.jme3.animation.Animation)5 Quaternion (com.jme3.math.Quaternion)5 Vector3f (com.jme3.math.Vector3f)5 HashMap (java.util.HashMap)5 Bone (com.jme3.animation.Bone)4 SpatialTrack (com.jme3.animation.SpatialTrack)4 Track (com.jme3.animation.Track)3 AnimControl (com.jme3.animation.AnimControl)2 Skeleton (com.jme3.animation.Skeleton)2 Map (java.util.Map)2 AnimChannel (com.jme3.animation.AnimChannel)1 SkeletonControl (com.jme3.animation.SkeletonControl)1 Transform (com.jme3.math.Transform)1 Spatial (com.jme3.scene.Spatial)1 BoneContext (com.jme3.scene.plugins.blender.animations.BoneContext)1 AnimInverval (com.jme3.scene.plugins.fbx.AnimationList.AnimInverval)1 FbxAnimCurveNode (com.jme3.scene.plugins.fbx.anim.FbxAnimCurveNode)1 FbxAnimLayer (com.jme3.scene.plugins.fbx.anim.FbxAnimLayer)1 FbxAnimStack (com.jme3.scene.plugins.fbx.anim.FbxAnimStack)1