Search in sources :

Example 66 with Bone

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

the class FbxMesh method toJmeObject.

@Override
protected IntMap<Mesh> toJmeObject() {
    // Load clusters from SkinDeformer
    if (skinDeformer != null) {
        for (FbxCluster cluster : skinDeformer.getJmeObject()) {
            applyCluster(cluster);
        }
    }
    IrMesh irMesh = toIRMesh();
    // Trim bone weights to 4 weights per vertex.
    IrUtils.trimBoneWeights(irMesh);
    // Convert tangents / binormals to tangents with parity.
    IrUtils.toTangentsWithParity(irMesh);
    // Triangulate quads.
    IrUtils.triangulate(irMesh);
    // Split meshes by material indices.
    IntMap<IrMesh> irMeshes = IrUtils.splitByMaterial(irMesh);
    // Create a jME3 Mesh for each material index.
    IntMap<Mesh> jmeMeshes = new IntMap<Mesh>();
    for (IntMap.Entry<IrMesh> irMeshEntry : irMeshes) {
        Mesh jmeMesh = IrUtils.convertIrMeshToJmeMesh(irMeshEntry.getValue());
        jmeMeshes.put(irMeshEntry.getKey(), jmeMesh);
    }
    if (jmeMeshes.size() == 0) {
        // When will this actually happen? Not sure.
        logger.log(Level.WARNING, "Empty FBX mesh found (unusual).");
    }
    // It makes sense only if the mesh uses a single material!
    if (jmeMeshes.containsKey(-1) && jmeMeshes.size() > 1) {
        logger.log(Level.WARNING, "Mesh has polygons with no material " + "indices (unusual) - they will use material index 0.");
    }
    return jmeMeshes;
}
Also used : FbxCluster(com.jme3.scene.plugins.fbx.anim.FbxCluster) IntMap(com.jme3.util.IntMap) IrMesh(com.jme3.scene.plugins.IrMesh) Mesh(com.jme3.scene.Mesh) IrMesh(com.jme3.scene.plugins.IrMesh)

Example 67 with Bone

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

Example 68 with Bone

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

the class FbxSkin method generateBoneData.

private int generateBoneData(Mesh mesh, FbxMesh fbxMesh) {
    // Create bone buffers
    FloatBuffer boneWeightData = BufferUtils.createFloatBuffer(fbxMesh.vCount * 4);
    ByteBuffer boneIndicesData = BufferUtils.createByteBuffer(fbxMesh.vCount * 4);
    mesh.setBuffer(VertexBuffer.Type.BoneWeight, 4, boneWeightData);
    mesh.setBuffer(VertexBuffer.Type.BoneIndex, 4, boneIndicesData);
    mesh.getBuffer(VertexBuffer.Type.BoneWeight).setUsage(Usage.CpuOnly);
    mesh.getBuffer(VertexBuffer.Type.BoneIndex).setUsage(Usage.CpuOnly);
    VertexBuffer weightsHW = new VertexBuffer(Type.HWBoneWeight);
    VertexBuffer indicesHW = new VertexBuffer(Type.HWBoneIndex);
    // Setting usage to CpuOnly so that the buffer is not send empty to the GPU
    indicesHW.setUsage(Usage.CpuOnly);
    weightsHW.setUsage(Usage.CpuOnly);
    mesh.setBuffer(weightsHW);
    mesh.setBuffer(indicesHW);
    int bonesLimitExceeded = 0;
    // Accumulate skin bones influence into mesh buffers
    for (FbxNode limb : bones) {
        FbxCluster cluster = limb.skinToCluster.get(id);
        if (cluster == null || cluster.indexes == null || cluster.weights == null || cluster.indexes.length != cluster.weights.length)
            continue;
        if (limb.boneIndex > 255)
            throw new AssetLoadException("Bone index can't be packed into byte");
        for (int i = 0; i < cluster.indexes.length; ++i) {
            int vertexIndex = cluster.indexes[i];
            if (vertexIndex >= fbxMesh.reverseVertexMap.size())
                throw new AssetLoadException("Invalid skinning vertex index. Unexpected index lookup " + vertexIndex + " from " + fbxMesh.reverseVertexMap.size());
            List<Integer> dstVertices = fbxMesh.reverseVertexMap.get(vertexIndex);
            for (int j = 0; j < dstVertices.size(); ++j) {
                int v = dstVertices.get(j);
                // Append bone index and weight to vertex
                int offset;
                int smalestOffset = 0;
                float w = 0;
                float smalestW = Float.MAX_VALUE;
                for (offset = v * 4; offset < v * 4 + 4; ++offset) {
                    w = boneWeightData.get(offset);
                    if (w == 0)
                        break;
                    if (w < smalestW) {
                        smalestW = w;
                        smalestOffset = offset;
                    }
                }
                if (w == 0) {
                    boneWeightData.put(offset, (float) cluster.weights[i]);
                    boneIndicesData.put(offset, (byte) limb.boneIndex);
                } else {
                    if ((float) cluster.weights[i] > smalestW) {
                        // If current weight more than smallest, discard smallest
                        boneWeightData.put(smalestOffset, (float) cluster.weights[i]);
                        boneIndicesData.put(smalestOffset, (byte) limb.boneIndex);
                    }
                    bonesLimitExceeded++;
                }
            }
        }
    }
    if (bonesLimitExceeded > 0)
        scene.warning("Skinning support max 4 bone per vertex. Exceeding data of " + bonesLimitExceeded + " weights in mesh bones will be discarded");
    // Postprocess bones weights
    int maxWeightsPerVert = 0;
    boneWeightData.rewind();
    for (int v = 0; v < fbxMesh.vCount; v++) {
        float w0 = boneWeightData.get();
        float w1 = boneWeightData.get();
        float w2 = boneWeightData.get();
        float w3 = boneWeightData.get();
        if (w3 != 0) {
            maxWeightsPerVert = Math.max(maxWeightsPerVert, 4);
        } else if (w2 != 0) {
            maxWeightsPerVert = Math.max(maxWeightsPerVert, 3);
        } else if (w1 != 0) {
            maxWeightsPerVert = Math.max(maxWeightsPerVert, 2);
        } else if (w0 != 0) {
            maxWeightsPerVert = Math.max(maxWeightsPerVert, 1);
        }
        float sum = w0 + w1 + w2 + w3;
        if (sum != 1f) {
            // normalize weights
            float mult = (sum != 0) ? (1f / sum) : 0;
            boneWeightData.position(v * 4);
            boneWeightData.put(w0 * mult);
            boneWeightData.put(w1 * mult);
            boneWeightData.put(w2 * mult);
            boneWeightData.put(w3 * mult);
        }
    }
    return maxWeightsPerVert;
}
Also used : VertexBuffer(com.jme3.scene.VertexBuffer) FloatBuffer(java.nio.FloatBuffer) ByteBuffer(java.nio.ByteBuffer) AssetLoadException(com.jme3.asset.AssetLoadException)

Example 69 with Bone

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

the class FbxLimbNode method createBones.

private static void createBones(FbxNode skeletonHolderNode, FbxLimbNode limb, List<Bone> bones) {
    limb.skeletonHolder = skeletonHolderNode;
    Bone parentBone = limb.getJmeBone();
    bones.add(parentBone);
    for (FbxNode child : limb.children) {
        if (child instanceof FbxLimbNode) {
            FbxLimbNode childLimb = (FbxLimbNode) child;
            createBones(skeletonHolderNode, childLimb, bones);
            parentBone.addChild(childLimb.getJmeBone());
        }
    }
}
Also used : FbxNode(com.jme3.scene.plugins.fbx.node.FbxNode) Bone(com.jme3.animation.Bone)

Aggregations

Bone (com.jme3.animation.Bone)35 Vector3f (com.jme3.math.Vector3f)25 Quaternion (com.jme3.math.Quaternion)17 TempVars (com.jme3.util.TempVars)13 SixDofJoint (com.jme3.bullet.joints.SixDofJoint)10 FloatBuffer (java.nio.FloatBuffer)10 VertexBuffer (com.jme3.scene.VertexBuffer)8 HashMap (java.util.HashMap)8 Skeleton (com.jme3.animation.Skeleton)7 Matrix4f (com.jme3.math.Matrix4f)7 Transform (com.jme3.math.Transform)7 BoneContext (com.jme3.scene.plugins.blender.animations.BoneContext)7 ByteBuffer (java.nio.ByteBuffer)7 BoneTrack (com.jme3.animation.BoneTrack)6 Structure (com.jme3.scene.plugins.blender.file.Structure)6 ArrayList (java.util.ArrayList)6 AnimControl (com.jme3.animation.AnimControl)5 Spatial (com.jme3.scene.Spatial)5 Map (java.util.Map)5 Animation (com.jme3.animation.Animation)4