Search in sources :

Example 11 with FbxNode

use of com.jme3.scene.plugins.fbx.node.FbxNode 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 12 with FbxNode

use of com.jme3.scene.plugins.fbx.node.FbxNode in project jmonkeyengine by jMonkeyEngine.

the class FbxNode method createScene.

public static Spatial createScene(FbxNode fbxNode) {
    Spatial jmeSpatial = fbxNode.getJmeObject();
    if (jmeSpatial instanceof Node) {
        // Attach children to Node
        Node jmeNode = (Node) jmeSpatial;
        for (FbxNode fbxChild : fbxNode.children) {
            if (!(fbxChild instanceof FbxLimbNode)) {
                createScene(fbxChild);
                FbxNode preferredParent = fbxChild.getPreferredParent();
                Spatial jmeChild = fbxChild.getJmeObject();
                if (preferredParent != null) {
                    System.out.println("Preferred parent for " + fbxChild + " is " + preferredParent);
                    Node jmePreferredParent = (Node) preferredParent.getJmeObject();
                    relocateSpatial(jmeChild, fbxChild.jmeWorldNodeTransform, preferredParent.jmeWorldNodeTransform);
                    jmePreferredParent.attachChild(jmeChild);
                } else {
                    jmeNode.attachChild(jmeChild);
                }
            }
        }
    }
    if (fbxNode.skeleton != null) {
        jmeSpatial.addControl(new AnimControl(fbxNode.skeleton));
        jmeSpatial.addControl(new SkeletonControl(fbxNode.skeleton));
        SkeletonDebugger sd = new SkeletonDebugger("debug", fbxNode.skeleton);
        Material mat = new Material(fbxNode.assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        mat.getAdditionalRenderState().setWireframe(true);
        mat.getAdditionalRenderState().setDepthTest(false);
        mat.setColor("Color", ColorRGBA.Green);
        sd.setMaterial(mat);
        ((Node) jmeSpatial).attachChild(sd);
    }
    return jmeSpatial;
}
Also used : SkeletonDebugger(com.jme3.scene.debug.SkeletonDebugger) Spatial(com.jme3.scene.Spatial) FbxLimbNode(com.jme3.scene.plugins.fbx.anim.FbxLimbNode) Node(com.jme3.scene.Node) FbxAnimCurveNode(com.jme3.scene.plugins.fbx.anim.FbxAnimCurveNode) SkeletonControl(com.jme3.animation.SkeletonControl) Material(com.jme3.material.Material) FbxMaterial(com.jme3.scene.plugins.fbx.material.FbxMaterial) FbxLimbNode(com.jme3.scene.plugins.fbx.anim.FbxLimbNode) AnimControl(com.jme3.animation.AnimControl)

Example 13 with FbxNode

use of com.jme3.scene.plugins.fbx.node.FbxNode 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 14 with FbxNode

use of com.jme3.scene.plugins.fbx.node.FbxNode 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 15 with FbxNode

use of com.jme3.scene.plugins.fbx.node.FbxNode 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

FbxNode (com.jme3.scene.plugins.fbx.node.FbxNode)6 Bone (com.jme3.animation.Bone)4 FbxLimbNode (com.jme3.scene.plugins.fbx.anim.FbxLimbNode)4 FbxNode (com.jme3.scene.plugins.fbx.objects.FbxNode)4 AnimControl (com.jme3.animation.AnimControl)3 FbxAnimCurveNode (com.jme3.scene.plugins.fbx.anim.FbxAnimCurveNode)3 HashMap (java.util.HashMap)3 Animation (com.jme3.animation.Animation)2 BoneTrack (com.jme3.animation.BoneTrack)2 Skeleton (com.jme3.animation.Skeleton)2 SkeletonControl (com.jme3.animation.SkeletonControl)2 Material (com.jme3.material.Material)2 Node (com.jme3.scene.Node)2 Spatial (com.jme3.scene.Spatial)2 FbxAnimNode (com.jme3.scene.plugins.fbx.objects.FbxAnimNode)2 FbxBindPose (com.jme3.scene.plugins.fbx.objects.FbxBindPose)2 FbxMesh (com.jme3.scene.plugins.fbx.objects.FbxMesh)2 FbxObject (com.jme3.scene.plugins.fbx.objects.FbxObject)2 Map (java.util.Map)2 Track (com.jme3.animation.Track)1