Search in sources :

Example 1 with BoneTrack

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

the class FbxToJmeTrack method toJmeTrackInternal.

private Track toJmeTrackInternal(int boneIndex, Transform inverseBindPose) {
    float duration = animStack.getDuration();
    FbxAnimCurveNode translationCurve = animCurves.get("Lcl Translation");
    FbxAnimCurveNode rotationCurve = animCurves.get("Lcl Rotation");
    FbxAnimCurveNode scalingCurve = animCurves.get("Lcl Scaling");
    long[] fbxTimes = getKeyTimes();
    float[] times = new float[fbxTimes.length];
    // Translations / Rotations must be set on all tracks.
    // (Required for jME3)
    Vector3f[] translations = new Vector3f[fbxTimes.length];
    Quaternion[] rotations = new Quaternion[fbxTimes.length];
    Vector3f[] scales = null;
    if (scalingCurve != null) {
        scales = new Vector3f[fbxTimes.length];
    }
    for (int i = 0; i < fbxTimes.length; i++) {
        long fbxTime = fbxTimes[i];
        float time = (float) (fbxTime * FbxAnimUtil.SECONDS_PER_UNIT);
        if (time > duration) {
            // Expand animation duration to fit the curve.
            duration = time;
            System.out.println("actual duration: " + duration);
        }
        times[i] = time;
        if (translationCurve != null) {
            translations[i] = translationCurve.getVector3Value(fbxTime);
        } else {
            translations[i] = new Vector3f();
        }
        if (rotationCurve != null) {
            rotations[i] = rotationCurve.getQuaternionValue(fbxTime);
            if (i > 0) {
                if (rotations[i - 1].dot(rotations[i]) < 0) {
                    System.out.println("rotation will go the long way, oh noes");
                    rotations[i - 1].negate();
                }
            }
        } else {
            rotations[i] = new Quaternion();
        }
        if (scalingCurve != null) {
            scales[i] = scalingCurve.getVector3Value(fbxTime);
        }
        if (inverseBindPose != null) {
            applyInverse(translations[i], rotations[i], scales != null ? scales[i] : null, inverseBindPose);
        }
    }
    if (boneIndex == -1) {
        return new SpatialTrack(times, translations, rotations, scales);
    } else {
        if (scales != null) {
            return new BoneTrack(boneIndex, times, translations, rotations, scales);
        } else {
            return new BoneTrack(boneIndex, times, translations, rotations);
        }
    }
}
Also used : SpatialTrack(com.jme3.animation.SpatialTrack) BoneTrack(com.jme3.animation.BoneTrack) Quaternion(com.jme3.math.Quaternion) Vector3f(com.jme3.math.Vector3f)

Example 2 with BoneTrack

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

the class FbxLoader method constructAnimations.

private void constructAnimations() {
    // In FBX, animation are not attached to any root.
    // They are implicitly global.
    // So, we need to use hueristics to find which node(s) 
    // an animation is associated with, so we can create the AnimControl
    // in the appropriate location in the scene.
    Map<FbxToJmeTrack, FbxToJmeTrack> pairs = new HashMap<FbxToJmeTrack, FbxToJmeTrack>();
    for (FbxAnimStack stack : animStacks) {
        for (FbxAnimLayer layer : stack.getLayers()) {
            for (FbxAnimCurveNode curveNode : layer.getAnimationCurveNodes()) {
                for (Map.Entry<FbxNode, String> nodePropertyEntry : curveNode.getInfluencedNodeProperties().entrySet()) {
                    FbxToJmeTrack lookupPair = new FbxToJmeTrack();
                    lookupPair.animStack = stack;
                    lookupPair.animLayer = layer;
                    lookupPair.node = nodePropertyEntry.getKey();
                    // Find if this pair is already stored
                    FbxToJmeTrack storedPair = pairs.get(lookupPair);
                    if (storedPair == null) {
                        // If not, store it.
                        storedPair = lookupPair;
                        pairs.put(storedPair, storedPair);
                    }
                    String property = nodePropertyEntry.getValue();
                    storedPair.animCurves.put(property, curveNode);
                }
            }
        }
    }
    // At this point we can construct the animation for all pairs ...
    for (FbxToJmeTrack pair : pairs.values()) {
        String animName = pair.animStack.getName();
        float duration = pair.animStack.getDuration();
        System.out.println("ANIMATION: " + animName + ", duration = " + duration);
        System.out.println("NODE: " + pair.node.getName());
        duration = pair.getDuration();
        if (pair.node instanceof FbxLimbNode) {
            // Find the spatial that has the skeleton for this limb.
            FbxLimbNode limbNode = (FbxLimbNode) pair.node;
            Bone bone = limbNode.getJmeBone();
            Spatial jmeSpatial = limbNode.getSkeletonHolder().getJmeObject();
            Skeleton skeleton = limbNode.getSkeletonHolder().getJmeSkeleton();
            // Get the animation control (create if missing).
            AnimControl animControl = jmeSpatial.getControl(AnimControl.class);
            if (animControl.getSkeleton() != skeleton) {
                throw new UnsupportedOperationException();
            }
            // Get the animation (create if missing).
            Animation anim = animControl.getAnim(animName);
            if (anim == null) {
                anim = new Animation(animName, duration);
                animControl.addAnim(anim);
            }
            // Find the bone index from the spatial's skeleton.
            int boneIndex = skeleton.getBoneIndex(bone);
            // Generate the bone track.
            BoneTrack bt = pair.toJmeBoneTrack(boneIndex, bone.getBindInverseTransform());
            // Add the bone track to the animation.
            anim.addTrack(bt);
        } else {
            // Create the spatial animation
            Animation anim = new Animation(animName, duration);
            anim.setTracks(new Track[] { pair.toJmeSpatialTrack() });
            // Get the animation control (create if missing).
            Spatial jmeSpatial = pair.node.getJmeObject();
            AnimControl animControl = jmeSpatial.getControl(AnimControl.class);
            if (animControl == null) {
                animControl = new AnimControl(null);
                jmeSpatial.addControl(animControl);
            }
            // Add the spatial animation
            animControl.addAnim(anim);
        }
    }
}
Also used : BoneTrack(com.jme3.animation.BoneTrack) HashMap(java.util.HashMap) FbxAnimCurveNode(com.jme3.scene.plugins.fbx.anim.FbxAnimCurveNode) AnimControl(com.jme3.animation.AnimControl) FbxNode(com.jme3.scene.plugins.fbx.node.FbxNode) Spatial(com.jme3.scene.Spatial) Animation(com.jme3.animation.Animation) FbxToJmeTrack(com.jme3.scene.plugins.fbx.anim.FbxToJmeTrack) Skeleton(com.jme3.animation.Skeleton) Bone(com.jme3.animation.Bone) FbxLimbNode(com.jme3.scene.plugins.fbx.anim.FbxLimbNode) FbxAnimLayer(com.jme3.scene.plugins.fbx.anim.FbxAnimLayer) HashMap(java.util.HashMap) Map(java.util.Map) FbxAnimStack(com.jme3.scene.plugins.fbx.anim.FbxAnimStack)

Example 3 with BoneTrack

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

the class SkeletonLoader method startElement.

public void startElement(String uri, String localName, String qName, Attributes attribs) throws SAXException {
    if (qName.equals("position") || qName.equals("translate")) {
        position = SAXUtil.parseVector3(attribs);
    } else if (qName.equals("rotation") || qName.equals("rotate")) {
        angle = SAXUtil.parseFloat(attribs.getValue("angle"));
    } else if (qName.equals("axis")) {
        assert elementStack.peek().equals("rotation") || elementStack.peek().equals("rotate");
        axis = SAXUtil.parseVector3(attribs);
    } else if (qName.equals("scale")) {
        scale = SAXUtil.parseVector3(attribs);
    } else if (qName.equals("keyframe")) {
        assert elementStack.peek().equals("keyframes");
        time = SAXUtil.parseFloat(attribs.getValue("time"));
    } else if (qName.equals("keyframes")) {
        assert elementStack.peek().equals("track");
    } else if (qName.equals("track")) {
        assert elementStack.peek().equals("tracks");
        String boneName = SAXUtil.parseString(attribs.getValue("bone"));
        Bone bone = nameToBone.get(boneName);
        int index = skeleton.getBoneIndex(bone);
        track = new BoneTrack(index);
    } else if (qName.equals("boneparent")) {
        assert elementStack.peek().equals("bonehierarchy");
        String boneName = attribs.getValue("bone");
        String parentName = attribs.getValue("parent");
        Bone bone = nameToBone.get(boneName);
        Bone parent = nameToBone.get(parentName);
        parent.addChild(bone);
    } else if (qName.equals("bone")) {
        assert elementStack.peek().equals("bones");
        // insert bone into indexed map
        bone = new Bone(attribs.getValue("name"));
        int id = SAXUtil.parseInt(attribs.getValue("id"));
        indexToBone.put(id, bone);
        nameToBone.put(bone.getName(), bone);
    } else if (qName.equals("tracks")) {
        assert elementStack.peek().equals("animation");
        tracks.clear();
    } else if (qName.equals("animation")) {
        assert elementStack.peek().equals("animations");
        String name = SAXUtil.parseString(attribs.getValue("name"));
        float length = SAXUtil.parseFloat(attribs.getValue("length"));
        animation = new Animation(name, length);
    } else if (qName.equals("bonehierarchy")) {
        assert elementStack.peek().equals("skeleton");
    } else if (qName.equals("animations")) {
        assert elementStack.peek().equals("skeleton");
        animations = new ArrayList<Animation>();
    } else if (qName.equals("bones")) {
        assert elementStack.peek().equals("skeleton");
    } else if (qName.equals("skeleton")) {
        assert elementStack.size() == 0;
    }
    elementStack.add(qName);
}
Also used : BoneTrack(com.jme3.animation.BoneTrack) Animation(com.jme3.animation.Animation) Bone(com.jme3.animation.Bone)

Example 4 with BoneTrack

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

the class AnimationHelper method applyAnimations.

/**
     * The method applies skeleton animations to the given node.
     * @param node
     *            the node where the animations will be applied
     * @param skeleton
     *            the skeleton of the node
     * @param animationMatchMethod
     *            the way animation should be matched with skeleton
     */
public void applyAnimations(Node node, Skeleton skeleton, AnimationMatchMethod animationMatchMethod) {
    node.addControl(new SkeletonControl(skeleton));
    blenderContext.setNodeForSkeleton(skeleton, node);
    List<BlenderAction> actions = this.getActions(skeleton, animationMatchMethod);
    if (actions.size() > 0) {
        List<Animation> animations = new ArrayList<Animation>();
        for (BlenderAction action : actions) {
            BoneTrack[] tracks = action.toTracks(skeleton, blenderContext);
            if (tracks != null && tracks.length > 0) {
                Animation boneAnimation = new Animation(action.getName(), action.getAnimationTime());
                boneAnimation.setTracks(tracks);
                animations.add(boneAnimation);
                Long animatedNodeOMA = ((Number) blenderContext.getMarkerValue(ObjectHelper.OMA_MARKER, node)).longValue();
                blenderContext.addAnimation(animatedNodeOMA, boneAnimation);
            }
        }
        if (animations.size() > 0) {
            AnimControl control = new AnimControl(skeleton);
            HashMap<String, Animation> anims = new HashMap<String, Animation>(animations.size());
            for (int i = 0; i < animations.size(); ++i) {
                Animation animation = animations.get(i);
                anims.put(animation.getName(), animation);
            }
            control.setAnimations(anims);
            node.addControl(control);
            // make sure that SkeletonControl is added AFTER the AnimControl
            SkeletonControl skeletonControl = node.getControl(SkeletonControl.class);
            if (skeletonControl != null) {
                node.removeControl(SkeletonControl.class);
                node.addControl(skeletonControl);
            }
        }
    }
}
Also used : BoneTrack(com.jme3.animation.BoneTrack) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) SkeletonControl(com.jme3.animation.SkeletonControl) AnimControl(com.jme3.animation.AnimControl) Animation(com.jme3.animation.Animation)

Example 5 with BoneTrack

use of com.jme3.animation.BoneTrack 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)

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