Merge branch 'fbx-import-animation' into experimental

experimental
Kirill Vainer 9 years ago
commit 962ab22ef4
  1. 5
      jme3-core/src/main/java/com/jme3/animation/SkeletonControl.java
  2. 4
      jme3-core/src/main/resources/com/jme3/asset/General.cfg
  3. 1
      jme3-plugins/build.gradle
  4. 56
      jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/FbxLoader.java
  5. 10
      jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/anim/FbxAnimUtil.java
  6. 16
      jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/anim/FbxBindPose.java
  7. 26
      jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/anim/FbxCluster.java
  8. 52
      jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/anim/FbxLimbNode.java
  9. 112
      jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/anim/FbxSkeleton.java
  10. 74
      jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/anim/FbxSkinDeformer.java
  11. 22
      jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/anim/FbxToJmeTrack.java
  12. 6
      jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/material/FbxMaterial.java
  13. 62
      jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/mesh/FbxMesh.java
  14. 49
      jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/node/FbxNode.java

@ -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;
} }
} }

@ -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…
Cancel
Save