Search in sources :

Example 6 with BoneContext

use of com.jme3.scene.plugins.blender.animations.BoneContext in project jmonkeyengine by jMonkeyEngine.

the class SimulationNode method applyConstraints.

/**
     * Applies constraints to the given bone and its children.
     * The goal is to apply constraint from root bone to the last child.
     * @param bone
     *            the bone whose constraints will be applied
     * @param alteredOmas
     *            the set of OMAS of the altered bones (is populated if necessary)
     * @param frame
     *            the current frame of the animation
     * @param bonesStack
     *            the stack of bones used to avoid infinite loops while applying constraints
     */
private void applyConstraints(Bone bone, Set<Long> alteredOmas, Set<Long> applied, int frame, Stack<Bone> bonesStack) {
    if (!bonesStack.contains(bone)) {
        bonesStack.push(bone);
        BoneContext boneContext = blenderContext.getBoneContext(bone);
        if (!applied.contains(boneContext.getBoneOma())) {
            List<Constraint> constraints = this.findConstraints(boneContext.getBoneOma(), blenderContext);
            if (constraints != null && constraints.size() > 0) {
                for (Constraint constraint : constraints) {
                    if (constraint.getTargetOMA() != null && constraint.getTargetOMA() > 0L) {
                        // first apply constraints of the target bone
                        BoneContext targetBone = blenderContext.getBoneContext(constraint.getTargetOMA());
                        this.applyConstraints(targetBone.getBone(), alteredOmas, applied, frame, bonesStack);
                    }
                    constraint.apply(frame);
                    if (constraint.getAlteredOmas() != null) {
                        alteredOmas.addAll(constraint.getAlteredOmas());
                    }
                    alteredOmas.add(boneContext.getBoneOma());
                }
            }
            applied.add(boneContext.getBoneOma());
        }
        List<Bone> children = bone.getChildren();
        if (children != null && children.size() > 0) {
            for (Bone child : bone.getChildren()) {
                this.applyConstraints(child, alteredOmas, applied, frame, bonesStack);
            }
        }
        bonesStack.pop();
    }
}
Also used : BoneContext(com.jme3.scene.plugins.blender.animations.BoneContext) Bone(com.jme3.animation.Bone)

Example 7 with BoneContext

use of com.jme3.scene.plugins.blender.animations.BoneContext 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 8 with BoneContext

use of com.jme3.scene.plugins.blender.animations.BoneContext in project jmonkeyengine by jMonkeyEngine.

the class ConstraintDefinition method applyOwnerTransform.

/**
     * The method applies the given transformation to the owner.
     * @param ownerTransform
     *            the transformation to apply to the owner
     * @param ownerSpace
     *            the space that defines which owner's transformation (ie. global, local, etc. will be set)
     */
protected void applyOwnerTransform(Transform ownerTransform, Space ownerSpace) {
    if (this.getOwner() instanceof Bone) {
        BoneContext boneContext = blenderContext.getBoneContext(ownerOMA);
        constraintHelper.applyTransform(boneContext.getArmatureObjectOMA(), boneContext.getBone().getName(), ownerSpace, ownerTransform);
    } else {
        constraintHelper.applyTransform(ownerOMA, null, ownerSpace, ownerTransform);
    }
}
Also used : BoneContext(com.jme3.scene.plugins.blender.animations.BoneContext) Bone(com.jme3.animation.Bone)

Example 9 with BoneContext

use of com.jme3.scene.plugins.blender.animations.BoneContext in project jmonkeyengine by jMonkeyEngine.

the class ConstraintDefinitionIK method bake.

@Override
public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) {
    if (influence == 0 || !trackToBeChanged || targetTransform == null || bonesCount == 0) {
        // no need to do anything
        return;
    }
    if (bones == null) {
        bones = new BonesChain((Bone) this.getOwner(), useTail, bonesAffected, alteredOmas, blenderContext);
    }
    if (bones.size() == 0) {
        bonesCount = 0;
        // no need to do anything
        return;
    }
    double distanceFromTarget = Double.MAX_VALUE;
    target.set(targetTransform.getTranslation().x, targetTransform.getTranslation().y, targetTransform.getTranslation().z);
    if (bonesCount < 0) {
        bonesCount = bones.size();
        rotationVectors = new Vector3d[bonesCount];
        for (int i = 0; i < bonesCount; ++i) {
            rotationVectors[i] = new Vector3d();
        }
        J = new Matrix(3, bonesCount);
    }
    BoneContext topBone = bones.get(0);
    for (int i = 0; i < iterations; ++i) {
        DTransform topBoneTransform = bones.getWorldTransform(topBone);
        // effector
        Vector3d e = topBoneTransform.getTranslation().add(topBoneTransform.getRotation().mult(Vector3d.UNIT_Y).multLocal(topBone.getLength()));
        distanceFromTarget = e.distance(target);
        if (distanceFromTarget <= MIN_DISTANCE) {
            break;
        }
        deltaP.setColumn(0, 0, target.x - e.x, target.y - e.y, target.z - e.z);
        int column = 0;
        for (BoneContext boneContext : bones) {
            DTransform boneWorldTransform = bones.getWorldTransform(boneContext);
            // current join position
            Vector3d j = boneWorldTransform.getTranslation();
            Vector3d vectorFromJointToEffector = e.subtract(j);
            vectorFromJointToEffector.cross(target.subtract(j), rotationVectors[column]).normalizeLocal();
            rotationVectors[column].cross(vectorFromJointToEffector, col);
            J.setColumn(col, column++);
        }
        Matrix J_1 = J.pseudoinverse();
        SimpleMatrix deltaThetas = J_1.mult(deltaP);
        if (deltaThetas.elementMaxAbs() < MIN_ANGLE_CHANGE) {
            break;
        }
        for (int j = 0; j < deltaThetas.numRows(); ++j) {
            double angle = deltaThetas.get(j, 0);
            Vector3d rotationVector = rotationVectors[j];
            tempDQuaternion.fromAngleAxis(angle, rotationVector);
            BoneContext boneContext = bones.get(j);
            Bone bone = boneContext.getBone();
            if (bone.equals(this.getOwner())) {
                if (boneContext.isLockX()) {
                    tempDQuaternion.set(0, tempDQuaternion.getY(), tempDQuaternion.getZ(), tempDQuaternion.getW());
                }
                if (boneContext.isLockY()) {
                    tempDQuaternion.set(tempDQuaternion.getX(), 0, tempDQuaternion.getZ(), tempDQuaternion.getW());
                }
                if (boneContext.isLockZ()) {
                    tempDQuaternion.set(tempDQuaternion.getX(), tempDQuaternion.getY(), 0, tempDQuaternion.getW());
                }
            }
            DTransform boneTransform = bones.getWorldTransform(boneContext);
            boneTransform.getRotation().set(tempDQuaternion.mult(boneTransform.getRotation()));
            bones.setWorldTransform(boneContext, boneTransform);
        }
    }
    // applying the results
    for (int i = bonesCount - 1; i >= 0; --i) {
        BoneContext boneContext = bones.get(i);
        DTransform transform = bones.getWorldTransform(boneContext);
        constraintHelper.applyTransform(boneContext.getArmatureObjectOMA(), boneContext.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD, transform.toTransform());
    }
    // need to reload them again
    bones = null;
}
Also used : SimpleMatrix(org.ejml.simple.SimpleMatrix) Matrix(com.jme3.scene.plugins.blender.math.Matrix) SimpleMatrix(org.ejml.simple.SimpleMatrix) Vector3d(com.jme3.scene.plugins.blender.math.Vector3d) BoneContext(com.jme3.scene.plugins.blender.animations.BoneContext) DTransform(com.jme3.scene.plugins.blender.math.DTransform) Bone(com.jme3.animation.Bone)

Example 10 with BoneContext

use of com.jme3.scene.plugins.blender.animations.BoneContext 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)

Aggregations

BoneContext (com.jme3.scene.plugins.blender.animations.BoneContext)8 Bone (com.jme3.animation.Bone)7 Vector3f (com.jme3.math.Vector3f)4 Matrix4f (com.jme3.math.Matrix4f)3 Quaternion (com.jme3.math.Quaternion)3 Transform (com.jme3.math.Transform)3 Spatial (com.jme3.scene.Spatial)3 TempVars (com.jme3.util.TempVars)3 BoneTrack (com.jme3.animation.BoneTrack)2 SpatialTrack (com.jme3.animation.SpatialTrack)2 HashSet (java.util.HashSet)2 AnimChannel (com.jme3.animation.AnimChannel)1 Animation (com.jme3.animation.Animation)1 Skeleton (com.jme3.animation.Skeleton)1 Track (com.jme3.animation.Track)1 Structure (com.jme3.scene.plugins.blender.file.Structure)1 DTransform (com.jme3.scene.plugins.blender.math.DTransform)1 Matrix (com.jme3.scene.plugins.blender.math.Matrix)1 Vector3d (com.jme3.scene.plugins.blender.math.Vector3d)1 ObjectHelper (com.jme3.scene.plugins.blender.objects.ObjectHelper)1