Merge branch 'fbx-import-animation' into experimental
This commit is contained in:
commit
962ab22ef4
@ -108,7 +108,7 @@ public class SkeletonControl extends AbstractControl implements Cloneable {
|
|||||||
/**
|
/**
|
||||||
* Material references used for hardware skinning
|
* Material references used for hardware skinning
|
||||||
*/
|
*/
|
||||||
private Set<Material> materials = new HashSet<Material>();
|
private final HashSet<Material> materials = new HashSet<Material>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serialization only. Do not use.
|
* Serialization only. Do not use.
|
||||||
@ -202,6 +202,9 @@ public class SkeletonControl extends AbstractControl implements Cloneable {
|
|||||||
* @param skeleton the skeleton
|
* @param skeleton the skeleton
|
||||||
*/
|
*/
|
||||||
public SkeletonControl(Skeleton skeleton) {
|
public SkeletonControl(Skeleton skeleton) {
|
||||||
|
if (skeleton == null) {
|
||||||
|
throw new IllegalArgumentException("skeleton cannot be null");
|
||||||
|
}
|
||||||
this.skeleton = skeleton;
|
this.skeleton = skeleton;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,5 +22,5 @@ LOADER com.jme3.scene.plugins.ogre.MaterialLoader : material
|
|||||||
LOADER com.jme3.scene.plugins.ogre.SceneLoader : scene
|
LOADER com.jme3.scene.plugins.ogre.SceneLoader : scene
|
||||||
LOADER com.jme3.scene.plugins.blender.BlenderModelLoader : blend
|
LOADER com.jme3.scene.plugins.blender.BlenderModelLoader : blend
|
||||||
LOADER com.jme3.shader.plugins.GLSLLoader : vert, frag, geom, tsctrl, tseval, glsl, glsllib
|
LOADER com.jme3.shader.plugins.GLSLLoader : vert, frag, geom, tsctrl, tseval, glsl, glsllib
|
||||||
LOADER com.jme3.scene.plugins.fbx.SceneLoader : fbx
|
LOADER com.jme3.scene.plugins.fbx.FbxLoader : fbx
|
||||||
LOADER com.jme3.scene.plugins.fbx.SceneWithAnimationLoader : fba
|
# LOADER com.jme3.scene.plugins.fbx.SceneWithAnimationLoader : fba
|
||||||
|
@ -5,6 +5,7 @@ if (!hasProperty('mainClass')) {
|
|||||||
sourceSets {
|
sourceSets {
|
||||||
main {
|
main {
|
||||||
java {
|
java {
|
||||||
|
srcDir 'src/main/java'
|
||||||
srcDir 'src/ogre/java'
|
srcDir 'src/ogre/java'
|
||||||
srcDir 'src/fbx/java'
|
srcDir 'src/fbx/java'
|
||||||
srcDir 'src/xml/java'
|
srcDir 'src/xml/java'
|
||||||
|
@ -150,7 +150,7 @@ public class FbxLoader implements AssetLoader {
|
|||||||
private void loadData(InputStream stream) throws IOException {
|
private void loadData(InputStream stream) throws IOException {
|
||||||
FbxFile scene = FbxReader.readFBX(stream);
|
FbxFile scene = FbxReader.readFBX(stream);
|
||||||
|
|
||||||
FbxDump.dumpFile(scene);
|
// FbxDump.dumpFile(scene);
|
||||||
|
|
||||||
// TODO: Load FBX object templates
|
// TODO: Load FBX object templates
|
||||||
|
|
||||||
@ -346,33 +346,33 @@ public class FbxLoader implements AssetLoader {
|
|||||||
duration = pair.getDuration();
|
duration = pair.getDuration();
|
||||||
|
|
||||||
if (pair.node instanceof FbxLimbNode) {
|
if (pair.node instanceof FbxLimbNode) {
|
||||||
// Find the spatial that has the skeleton for this limb.
|
// // Find the spatial that has the skeleton for this limb.
|
||||||
FbxLimbNode limbNode = (FbxLimbNode) pair.node;
|
// FbxLimbNode limbNode = (FbxLimbNode) pair.node;
|
||||||
Bone bone = limbNode.getJmeBone();
|
// Bone bone = limbNode.getJmeBone();
|
||||||
Spatial jmeSpatial = limbNode.getSkeletonHolder().getJmeObject();
|
// Spatial jmeSpatial = limbNode.getSkeletonRoot().getJmeObject();
|
||||||
Skeleton skeleton = limbNode.getSkeletonHolder().getJmeSkeleton();
|
// Skeleton skeleton = limbNode.getSkeletonRoot().getJmeSkeleton();
|
||||||
|
//
|
||||||
// Get the animation control (create if missing).
|
// // Get the animation control (create if missing).
|
||||||
AnimControl animControl = jmeSpatial.getControl(AnimControl.class);
|
// AnimControl animControl = jmeSpatial.getControl(AnimControl.class);
|
||||||
if (animControl.getSkeleton() != skeleton) {
|
// if (animControl.getSkeleton() != skeleton) {
|
||||||
throw new UnsupportedOperationException();
|
// throw new UnsupportedOperationException();
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// Get the animation (create if missing).
|
// // Get the animation (create if missing).
|
||||||
Animation anim = animControl.getAnim(animName);
|
// Animation anim = animControl.getAnim(animName);
|
||||||
if (anim == null) {
|
// if (anim == null) {
|
||||||
anim = new Animation(animName, duration);
|
// anim = new Animation(animName, duration);
|
||||||
animControl.addAnim(anim);
|
// animControl.addAnim(anim);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// Find the bone index from the spatial's skeleton.
|
// // Find the bone index from the spatial's skeleton.
|
||||||
int boneIndex = skeleton.getBoneIndex(bone);
|
// int boneIndex = skeleton.getBoneIndex(bone);
|
||||||
|
//
|
||||||
// Generate the bone track.
|
// // Generate the bone track.
|
||||||
BoneTrack bt = pair.toJmeBoneTrack(boneIndex, bone.getBindInverseTransform());
|
// BoneTrack bt = pair.toJmeBoneTrack(boneIndex, bone.getBindInverseTransform());
|
||||||
|
//
|
||||||
// Add the bone track to the animation.
|
// // Add the bone track to the animation.
|
||||||
anim.addTrack(bt);
|
// anim.addTrack(bt);
|
||||||
} else {
|
} else {
|
||||||
// Create the spatial animation
|
// Create the spatial animation
|
||||||
Animation anim = new Animation(animName, duration);
|
Animation anim = new Animation(animName, duration);
|
||||||
|
@ -31,6 +31,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.jme3.scene.plugins.fbx.anim;
|
package com.jme3.scene.plugins.fbx.anim;
|
||||||
|
|
||||||
|
import com.jme3.math.Matrix4f;
|
||||||
|
|
||||||
public class FbxAnimUtil {
|
public class FbxAnimUtil {
|
||||||
/**
|
/**
|
||||||
* Conversion factor from FBX animation time unit to seconds.
|
* Conversion factor from FBX animation time unit to seconds.
|
||||||
@ -41,4 +43,12 @@ public class FbxAnimUtil {
|
|||||||
public static final String CURVE_NODE_PROPERTY_Y = "d|Y";
|
public static final String CURVE_NODE_PROPERTY_Y = "d|Y";
|
||||||
public static final String CURVE_NODE_PROPERTY_Z = "d|Z";
|
public static final String CURVE_NODE_PROPERTY_Z = "d|Z";
|
||||||
public static final String CURVE_NODE_PROPERTY_VISIBILITY = "d|Visibility";
|
public static final String CURVE_NODE_PROPERTY_VISIBILITY = "d|Visibility";
|
||||||
|
|
||||||
|
public static Matrix4f toMatrix4(double[] matrixData) {
|
||||||
|
float[] matrixDataFloat = new float[16];
|
||||||
|
for (int i = 0; i < matrixData.length; i++) {
|
||||||
|
matrixDataFloat[i] = (float) matrixData[i];
|
||||||
|
}
|
||||||
|
return new Matrix4f(matrixDataFloat);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,31 +56,25 @@ public class FbxBindPose extends FbxObject<Map<FbxId, Matrix4f>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FbxId node = null;
|
FbxId node = null;
|
||||||
float[] matData = null;
|
double[] matData = null;
|
||||||
|
|
||||||
for (FbxElement e : child.children) {
|
for (FbxElement e : child.children) {
|
||||||
if (e.id.equals("Node")) {
|
if (e.id.equals("Node")) {
|
||||||
node = FbxId.create(e.properties.get(0));
|
node = FbxId.create(e.properties.get(0));
|
||||||
} else if (e.id.equals("Matrix")) {
|
} else if (e.id.equals("Matrix")) {
|
||||||
double[] matDataDoubles = (double[]) e.properties.get(0);
|
matData = (double[]) e.properties.get(0);
|
||||||
|
|
||||||
if (matDataDoubles.length != 16) {
|
if (matData.length != 16) {
|
||||||
// corrupt
|
// corrupt
|
||||||
throw new UnsupportedOperationException("Bind pose matrix "
|
throw new UnsupportedOperationException("Bind pose matrix "
|
||||||
+ "must have 16 doubles, but it has "
|
+ "must have 16 doubles, but it has "
|
||||||
+ matDataDoubles.length + ". Data is corrupt");
|
+ matData.length + ". Data is corrupt");
|
||||||
}
|
|
||||||
|
|
||||||
matData = new float[16];
|
|
||||||
for (int i = 0; i < matDataDoubles.length; i++) {
|
|
||||||
matData[i] = (float) matDataDoubles[i];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node != null && matData != null) {
|
if (node != null && matData != null) {
|
||||||
Matrix4f matrix = new Matrix4f(matData);
|
bindPose.put(node, FbxAnimUtil.toMatrix4(matData));
|
||||||
bindPose.put(node, matrix);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
package com.jme3.scene.plugins.fbx.anim;
|
package com.jme3.scene.plugins.fbx.anim;
|
||||||
|
|
||||||
import com.jme3.asset.AssetManager;
|
import com.jme3.asset.AssetManager;
|
||||||
|
import com.jme3.math.Matrix4f;
|
||||||
import com.jme3.scene.plugins.fbx.file.FbxElement;
|
import com.jme3.scene.plugins.fbx.file.FbxElement;
|
||||||
import com.jme3.scene.plugins.fbx.obj.FbxObject;
|
import com.jme3.scene.plugins.fbx.obj.FbxObject;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
@ -45,6 +46,10 @@ public class FbxCluster extends FbxObject {
|
|||||||
private double[] weights;
|
private double[] weights;
|
||||||
private FbxLimbNode limb;
|
private FbxLimbNode limb;
|
||||||
|
|
||||||
|
private Matrix4f transformMatrix;
|
||||||
|
private Matrix4f transformLinkMatrix;
|
||||||
|
private Matrix4f transformAssociateModelMatrix;
|
||||||
|
|
||||||
public FbxCluster(AssetManager assetManager, String sceneFolderName) {
|
public FbxCluster(AssetManager assetManager, String sceneFolderName) {
|
||||||
super(assetManager, sceneFolderName);
|
super(assetManager, sceneFolderName);
|
||||||
}
|
}
|
||||||
@ -57,6 +62,15 @@ public class FbxCluster extends FbxObject {
|
|||||||
indexes = (int[]) e.properties.get(0);
|
indexes = (int[]) e.properties.get(0);
|
||||||
} else if (e.id.equals("Weights")) {
|
} else if (e.id.equals("Weights")) {
|
||||||
weights = (double[]) e.properties.get(0);
|
weights = (double[]) e.properties.get(0);
|
||||||
|
} else if (e.id.equals("Transform")) {
|
||||||
|
double[] data = (double[]) e.properties.get(0);
|
||||||
|
transformMatrix = FbxAnimUtil.toMatrix4(data);
|
||||||
|
} else if (e.id.equals("TransformLink")) {
|
||||||
|
double[] data = (double[]) e.properties.get(0);
|
||||||
|
transformLinkMatrix = FbxAnimUtil.toMatrix4(data);
|
||||||
|
} else if (e.id.equals("TransformAssociateModel")) {
|
||||||
|
double[] data = (double[]) e.properties.get(0);
|
||||||
|
transformAssociateModelMatrix = FbxAnimUtil.toMatrix4(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -86,6 +100,18 @@ public class FbxCluster extends FbxObject {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
limb = (FbxLimbNode) object;
|
limb = (FbxLimbNode) object;
|
||||||
|
|
||||||
|
System.out.println(" ----- for limb: " + limb.getName());
|
||||||
|
System.out.println(" transform : " + transformMatrix);
|
||||||
|
System.out.println(" transform link : " + transformLinkMatrix);
|
||||||
|
System.out.println(" transform associate model : " + transformAssociateModelMatrix);
|
||||||
|
|
||||||
|
// Invert(Invert(TransformLinkMatrix) * TransformMatrix * Geometry)
|
||||||
|
Matrix4f accumMatrix = transformLinkMatrix.invert();
|
||||||
|
accumMatrix.multLocal(transformMatrix);
|
||||||
|
accumMatrix.invertLocal();
|
||||||
|
|
||||||
|
System.out.println(" limb bind pose : " + accumMatrix);
|
||||||
} else {
|
} else {
|
||||||
unsupportedConnectObject(object);
|
unsupportedConnectObject(object);
|
||||||
}
|
}
|
||||||
|
@ -31,64 +31,22 @@
|
|||||||
*/
|
*/
|
||||||
package com.jme3.scene.plugins.fbx.anim;
|
package com.jme3.scene.plugins.fbx.anim;
|
||||||
|
|
||||||
import com.jme3.animation.Bone;
|
|
||||||
import com.jme3.animation.Skeleton;
|
|
||||||
import com.jme3.asset.AssetManager;
|
import com.jme3.asset.AssetManager;
|
||||||
import com.jme3.scene.plugins.fbx.node.FbxNode;
|
import com.jme3.scene.plugins.fbx.node.FbxNode;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class FbxLimbNode extends FbxNode {
|
public class FbxLimbNode extends FbxNode {
|
||||||
|
|
||||||
protected FbxNode skeletonHolder;
|
protected FbxNode skeletonRoot;
|
||||||
protected Bone bone;
|
|
||||||
|
|
||||||
public FbxLimbNode(AssetManager assetManager, String sceneFolderName) {
|
public FbxLimbNode(AssetManager assetManager, String sceneFolderName) {
|
||||||
super(assetManager, sceneFolderName);
|
super(assetManager, sceneFolderName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void createBones(FbxNode skeletonHolderNode, FbxLimbNode limb, List<Bone> bones) {
|
public FbxNode getSkeletonRoot() {
|
||||||
limb.skeletonHolder = skeletonHolderNode;
|
return skeletonRoot;
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Skeleton createSkeleton(FbxNode skeletonHolderNode) {
|
public void setSkeletonRoot(FbxNode skeletonRoot) {
|
||||||
if (skeletonHolderNode instanceof FbxLimbNode) {
|
this.skeletonRoot = skeletonRoot;
|
||||||
throw new UnsupportedOperationException("Limb nodes cannot be skeleton holders");
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Bone> bones = new ArrayList<Bone>();
|
|
||||||
|
|
||||||
for (FbxNode child : skeletonHolderNode.getChildren()) {
|
|
||||||
if (child instanceof FbxLimbNode) {
|
|
||||||
createBones(skeletonHolderNode, (FbxLimbNode) child, bones);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Skeleton(bones.toArray(new Bone[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
public FbxNode getSkeletonHolder() {
|
|
||||||
return skeletonHolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Bone getJmeBone() {
|
|
||||||
if (bone == null) {
|
|
||||||
bone = new Bone(name);
|
|
||||||
bone.setBindTransforms(jmeLocalBindPose.getTranslation(),
|
|
||||||
jmeLocalBindPose.getRotation(),
|
|
||||||
jmeLocalBindPose.getScale());
|
|
||||||
}
|
|
||||||
return bone;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
112
jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/anim/FbxSkeleton.java
Executable file
112
jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/anim/FbxSkeleton.java
Executable file
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2015 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package com.jme3.scene.plugins.fbx.anim;
|
||||||
|
|
||||||
|
import com.jme3.animation.Bone;
|
||||||
|
import com.jme3.animation.Skeleton;
|
||||||
|
import com.jme3.scene.plugins.fbx.node.FbxNode;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Similar to {@link Skeleton jME skeleton} except
|
||||||
|
* contains {@link FbxLimbNode limb nodes}.
|
||||||
|
*
|
||||||
|
* This is used to determine the bone indices (for assigning clusters to meshes)
|
||||||
|
* as well as the limb hierarchy when creating the jME3 Skeleton.
|
||||||
|
*
|
||||||
|
* @author Kirill Vainer
|
||||||
|
*/
|
||||||
|
public class FbxSkeleton {
|
||||||
|
|
||||||
|
FbxLimbNode[] rootLimbs;
|
||||||
|
FbxLimbNode[] allLimbs;
|
||||||
|
HashMap<FbxLimbNode, Integer> limbToIndexMap = new HashMap<FbxLimbNode, Integer>();
|
||||||
|
|
||||||
|
private FbxSkeleton() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void populateSkeletonData(FbxNode skeletonRoot) {
|
||||||
|
// if (skeletonRoot instanceof FbxLimbNode) {
|
||||||
|
// throw new UnsupportedOperationException("Limb node cannot be a skeleton root");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// FbxSkeleton skeleton = new FbxSkeleton();
|
||||||
|
// skeleton.scanLimbs(skeletonRoot);
|
||||||
|
// skeletonRoot.setFbxSkeleton(skeleton);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void scanLimbs(FbxNode skeletonRoot, FbxLimbNode limb, List<FbxLimbNode> limbList) {
|
||||||
|
// limb.skeletonRoot = skeletonRoot;
|
||||||
|
// limbList.add(limb);
|
||||||
|
// for (FbxNode child : limb.getChildren()) {
|
||||||
|
// if (child instanceof FbxLimbNode) {
|
||||||
|
// FbxLimbNode childLimb = (FbxLimbNode) child;
|
||||||
|
// scanLimbs(skeletonRoot, childLimb, limbList);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
private void scanLimbs(FbxNode skeletonRoot) {
|
||||||
|
List<FbxLimbNode> limbList = new ArrayList<FbxLimbNode>();
|
||||||
|
List<FbxLimbNode> rootList = new ArrayList<FbxLimbNode>();
|
||||||
|
|
||||||
|
for (FbxNode child : skeletonRoot.getChildren()) {
|
||||||
|
if (child instanceof FbxLimbNode) {
|
||||||
|
FbxLimbNode limb = (FbxLimbNode) child;
|
||||||
|
rootList.add(limb);
|
||||||
|
scanLimbs(skeletonRoot, limb, limbList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allLimbs = limbList.toArray(new FbxLimbNode[0]);
|
||||||
|
rootLimbs = rootList.toArray(new FbxLimbNode[0]);
|
||||||
|
|
||||||
|
for (int i = 0; i < allLimbs.length; i++) {
|
||||||
|
limbToIndexMap.put(allLimbs[i], i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLimbIndex(FbxLimbNode limbNode) {
|
||||||
|
return limbToIndexMap.get(limbNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FbxLimbNode getLimb(int index) {
|
||||||
|
return allLimbs[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
public FbxLimbNode[] getRootLimbs() {
|
||||||
|
return rootLimbs;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -31,21 +31,91 @@
|
|||||||
*/
|
*/
|
||||||
package com.jme3.scene.plugins.fbx.anim;
|
package com.jme3.scene.plugins.fbx.anim;
|
||||||
|
|
||||||
|
import com.jme3.animation.Bone;
|
||||||
|
import com.jme3.animation.Skeleton;
|
||||||
import com.jme3.asset.AssetManager;
|
import com.jme3.asset.AssetManager;
|
||||||
|
import com.jme3.math.Transform;
|
||||||
|
import com.jme3.scene.plugins.fbx.node.FbxNode;
|
||||||
import com.jme3.scene.plugins.fbx.obj.FbxObject;
|
import com.jme3.scene.plugins.fbx.obj.FbxObject;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class FbxSkinDeformer extends FbxObject<List<FbxCluster>> {
|
public class FbxSkinDeformer extends FbxObject<Skeleton> {
|
||||||
|
|
||||||
|
private FbxNode skeletonRoot;
|
||||||
private final List<FbxCluster> clusters = new ArrayList<FbxCluster>();
|
private final List<FbxCluster> clusters = new ArrayList<FbxCluster>();
|
||||||
|
|
||||||
public FbxSkinDeformer(AssetManager assetManager, String sceneFolderName) {
|
public FbxSkinDeformer(AssetManager assetManager, String sceneFolderName) {
|
||||||
super(assetManager, sceneFolderName);
|
super(assetManager, sceneFolderName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isHierarchyCompatible(Bone thisBone, Bone otherBone) {
|
||||||
|
Transform thisTransform = thisBone.getBindInverseTransform();
|
||||||
|
Transform otherTransform = otherBone.getBindInverseTransform();
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if both skin deformers can share the same
|
||||||
|
* Skeleton object and hence the same SkeletonControl / AnimControl.
|
||||||
|
*
|
||||||
|
* @param skinDeformer The skin deformer to test compatibility against.
|
||||||
|
* @return True if the skeletons are identical and can be shared, false
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
public boolean isCompatible(FbxSkinDeformer skinDeformer) {
|
||||||
|
Skeleton thisSkeleton = this.getJmeObject();
|
||||||
|
Skeleton otherSkeleton = skinDeformer.getJmeObject();
|
||||||
|
Bone[] thisRoots = thisSkeleton.getRoots();
|
||||||
|
Bone[] otherRoots = otherSkeleton.getRoots();
|
||||||
|
for (int i = 0; i < thisRoots.length; i++) {
|
||||||
|
|
||||||
|
}
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the root FbxNode containing the skeleton.
|
||||||
|
*
|
||||||
|
* The node should have one or more FbxLimbNodes which are
|
||||||
|
* the root limbs of the skeleton structure.
|
||||||
|
*
|
||||||
|
* This is null until prepareSkeletonData() is called.
|
||||||
|
*
|
||||||
|
* @return The root node containing the skeleton.
|
||||||
|
*/
|
||||||
|
public FbxNode getSkeletonRoot() {
|
||||||
|
return skeletonRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derives the skeleton from the skin deformer.
|
||||||
|
*
|
||||||
|
* The Skeleton hierarchy is derived via the {@link #getSkeletonRoot() skeleton root}
|
||||||
|
* whereas the bind poses for the bones is derived from the
|
||||||
|
* {@link #getClusters() clusters}.
|
||||||
|
*
|
||||||
|
* FbxLimbNode.prepareSkeletonData() must have been called first
|
||||||
|
* The bone's bind pose depends on each cluster's TransformLinkMatrix
|
||||||
|
* and TransformMatrix.
|
||||||
|
* The bone's bind pose is derived as follows:
|
||||||
|
* <code><pre>
|
||||||
|
* Invert(Invert(TransformLinkMatrix) * TransformMatrix * Geometry)
|
||||||
|
* </code></pre>
|
||||||
|
*
|
||||||
|
* @return The skeleton as described by this skin deformer.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected List<FbxCluster> toJmeObject() {
|
protected Skeleton toJmeObject() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the clusters attached to this skin deformer.
|
||||||
|
*
|
||||||
|
* @return The skin deformer's clusters.
|
||||||
|
*/
|
||||||
|
public List<FbxCluster> getClusters() {
|
||||||
return clusters;
|
return clusters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ package com.jme3.scene.plugins.fbx.anim;
|
|||||||
import com.jme3.animation.BoneTrack;
|
import com.jme3.animation.BoneTrack;
|
||||||
import com.jme3.animation.SpatialTrack;
|
import com.jme3.animation.SpatialTrack;
|
||||||
import com.jme3.animation.Track;
|
import com.jme3.animation.Track;
|
||||||
|
import com.jme3.math.Matrix4f;
|
||||||
import com.jme3.math.Quaternion;
|
import com.jme3.math.Quaternion;
|
||||||
import com.jme3.math.Transform;
|
import com.jme3.math.Transform;
|
||||||
import com.jme3.math.Vector3f;
|
import com.jme3.math.Vector3f;
|
||||||
@ -98,6 +99,7 @@ public final class FbxToJmeTrack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void applyInverse(Vector3f translation, Quaternion rotation, Vector3f scale, Transform inverseBindPose) {
|
private static void applyInverse(Vector3f translation, Quaternion rotation, Vector3f scale, Transform inverseBindPose) {
|
||||||
|
/*
|
||||||
Transform t = new Transform();
|
Transform t = new Transform();
|
||||||
t.setTranslation(translation);
|
t.setTranslation(translation);
|
||||||
t.setRotation(rotation);
|
t.setRotation(rotation);
|
||||||
@ -111,6 +113,24 @@ public final class FbxToJmeTrack {
|
|||||||
if (scale != null) {
|
if (scale != null) {
|
||||||
t.getScale(scale);
|
t.getScale(scale);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
Matrix4f mat = new Matrix4f();
|
||||||
|
mat.setTranslation(translation);
|
||||||
|
mat.setRotationQuaternion(rotation);
|
||||||
|
if (scale != null) {
|
||||||
|
mat.setScale(scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix4f mat2 = inverseBindPose.toTransformMatrix();
|
||||||
|
mat2.multLocal(mat);
|
||||||
|
mat = mat2;
|
||||||
|
|
||||||
|
mat.toTranslationVector(translation);
|
||||||
|
mat.toRotationQuat(rotation);
|
||||||
|
if (scale != null) {
|
||||||
|
mat.toScaleVector(scale);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Track toJmeTrackInternal(int boneIndex, Transform inverseBindPose) {
|
private Track toJmeTrackInternal(int boneIndex, Transform inverseBindPose) {
|
||||||
@ -154,7 +174,7 @@ public final class FbxToJmeTrack {
|
|||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
if (rotations[i - 1].dot(rotations[i]) < 0) {
|
if (rotations[i - 1].dot(rotations[i]) < 0) {
|
||||||
System.out.println("rotation will go the long way, oh noes");
|
System.out.println("rotation will go the long way, oh noes");
|
||||||
rotations[i - 1].negate();
|
rotations[i].negate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -307,7 +307,11 @@ public class FbxMaterial extends FbxObject<Material> {
|
|||||||
if (useAlphaBlend) {
|
if (useAlphaBlend) {
|
||||||
// No idea if this is a transparent or translucent model, gotta guess..
|
// No idea if this is a transparent or translucent model, gotta guess..
|
||||||
mat.setTransparent(true);
|
mat.setTransparent(true);
|
||||||
mat.setFloat("AlphaDiscardThreshold", 0.01f);
|
|
||||||
|
// Commenting this out for now. It causes extra shaders to be
|
||||||
|
// used and is less efficient due to usage of "discard".
|
||||||
|
// mat.setFloat("AlphaDiscardThreshold", 0.01f);
|
||||||
|
|
||||||
mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
|
mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,36 +111,36 @@ public final class FbxMesh extends FbxNodeAttribute<IntMap<Mesh>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void applyCluster(FbxCluster cluster) {
|
public void applyCluster(FbxCluster cluster) {
|
||||||
if (boneIndices == null) {
|
// if (boneIndices == null) {
|
||||||
boneIndices = new ArrayList[positions.length];
|
// boneIndices = new ArrayList[positions.length];
|
||||||
boneWeights = new ArrayList[positions.length];
|
// boneWeights = new ArrayList[positions.length];
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
FbxLimbNode limb = cluster.getLimb();
|
// FbxLimbNode limb = cluster.getLimb();
|
||||||
Bone bone = limb.getJmeBone();
|
// Bone bone = limb.getJmeBone();
|
||||||
Skeleton skeleton = limb.getSkeletonHolder().getJmeSkeleton();
|
// Skeleton skeleton = limb.getSkeletonRoot().getJmeSkeleton();
|
||||||
int boneIndex = skeleton.getBoneIndex(bone);
|
// int boneIndex = skeleton.getBoneIndex(bone);
|
||||||
|
//
|
||||||
int[] positionIndices = cluster.getVertexIndices();
|
// int[] positionIndices = cluster.getVertexIndices();
|
||||||
double[] weights = cluster.getWeights();
|
// double[] weights = cluster.getWeights();
|
||||||
|
//
|
||||||
for (int i = 0; i < positionIndices.length; i++) {
|
// for (int i = 0; i < positionIndices.length; i++) {
|
||||||
int positionIndex = positionIndices[i];
|
// int positionIndex = positionIndices[i];
|
||||||
float boneWeight = (float)weights[i];
|
// float boneWeight = (float)weights[i];
|
||||||
|
//
|
||||||
ArrayList<Integer> boneIndicesForVertex = boneIndices[positionIndex];
|
// ArrayList<Integer> boneIndicesForVertex = boneIndices[positionIndex];
|
||||||
ArrayList<Float> boneWeightsForVertex = boneWeights[positionIndex];
|
// ArrayList<Float> boneWeightsForVertex = boneWeights[positionIndex];
|
||||||
|
//
|
||||||
if (boneIndicesForVertex == null) {
|
// if (boneIndicesForVertex == null) {
|
||||||
boneIndicesForVertex = new ArrayList<Integer>();
|
// boneIndicesForVertex = new ArrayList<Integer>();
|
||||||
boneWeightsForVertex = new ArrayList<Float>();
|
// boneWeightsForVertex = new ArrayList<Float>();
|
||||||
boneIndices[positionIndex] = boneIndicesForVertex;
|
// boneIndices[positionIndex] = boneIndicesForVertex;
|
||||||
boneWeights[positionIndex] = boneWeightsForVertex;
|
// boneWeights[positionIndex] = boneWeightsForVertex;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
boneIndicesForVertex.add(boneIndex);
|
// boneIndicesForVertex.add(boneIndex);
|
||||||
boneWeightsForVertex.add(boneWeight);
|
// boneWeightsForVertex.add(boneWeight);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -210,7 +210,7 @@ public final class FbxMesh extends FbxNodeAttribute<IntMap<Mesh>> {
|
|||||||
protected IntMap<Mesh> toJmeObject() {
|
protected IntMap<Mesh> toJmeObject() {
|
||||||
// Load clusters from SkinDeformer
|
// Load clusters from SkinDeformer
|
||||||
if (skinDeformer != null) {
|
if (skinDeformer != null) {
|
||||||
for (FbxCluster cluster : skinDeformer.getJmeObject()) {
|
for (FbxCluster cluster : skinDeformer.getClusters()) {
|
||||||
applyCluster(cluster);
|
applyCluster(cluster);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,7 @@ import com.jme3.scene.debug.SkeletonDebugger;
|
|||||||
import com.jme3.scene.plugins.fbx.anim.FbxAnimCurveNode;
|
import com.jme3.scene.plugins.fbx.anim.FbxAnimCurveNode;
|
||||||
import com.jme3.scene.plugins.fbx.anim.FbxCluster;
|
import com.jme3.scene.plugins.fbx.anim.FbxCluster;
|
||||||
import com.jme3.scene.plugins.fbx.anim.FbxLimbNode;
|
import com.jme3.scene.plugins.fbx.anim.FbxLimbNode;
|
||||||
|
import com.jme3.scene.plugins.fbx.anim.FbxSkeleton;
|
||||||
import com.jme3.scene.plugins.fbx.anim.FbxSkinDeformer;
|
import com.jme3.scene.plugins.fbx.anim.FbxSkinDeformer;
|
||||||
import com.jme3.scene.plugins.fbx.file.FbxElement;
|
import com.jme3.scene.plugins.fbx.file.FbxElement;
|
||||||
import com.jme3.scene.plugins.fbx.material.FbxImage;
|
import com.jme3.scene.plugins.fbx.material.FbxImage;
|
||||||
@ -108,7 +109,7 @@ public class FbxNode extends FbxObject<Spatial> {
|
|||||||
/**
|
/**
|
||||||
* For FBX nodes that contain a skeleton (i.e. FBX limbs).
|
* For FBX nodes that contain a skeleton (i.e. FBX limbs).
|
||||||
*/
|
*/
|
||||||
protected Skeleton skeleton;
|
protected FbxSkeleton skeleton;
|
||||||
|
|
||||||
protected final Transform jmeWorldNodeTransform = new Transform();
|
protected final Transform jmeWorldNodeTransform = new Transform();
|
||||||
protected final Transform jmeLocalNodeTransform = new Transform();
|
protected final Transform jmeLocalNodeTransform = new Transform();
|
||||||
@ -380,11 +381,11 @@ public class FbxNode extends FbxObject<Spatial> {
|
|||||||
FbxNode preferredParent = null;
|
FbxNode preferredParent = null;
|
||||||
|
|
||||||
if (deformer != null) {
|
if (deformer != null) {
|
||||||
for (FbxCluster cluster : deformer.getJmeObject()) {
|
for (FbxCluster cluster : deformer.getClusters()) {
|
||||||
FbxLimbNode limb = cluster.getLimb();
|
FbxLimbNode limb = cluster.getLimb();
|
||||||
if (preferredParent == null) {
|
if (preferredParent == null) {
|
||||||
preferredParent = limb.getSkeletonHolder();
|
preferredParent = limb.getSkeletonRoot();
|
||||||
} else if (preferredParent != limb.getSkeletonHolder()) {
|
} else if (preferredParent != limb.getSkeletonRoot()) {
|
||||||
logger.log(Level.WARNING, "A mesh is being deformed by multiple skeletons. "
|
logger.log(Level.WARNING, "A mesh is being deformed by multiple skeletons. "
|
||||||
+ "Only one skeleton will work, ignoring other skeletons.");
|
+ "Only one skeleton will work, ignoring other skeletons.");
|
||||||
}
|
}
|
||||||
@ -484,8 +485,8 @@ public class FbxNode extends FbxObject<Spatial> {
|
|||||||
if (fbxNode.skeleton != null) {
|
if (fbxNode.skeleton != null) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
fbxNode.skeleton = FbxLimbNode.createSkeleton(fbxNode);
|
// fbxNode.skeleton = FbxLimbNode.createSkeleton(fbxNode);
|
||||||
System.out.println("created skeleton: " + fbxNode.skeleton);
|
// System.out.println("created skeleton: " + fbxNode.skeleton);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -523,19 +524,19 @@ public class FbxNode extends FbxObject<Spatial> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fbxNode.skeleton != null) {
|
// if (fbxNode.skeleton != null) {
|
||||||
jmeSpatial.addControl(new AnimControl(fbxNode.skeleton));
|
// jmeSpatial.addControl(new AnimControl(fbxNode.skeleton));
|
||||||
jmeSpatial.addControl(new SkeletonControl(fbxNode.skeleton));
|
// jmeSpatial.addControl(new SkeletonControl(fbxNode.skeleton));
|
||||||
|
//
|
||||||
SkeletonDebugger sd = new SkeletonDebugger("debug", fbxNode.skeleton);
|
// SkeletonDebugger sd = new SkeletonDebugger("debug", fbxNode.skeleton);
|
||||||
Material mat = new Material(fbxNode.assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
|
// Material mat = new Material(fbxNode.assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
|
||||||
mat.getAdditionalRenderState().setWireframe(true);
|
// mat.getAdditionalRenderState().setWireframe(true);
|
||||||
mat.getAdditionalRenderState().setDepthTest(false);
|
// mat.getAdditionalRenderState().setDepthTest(false);
|
||||||
mat.setColor("Color", ColorRGBA.Green);
|
// mat.setColor("Color", ColorRGBA.Green);
|
||||||
sd.setMaterial(mat);
|
// sd.setMaterial(mat);
|
||||||
|
//
|
||||||
((Node)jmeSpatial).attachChild(sd);
|
// ((Node)jmeSpatial).attachChild(sd);
|
||||||
}
|
// }
|
||||||
|
|
||||||
return jmeSpatial;
|
return jmeSpatial;
|
||||||
}
|
}
|
||||||
@ -548,10 +549,18 @@ public class FbxNode extends FbxObject<Spatial> {
|
|||||||
// return limb;
|
// return limb;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
public Skeleton getJmeSkeleton() {
|
// public Skeleton getJmeSkeleton() {
|
||||||
|
// return skeleton;
|
||||||
|
// }
|
||||||
|
|
||||||
|
public FbxSkeleton getFbxSkeleton() {
|
||||||
return skeleton;
|
return skeleton;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setFbxSkeleton(FbxSkeleton skeleton) {
|
||||||
|
this.skeleton = skeleton;
|
||||||
|
}
|
||||||
|
|
||||||
public List<FbxNode> getChildren() {
|
public List<FbxNode> getChildren() {
|
||||||
return children;
|
return children;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user