Search in sources :

Example 11 with Track

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

the class ChaseCamera method updateCamera.

/**
     * Updates the camera, should only be called internally
     */
protected void updateCamera(float tpf) {
    if (enabled) {
        targetLocation.set(target.getWorldTranslation()).addLocal(lookAtOffset);
        if (smoothMotion) {
            //computation of target direction
            targetDir.set(targetLocation).subtractLocal(prevPos);
            float dist = targetDir.length();
            //Low pass filtering on the target postition to avoid shaking when physics are enabled.
            if (offsetDistance < dist) {
                //target moves, start chasing.
                chasing = true;
                //target moves, start trailing if it has to.
                if (trailingEnabled) {
                    trailing = true;
                }
                //target moves...
                targetMoves = true;
            } else {
                //We do not if the player is rotationg the cam
                if (targetMoves && !canRotate) {
                    if (targetRotation - rotation > trailingRotationInertia) {
                        targetRotation = rotation + trailingRotationInertia;
                    } else if (targetRotation - rotation < -trailingRotationInertia) {
                        targetRotation = rotation - trailingRotationInertia;
                    }
                }
                //Target stops
                targetMoves = false;
            }
            //the user is rotating the cam by dragging the mouse
            if (canRotate) {
                //reseting the trailing lerp factor
                trailingLerpFactor = 0;
                //stop trailing user has the control
                trailing = false;
            }
            if (trailingEnabled && trailing) {
                if (targetMoves) {
                    //computation if the inverted direction of the target
                    Vector3f a = targetDir.negate().normalizeLocal();
                    //the x unit vector
                    Vector3f b = Vector3f.UNIT_X;
                    //2d is good enough
                    a.y = 0;
                    //computation of the rotation angle between the x axis and the trail
                    if (targetDir.z > 0) {
                        targetRotation = FastMath.TWO_PI - FastMath.acos(a.dot(b));
                    } else {
                        targetRotation = FastMath.acos(a.dot(b));
                    }
                    if (targetRotation - rotation > FastMath.PI || targetRotation - rotation < -FastMath.PI) {
                        targetRotation -= FastMath.TWO_PI;
                    }
                    //if there is an important change in the direction while trailing reset of the lerp factor to avoid jumpy movements
                    if (targetRotation != previousTargetRotation && FastMath.abs(targetRotation - previousTargetRotation) > FastMath.PI / 8) {
                        trailingLerpFactor = 0;
                    }
                    previousTargetRotation = targetRotation;
                }
                //computing lerp factor
                trailingLerpFactor = Math.min(trailingLerpFactor + tpf * tpf * trailingSensitivity, 1);
                //computing rotation by linear interpolation
                rotation = FastMath.interpolateLinear(trailingLerpFactor, rotation, targetRotation);
                //if the rotation is near the target rotation we're good, that's over
                if (targetRotation + 0.01f >= rotation && targetRotation - 0.01f <= rotation) {
                    trailing = false;
                    trailingLerpFactor = 0;
                }
            }
            //linear interpolation of the distance while chasing
            if (chasing) {
                distance = temp.set(targetLocation).subtractLocal(cam.getLocation()).length();
                distanceLerpFactor = Math.min(distanceLerpFactor + (tpf * tpf * chasingSensitivity * 0.05f), 1);
                distance = FastMath.interpolateLinear(distanceLerpFactor, distance, targetDistance);
                if (targetDistance + 0.01f >= distance && targetDistance - 0.01f <= distance) {
                    distanceLerpFactor = 0;
                    chasing = false;
                }
            }
            //linear interpolation of the distance while zooming
            if (zooming) {
                distanceLerpFactor = Math.min(distanceLerpFactor + (tpf * tpf * zoomSensitivity), 1);
                distance = FastMath.interpolateLinear(distanceLerpFactor, distance, targetDistance);
                if (targetDistance + 0.1f >= distance && targetDistance - 0.1f <= distance) {
                    zooming = false;
                    distanceLerpFactor = 0;
                }
            }
            //linear interpolation of the rotation while rotating horizontally
            if (rotating) {
                rotationLerpFactor = Math.min(rotationLerpFactor + tpf * tpf * rotationSensitivity, 1);
                rotation = FastMath.interpolateLinear(rotationLerpFactor, rotation, targetRotation);
                if (targetRotation + 0.01f >= rotation && targetRotation - 0.01f <= rotation) {
                    rotating = false;
                    rotationLerpFactor = 0;
                }
            }
            //linear interpolation of the rotation while rotating vertically
            if (vRotating) {
                vRotationLerpFactor = Math.min(vRotationLerpFactor + tpf * tpf * rotationSensitivity, 1);
                vRotation = FastMath.interpolateLinear(vRotationLerpFactor, vRotation, targetVRotation);
                if (targetVRotation + 0.01f >= vRotation && targetVRotation - 0.01f <= vRotation) {
                    vRotating = false;
                    vRotationLerpFactor = 0;
                }
            }
            //computing the position
            computePosition();
            //setting the position at last
            cam.setLocation(pos.addLocal(lookAtOffset));
        } else {
            //easy no smooth motion
            vRotation = targetVRotation;
            rotation = targetRotation;
            distance = targetDistance;
            computePosition();
            cam.setLocation(pos.addLocal(lookAtOffset));
        }
        //keeping track on the previous position of the target
        prevPos.set(targetLocation);
        //the cam looks at the target
        cam.lookAt(targetLocation, initialUpVec);
    }
}
Also used : Vector3f(com.jme3.math.Vector3f)

Example 12 with Track

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

the class SimulationNode method simulateSkeleton.

/**
     * Simulates the bone node.
     */
private void simulateSkeleton() {
    LOGGER.fine("Simulating skeleton.");
    Set<Long> alteredOmas = new HashSet<Long>();
    if (animations != null) {
        TempVars vars = TempVars.get();
        AnimChannel animChannel = animControl.createChannel();
        for (Animation animation : animations) {
            float[] animationTimeBoundaries = this.computeAnimationTimeBoundaries(animation);
            int maxFrame = (int) animationTimeBoundaries[0];
            float maxTime = animationTimeBoundaries[1];
            Map<Integer, VirtualTrack> tracks = new HashMap<Integer, VirtualTrack>();
            for (int frame = 0; frame < maxFrame; ++frame) {
                // this MUST be done here, otherwise setting next frame of animation will
                // lead to possible errors
                this.reset();
                // first set proper time for all bones in all the tracks ...
                for (Track track : animation.getTracks()) {
                    float time = ((BoneTrack) track).getTimes()[frame];
                    track.setTime(time, 1, animControl, animChannel, vars);
                    skeleton.updateWorldVectors();
                }
                // ... and then apply constraints from the root bone to the last child ...
                Set<Long> applied = new HashSet<Long>();
                for (Bone rootBone : skeleton.getRoots()) {
                    // ignore the 0-indexed bone
                    if (skeleton.getBoneIndex(rootBone) > 0) {
                        this.applyConstraints(rootBone, alteredOmas, applied, frame, new Stack<Bone>());
                    }
                }
                // ... add virtual tracks if neccessary, for bones that were altered but had no tracks before ...
                for (Long boneOMA : alteredOmas) {
                    BoneContext boneContext = blenderContext.getBoneContext(boneOMA);
                    int boneIndex = skeleton.getBoneIndex(boneContext.getBone());
                    if (!tracks.containsKey(boneIndex)) {
                        tracks.put(boneIndex, new VirtualTrack(boneContext.getBone().getName(), maxFrame, maxTime));
                    }
                }
                alteredOmas.clear();
                // ... and fill in another frame in the result track
                for (Entry<Integer, VirtualTrack> trackEntry : tracks.entrySet()) {
                    Bone bone = skeleton.getBone(trackEntry.getKey());
                    Transform startTransform = boneStartTransforms.get(bone);
                    // track contains differences between the frame position and bind positions of bones/spatials
                    Vector3f bonePositionDifference = bone.getLocalPosition().subtract(startTransform.getTranslation());
                    Quaternion boneRotationDifference = startTransform.getRotation().inverse().mult(bone.getLocalRotation()).normalizeLocal();
                    Vector3f boneScaleDifference = bone.getLocalScale().divide(startTransform.getScale());
                    trackEntry.getValue().setTransform(frame, new Transform(bonePositionDifference, boneRotationDifference, boneScaleDifference));
                }
            }
            for (Entry<Integer, VirtualTrack> trackEntry : tracks.entrySet()) {
                Track newTrack = trackEntry.getValue().getAsBoneTrack(trackEntry.getKey());
                if (newTrack != null) {
                    boolean trackReplaced = false;
                    for (Track track : animation.getTracks()) {
                        if (((BoneTrack) track).getTargetBoneIndex() == trackEntry.getKey().intValue()) {
                            animation.removeTrack(track);
                            animation.addTrack(newTrack);
                            trackReplaced = true;
                            break;
                        }
                    }
                    if (!trackReplaced) {
                        animation.addTrack(newTrack);
                    }
                }
            }
        }
        vars.release();
        animControl.clearChannels();
        this.reset();
    }
}
Also used : HashMap(java.util.HashMap) Quaternion(com.jme3.math.Quaternion) AnimChannel(com.jme3.animation.AnimChannel) TempVars(com.jme3.util.TempVars) BoneContext(com.jme3.scene.plugins.blender.animations.BoneContext) Vector3f(com.jme3.math.Vector3f) Animation(com.jme3.animation.Animation) Bone(com.jme3.animation.Bone) Transform(com.jme3.math.Transform) SpatialTrack(com.jme3.animation.SpatialTrack) BoneTrack(com.jme3.animation.BoneTrack) Track(com.jme3.animation.Track) HashSet(java.util.HashSet)

Example 13 with Track

use of com.jme3.animation.Track 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 14 with Track

use of com.jme3.animation.Track 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 15 with Track

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

the class SpatialTrack method setTime.

/**
     * 
     * Modify the spatial which this track modifies.
     * 
     * @param time
     *            the current time of the animation
     */
public void setTime(float time, float weight, AnimControl control, AnimChannel channel, TempVars vars) {
    Spatial spatial = control.getSpatial();
    Vector3f tempV = vars.vect1;
    Vector3f tempS = vars.vect2;
    Quaternion tempQ = vars.quat1;
    Vector3f tempV2 = vars.vect3;
    Vector3f tempS2 = vars.vect4;
    Quaternion tempQ2 = vars.quat2;
    int lastFrame = times.length - 1;
    if (time < 0 || lastFrame == 0) {
        if (rotations != null)
            rotations.get(0, tempQ);
        if (translations != null)
            translations.get(0, tempV);
        if (scales != null) {
            scales.get(0, tempS);
        }
    } else if (time >= times[lastFrame]) {
        if (rotations != null)
            rotations.get(lastFrame, tempQ);
        if (translations != null)
            translations.get(lastFrame, tempV);
        if (scales != null) {
            scales.get(lastFrame, tempS);
        }
    } else {
        int startFrame = 0;
        int endFrame = 1;
        // use lastFrame so we never overflow the array
        for (int i = 0; i < lastFrame && times[i] < time; ++i) {
            startFrame = i;
            endFrame = i + 1;
        }
        float blend = (time - times[startFrame]) / (times[endFrame] - times[startFrame]);
        if (rotations != null)
            rotations.get(startFrame, tempQ);
        if (translations != null)
            translations.get(startFrame, tempV);
        if (scales != null) {
            scales.get(startFrame, tempS);
        }
        if (rotations != null)
            rotations.get(endFrame, tempQ2);
        if (translations != null)
            translations.get(endFrame, tempV2);
        if (scales != null) {
            scales.get(endFrame, tempS2);
        }
        tempQ.nlerp(tempQ2, blend);
        tempV.interpolateLocal(tempV2, blend);
        tempS.interpolateLocal(tempS2, blend);
    }
    if (translations != null)
        spatial.setLocalTranslation(tempV);
    if (rotations != null)
        spatial.setLocalRotation(tempQ);
    if (scales != null) {
        spatial.setLocalScale(tempS);
    }
}
Also used : Spatial(com.jme3.scene.Spatial) Quaternion(com.jme3.math.Quaternion) Vector3f(com.jme3.math.Vector3f)

Aggregations

BoneTrack (com.jme3.animation.BoneTrack)9 Vector3f (com.jme3.math.Vector3f)9 Quaternion (com.jme3.math.Quaternion)7 Animation (com.jme3.animation.Animation)5 SpatialTrack (com.jme3.animation.SpatialTrack)5 Spatial (com.jme3.scene.Spatial)5 HashMap (java.util.HashMap)5 Bone (com.jme3.animation.Bone)4 Track (com.jme3.animation.Track)4 Skeleton (com.jme3.animation.Skeleton)2 Node (com.jme3.scene.Node)2 Map (java.util.Map)2 AnimChannel (com.jme3.animation.AnimChannel)1 AnimControl (com.jme3.animation.AnimControl)1 AudioNode (com.jme3.audio.AudioNode)1 ParticleEmitter (com.jme3.effect.ParticleEmitter)1 InputCapsule (com.jme3.export.InputCapsule)1 OutputCapsule (com.jme3.export.OutputCapsule)1 Savable (com.jme3.export.Savable)1 TouchEvent (com.jme3.input.event.TouchEvent)1