Merge branch 'fbx-import-animation' into experimental
This commit is contained in:
commit
962ab22ef4
@ -108,8 +108,8 @@ public class SkeletonControl extends AbstractControl implements Cloneable {
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@ -202,6 +202,9 @@ public class SkeletonControl extends AbstractControl implements Cloneable {
|
||||
* @param skeleton the skeleton
|
||||
*/
|
||||
public SkeletonControl(Skeleton skeleton) {
|
||||
if (skeleton == null) {
|
||||
throw new IllegalArgumentException("skeleton cannot be null");
|
||||
}
|
||||
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.blender.BlenderModelLoader : blend
|
||||
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.SceneWithAnimationLoader : fba
|
||||
LOADER com.jme3.scene.plugins.fbx.FbxLoader : fbx
|
||||
# LOADER com.jme3.scene.plugins.fbx.SceneWithAnimationLoader : fba
|
||||
|
@ -5,6 +5,7 @@ if (!hasProperty('mainClass')) {
|
||||
sourceSets {
|
||||
main {
|
||||
java {
|
||||
srcDir 'src/main/java'
|
||||
srcDir 'src/ogre/java'
|
||||
srcDir 'src/fbx/java'
|
||||
srcDir 'src/xml/java'
|
||||
|
@ -150,7 +150,7 @@ public class FbxLoader implements AssetLoader {
|
||||
private void loadData(InputStream stream) throws IOException {
|
||||
FbxFile scene = FbxReader.readFBX(stream);
|
||||
|
||||
FbxDump.dumpFile(scene);
|
||||
// FbxDump.dumpFile(scene);
|
||||
|
||||
// TODO: Load FBX object templates
|
||||
|
||||
@ -346,33 +346,33 @@ public class FbxLoader implements AssetLoader {
|
||||
duration = pair.getDuration();
|
||||
|
||||
if (pair.node instanceof FbxLimbNode) {
|
||||
// Find the spatial that has the skeleton for this limb.
|
||||
FbxLimbNode limbNode = (FbxLimbNode) pair.node;
|
||||
Bone bone = limbNode.getJmeBone();
|
||||
Spatial jmeSpatial = limbNode.getSkeletonHolder().getJmeObject();
|
||||
Skeleton skeleton = limbNode.getSkeletonHolder().getJmeSkeleton();
|
||||
|
||||
// Get the animation control (create if missing).
|
||||
AnimControl animControl = jmeSpatial.getControl(AnimControl.class);
|
||||
if (animControl.getSkeleton() != skeleton) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
// Get the animation (create if missing).
|
||||
Animation anim = animControl.getAnim(animName);
|
||||
if (anim == null) {
|
||||
anim = new Animation(animName, duration);
|
||||
animControl.addAnim(anim);
|
||||
}
|
||||
|
||||
// Find the bone index from the spatial's skeleton.
|
||||
int boneIndex = skeleton.getBoneIndex(bone);
|
||||
|
||||
// Generate the bone track.
|
||||
BoneTrack bt = pair.toJmeBoneTrack(boneIndex, bone.getBindInverseTransform());
|
||||
|
||||
// Add the bone track to the animation.
|
||||
anim.addTrack(bt);
|
||||
// // Find the spatial that has the skeleton for this limb.
|
||||
// FbxLimbNode limbNode = (FbxLimbNode) pair.node;
|
||||
// Bone bone = limbNode.getJmeBone();
|
||||
// Spatial jmeSpatial = limbNode.getSkeletonRoot().getJmeObject();
|
||||
// Skeleton skeleton = limbNode.getSkeletonRoot().getJmeSkeleton();
|
||||
//
|
||||
// // Get the animation control (create if missing).
|
||||
// AnimControl animControl = jmeSpatial.getControl(AnimControl.class);
|
||||
// if (animControl.getSkeleton() != skeleton) {
|
||||
// throw new UnsupportedOperationException();
|
||||
// }
|
||||
//
|
||||
// // Get the animation (create if missing).
|
||||
// Animation anim = animControl.getAnim(animName);
|
||||
// if (anim == null) {
|
||||
// anim = new Animation(animName, duration);
|
||||
// animControl.addAnim(anim);
|
||||
// }
|
||||
//
|
||||
// // Find the bone index from the spatial's skeleton.
|
||||
// int boneIndex = skeleton.getBoneIndex(bone);
|
||||
//
|
||||
// // Generate the bone track.
|
||||
// BoneTrack bt = pair.toJmeBoneTrack(boneIndex, bone.getBindInverseTransform());
|
||||
//
|
||||
// // Add the bone track to the animation.
|
||||
// anim.addTrack(bt);
|
||||
} else {
|
||||
// Create the spatial animation
|
||||
Animation anim = new Animation(animName, duration);
|
||||
|
@ -31,6 +31,8 @@
|
||||
*/
|
||||
package com.jme3.scene.plugins.fbx.anim;
|
||||
|
||||
import com.jme3.math.Matrix4f;
|
||||
|
||||
public class FbxAnimUtil {
|
||||
/**
|
||||
* 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_Z = "d|Z";
|
||||
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;
|
||||
float[] matData = null;
|
||||
double[] matData = null;
|
||||
|
||||
for (FbxElement e : child.children) {
|
||||
if (e.id.equals("Node")) {
|
||||
node = FbxId.create(e.properties.get(0));
|
||||
} 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
|
||||
throw new UnsupportedOperationException("Bind pose matrix "
|
||||
+ "must have 16 doubles, but it has "
|
||||
+ matDataDoubles.length + ". Data is corrupt");
|
||||
}
|
||||
|
||||
matData = new float[16];
|
||||
for (int i = 0; i < matDataDoubles.length; i++) {
|
||||
matData[i] = (float) matDataDoubles[i];
|
||||
+ matData.length + ". Data is corrupt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (node != null && matData != null) {
|
||||
Matrix4f matrix = new Matrix4f(matData);
|
||||
bindPose.put(node, matrix);
|
||||
bindPose.put(node, FbxAnimUtil.toMatrix4(matData));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,7 @@
|
||||
package com.jme3.scene.plugins.fbx.anim;
|
||||
|
||||
import com.jme3.asset.AssetManager;
|
||||
import com.jme3.math.Matrix4f;
|
||||
import com.jme3.scene.plugins.fbx.file.FbxElement;
|
||||
import com.jme3.scene.plugins.fbx.obj.FbxObject;
|
||||
import java.util.logging.Level;
|
||||
@ -45,6 +46,10 @@ public class FbxCluster extends FbxObject {
|
||||
private double[] weights;
|
||||
private FbxLimbNode limb;
|
||||
|
||||
private Matrix4f transformMatrix;
|
||||
private Matrix4f transformLinkMatrix;
|
||||
private Matrix4f transformAssociateModelMatrix;
|
||||
|
||||
public FbxCluster(AssetManager assetManager, String sceneFolderName) {
|
||||
super(assetManager, sceneFolderName);
|
||||
}
|
||||
@ -57,6 +62,15 @@ public class FbxCluster extends FbxObject {
|
||||
indexes = (int[]) e.properties.get(0);
|
||||
} else if (e.id.equals("Weights")) {
|
||||
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;
|
||||
}
|
||||
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 {
|
||||
unsupportedConnectObject(object);
|
||||
}
|
||||
|
@ -31,64 +31,22 @@
|
||||
*/
|
||||
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.scene.plugins.fbx.node.FbxNode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class FbxLimbNode extends FbxNode {
|
||||
|
||||
protected FbxNode skeletonHolder;
|
||||
protected Bone bone;
|
||||
protected FbxNode skeletonRoot;
|
||||
|
||||
public FbxLimbNode(AssetManager assetManager, String sceneFolderName) {
|
||||
super(assetManager, sceneFolderName);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
public FbxNode getSkeletonRoot() {
|
||||
return skeletonRoot;
|
||||
}
|
||||
|
||||
public static Skeleton createSkeleton(FbxNode skeletonHolderNode) {
|
||||
if (skeletonHolderNode instanceof FbxLimbNode) {
|
||||
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;
|
||||
|
||||
public void setSkeletonRoot(FbxNode skeletonRoot) {
|
||||
this.skeletonRoot = skeletonRoot;
|
||||
}
|
||||
}
|
||||
|
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,24 +31,94 @@
|
||||
*/
|
||||
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.math.Transform;
|
||||
import com.jme3.scene.plugins.fbx.node.FbxNode;
|
||||
import com.jme3.scene.plugins.fbx.obj.FbxObject;
|
||||
import java.util.ArrayList;
|
||||
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>();
|
||||
|
||||
public FbxSkinDeformer(AssetManager assetManager, String 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
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void connectObject(FbxObject object) {
|
||||
if (object instanceof FbxCluster) {
|
||||
@ -62,5 +132,5 @@ public class FbxSkinDeformer extends FbxObject<List<FbxCluster>> {
|
||||
public void connectObjectProperty(FbxObject object, String property) {
|
||||
unsupportedConnectObjectProperty(object, property);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ package com.jme3.scene.plugins.fbx.anim;
|
||||
import com.jme3.animation.BoneTrack;
|
||||
import com.jme3.animation.SpatialTrack;
|
||||
import com.jme3.animation.Track;
|
||||
import com.jme3.math.Matrix4f;
|
||||
import com.jme3.math.Quaternion;
|
||||
import com.jme3.math.Transform;
|
||||
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) {
|
||||
/*
|
||||
Transform t = new Transform();
|
||||
t.setTranslation(translation);
|
||||
t.setRotation(rotation);
|
||||
@ -111,6 +113,24 @@ public final class FbxToJmeTrack {
|
||||
if (scale != null) {
|
||||
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) {
|
||||
@ -154,7 +174,7 @@ public final class FbxToJmeTrack {
|
||||
if (i > 0) {
|
||||
if (rotations[i - 1].dot(rotations[i]) < 0) {
|
||||
System.out.println("rotation will go the long way, oh noes");
|
||||
rotations[i - 1].negate();
|
||||
rotations[i].negate();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -307,7 +307,11 @@ public class FbxMaterial extends FbxObject<Material> {
|
||||
if (useAlphaBlend) {
|
||||
// No idea if this is a transparent or translucent model, gotta guess..
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -111,36 +111,36 @@ public final class FbxMesh extends FbxNodeAttribute<IntMap<Mesh>> {
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
// if (boneIndices == null) {
|
||||
// boneIndices = new ArrayList[positions.length];
|
||||
// boneWeights = new ArrayList[positions.length];
|
||||
// }
|
||||
//
|
||||
// FbxLimbNode limb = cluster.getLimb();
|
||||
// Bone bone = limb.getJmeBone();
|
||||
// Skeleton skeleton = limb.getSkeletonRoot().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);
|
||||
// }
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -210,7 +210,7 @@ public final class FbxMesh extends FbxNodeAttribute<IntMap<Mesh>> {
|
||||
protected IntMap<Mesh> toJmeObject() {
|
||||
// Load clusters from SkinDeformer
|
||||
if (skinDeformer != null) {
|
||||
for (FbxCluster cluster : skinDeformer.getJmeObject()) {
|
||||
for (FbxCluster cluster : skinDeformer.getClusters()) {
|
||||
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.FbxCluster;
|
||||
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.file.FbxElement;
|
||||
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).
|
||||
*/
|
||||
protected Skeleton skeleton;
|
||||
protected FbxSkeleton skeleton;
|
||||
|
||||
protected final Transform jmeWorldNodeTransform = new Transform();
|
||||
protected final Transform jmeLocalNodeTransform = new Transform();
|
||||
@ -380,11 +381,11 @@ public class FbxNode extends FbxObject<Spatial> {
|
||||
FbxNode preferredParent = null;
|
||||
|
||||
if (deformer != null) {
|
||||
for (FbxCluster cluster : deformer.getJmeObject()) {
|
||||
for (FbxCluster cluster : deformer.getClusters()) {
|
||||
FbxLimbNode limb = cluster.getLimb();
|
||||
if (preferredParent == null) {
|
||||
preferredParent = limb.getSkeletonHolder();
|
||||
} else if (preferredParent != limb.getSkeletonHolder()) {
|
||||
preferredParent = limb.getSkeletonRoot();
|
||||
} else if (preferredParent != limb.getSkeletonRoot()) {
|
||||
logger.log(Level.WARNING, "A mesh is being deformed by multiple skeletons. "
|
||||
+ "Only one skeleton will work, ignoring other skeletons.");
|
||||
}
|
||||
@ -484,8 +485,8 @@ public class FbxNode extends FbxObject<Spatial> {
|
||||
if (fbxNode.skeleton != null) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
fbxNode.skeleton = FbxLimbNode.createSkeleton(fbxNode);
|
||||
System.out.println("created skeleton: " + fbxNode.skeleton);
|
||||
// fbxNode.skeleton = FbxLimbNode.createSkeleton(fbxNode);
|
||||
// System.out.println("created skeleton: " + fbxNode.skeleton);
|
||||
}
|
||||
}
|
||||
|
||||
@ -523,19 +524,19 @@ public class FbxNode extends FbxObject<Spatial> {
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
@ -548,10 +549,18 @@ public class FbxNode extends FbxObject<Spatial> {
|
||||
// return limb;
|
||||
// }
|
||||
|
||||
public Skeleton getJmeSkeleton() {
|
||||
// public Skeleton getJmeSkeleton() {
|
||||
// return skeleton;
|
||||
// }
|
||||
|
||||
public FbxSkeleton getFbxSkeleton() {
|
||||
return skeleton;
|
||||
}
|
||||
|
||||
public void setFbxSkeleton(FbxSkeleton skeleton) {
|
||||
this.skeleton = skeleton;
|
||||
}
|
||||
|
||||
public List<FbxNode> getChildren() {
|
||||
return children;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user