Search in sources :

Example 26 with Skeleton

use of com.jme3.animation.Skeleton 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 27 with Skeleton

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

the class SceneLoader method applySkinning.

private void applySkinning() {
    for (FbxBindPose pose : bindMap.values()) pose.fillBindTransforms();
    if (limbMap == null)
        return;
    List<Bone> bones = new ArrayList<>();
    for (FbxNode limb : limbMap.values()) {
        if (limb.bone != null) {
            bones.add(limb.bone);
            limb.buildBindPoseBoneTransform();
        }
    }
    skeleton = new Skeleton(bones.toArray(new Bone[bones.size()]));
    skeleton.setBindingPose();
    for (FbxNode limb : limbMap.values()) limb.setSkeleton(skeleton);
    for (FbxSkin skin : skinMap.values()) skin.generateSkinning();
    // Attach controls
    animControl = new AnimControl(skeleton);
    sceneNode.addControl(animControl);
    SkeletonControl control = new SkeletonControl(skeleton);
    sceneNode.addControl(control);
}
Also used : FbxNode(com.jme3.scene.plugins.fbx.objects.FbxNode) FbxBindPose(com.jme3.scene.plugins.fbx.objects.FbxBindPose) ArrayList(java.util.ArrayList) FbxSkin(com.jme3.scene.plugins.fbx.objects.FbxSkin) SkeletonControl(com.jme3.animation.SkeletonControl) Skeleton(com.jme3.animation.Skeleton) Bone(com.jme3.animation.Bone) AnimControl(com.jme3.animation.AnimControl)

Example 28 with Skeleton

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

the class FbxMesh method applyCluster.

public void applyCluster(FbxCluster cluster) {
    if (boneIndices == null) {
        boneIndices = new ArrayList[positions.length];
        boneWeights = new ArrayList[positions.length];
    }
    FbxLimbNode limb = cluster.getLimb();
    Bone bone = limb.getJmeBone();
    Skeleton skeleton = limb.getSkeletonHolder().getJmeSkeleton();
    int boneIndex = skeleton.getBoneIndex(bone);
    int[] positionIndices = cluster.getVertexIndices();
    double[] weights = cluster.getWeights();
    for (int i = 0; i < positionIndices.length; i++) {
        int positionIndex = positionIndices[i];
        float boneWeight = (float) weights[i];
        ArrayList<Integer> boneIndicesForVertex = boneIndices[positionIndex];
        ArrayList<Float> boneWeightsForVertex = boneWeights[positionIndex];
        if (boneIndicesForVertex == null) {
            boneIndicesForVertex = new ArrayList<Integer>();
            boneWeightsForVertex = new ArrayList<Float>();
            boneIndices[positionIndex] = boneIndicesForVertex;
            boneWeights[positionIndex] = boneWeightsForVertex;
        }
        boneIndicesForVertex.add(boneIndex);
        boneWeightsForVertex.add(boneWeight);
    }
}
Also used : Skeleton(com.jme3.animation.Skeleton) Bone(com.jme3.animation.Bone) FbxLimbNode(com.jme3.scene.plugins.fbx.anim.FbxLimbNode)

Example 29 with Skeleton

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

the class FbxNode method getPreferredParent.

/**
     * If this geometry node is deformed by a skeleton, this
     * returns the node containing the skeleton.
     * 
     * In jME3, a mesh can be deformed by a skeleton only if it is 
     * a child of the node containing the skeleton. However, this
     * is not a requirement in FBX, so we have to modify the scene graph
     * of the loaded model to adjust for this.
     * This happens automatically in 
     * {@link #createScene(com.jme3.scene.plugins.fbx.node.FbxNode)}.
     * 
     * @return The model this node would like to be a child of, or null
     * if no preferred parent.
     */
public FbxNode getPreferredParent() {
    if (!(nodeAttribute instanceof FbxMesh)) {
        return null;
    }
    FbxMesh fbxMesh = (FbxMesh) nodeAttribute;
    FbxSkinDeformer deformer = fbxMesh.getSkinDeformer();
    FbxNode preferredParent = null;
    if (deformer != null) {
        for (FbxCluster cluster : deformer.getJmeObject()) {
            FbxLimbNode limb = cluster.getLimb();
            if (preferredParent == null) {
                preferredParent = limb.getSkeletonHolder();
            } else if (preferredParent != limb.getSkeletonHolder()) {
                logger.log(Level.WARNING, "A mesh is being deformed by multiple skeletons. " + "Only one skeleton will work, ignoring other skeletons.");
            }
        }
    }
    return preferredParent;
}
Also used : FbxCluster(com.jme3.scene.plugins.fbx.anim.FbxCluster) FbxMesh(com.jme3.scene.plugins.fbx.mesh.FbxMesh) FbxSkinDeformer(com.jme3.scene.plugins.fbx.anim.FbxSkinDeformer) FbxLimbNode(com.jme3.scene.plugins.fbx.anim.FbxLimbNode)

Example 30 with Skeleton

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

the class SkeletonLoader method load.

public Object load(InputStream in) throws IOException {
    try {
        // Added by larynx 25.06.2011
        // Android needs the namespace aware flag set to true 
        // Kirill 30.06.2011
        // Now, hack is applied for both desktop and android to avoid
        // checking with JmeSystem.
        SAXParserFactory factory = SAXParserFactory.newInstance();
        factory.setNamespaceAware(true);
        XMLReader xr = factory.newSAXParser().getXMLReader();
        xr.setContentHandler(this);
        xr.setErrorHandler(this);
        InputStreamReader r = new InputStreamReader(in);
        xr.parse(new InputSource(r));
        if (animations == null) {
            animations = new ArrayList<Animation>();
        }
        AnimData data = new AnimData(skeleton, animations);
        skeleton = null;
        animations = null;
        return data;
    } catch (SAXException ex) {
        IOException ioEx = new IOException("Error while parsing Ogre3D dotScene");
        ioEx.initCause(ex);
        fullReset();
        throw ioEx;
    } catch (ParserConfigurationException ex) {
        IOException ioEx = new IOException("Error while parsing Ogre3D dotScene");
        ioEx.initCause(ex);
        fullReset();
        throw ioEx;
    }
}
Also used : InputSource(org.xml.sax.InputSource) InputStreamReader(java.io.InputStreamReader) Animation(com.jme3.animation.Animation) IOException(java.io.IOException) ParserConfigurationException(javax.xml.parsers.ParserConfigurationException) XMLReader(org.xml.sax.XMLReader) SAXParserFactory(javax.xml.parsers.SAXParserFactory) SAXException(org.xml.sax.SAXException)

Aggregations

Quaternion (com.jme3.math.Quaternion)13 Vector3f (com.jme3.math.Vector3f)13 Bone (com.jme3.animation.Bone)11 Animation (com.jme3.animation.Animation)7 Skeleton (com.jme3.animation.Skeleton)7 AnimControl (com.jme3.animation.AnimControl)6 BoneTrack (com.jme3.animation.BoneTrack)6 TempVars (com.jme3.util.TempVars)6 HashMap (java.util.HashMap)6 SkeletonControl (com.jme3.animation.SkeletonControl)5 Material (com.jme3.material.Material)3 Transform (com.jme3.math.Transform)3 Node (com.jme3.scene.Node)3 Spatial (com.jme3.scene.Spatial)3 AnimChannel (com.jme3.animation.AnimChannel)2 Track (com.jme3.animation.Track)2 SixDofJoint (com.jme3.bullet.joints.SixDofJoint)2 DirectionalLight (com.jme3.light.DirectionalLight)2 Matrix4f (com.jme3.math.Matrix4f)2 Geometry (com.jme3.scene.Geometry)2