use of com.jme3.scene.plugins.fbx.objects.FbxNode in project jmonkeyengine by jMonkeyEngine.
the class FbxNode method updateWorldTransforms.
public void updateWorldTransforms(Transform jmeParentNodeTransform, Transform parentBindPose) {
Transform fbxLocalTransform = computeFbxLocalTransform();
jmeLocalNodeTransform.set(fbxLocalTransform);
if (jmeParentNodeTransform != null) {
jmeParentNodeTransform = jmeParentNodeTransform.clone();
switch(inheritMode) {
case NoParentScale:
case ScaleAfterChildRotation:
case ScaleBeforeChildRotation:
jmeWorldNodeTransform.set(jmeLocalNodeTransform);
jmeWorldNodeTransform.combineWithParent(jmeParentNodeTransform);
break;
}
} else {
jmeWorldNodeTransform.set(jmeLocalNodeTransform);
}
if (jmeWorldBindPose != null) {
jmeLocalBindPose = new Transform();
// Need to derive local bind pose from world bind pose
// (this is to be expected for FBX limbs)
jmeLocalBindPose.set(jmeWorldBindPose);
jmeLocalBindPose.combineWithParent(parentBindPose.invert());
// Its somewhat odd for the transforms to differ ...
System.out.println("Bind Pose for: " + getName());
if (!jmeLocalBindPose.equals(jmeLocalNodeTransform)) {
System.out.println("Local Bind: " + jmeLocalBindPose);
System.out.println("Local Trans: " + jmeLocalNodeTransform);
}
if (!jmeWorldBindPose.equals(jmeWorldNodeTransform)) {
System.out.println("World Bind: " + jmeWorldBindPose);
System.out.println("World Trans: " + jmeWorldNodeTransform);
}
} else {
// World pose derived from local transforms
// (this is to be expected for FBX nodes)
jmeLocalBindPose = new Transform();
jmeWorldBindPose = new Transform();
jmeLocalBindPose.set(jmeLocalNodeTransform);
if (parentBindPose != null) {
jmeWorldBindPose.set(jmeLocalNodeTransform);
jmeWorldBindPose.combineWithParent(parentBindPose);
} else {
jmeWorldBindPose.set(jmeWorldNodeTransform);
}
}
for (FbxNode child : children) {
child.updateWorldTransforms(jmeWorldNodeTransform, jmeWorldBindPose);
}
}
use of com.jme3.scene.plugins.fbx.objects.FbxNode in project jmonkeyengine by jMonkeyEngine.
the class FbxLoader method constructSceneGraph.
private Spatial constructSceneGraph() {
// Acquire the implicit root object.
FbxNode fbxRoot = (FbxNode) objectMap.get(FbxId.ROOT);
// Convert it into a jME3 scene
Node jmeRoot = (Node) FbxNode.createScene(fbxRoot);
// Fix the name (will probably be set to something like "-node")
jmeRoot.setName(sceneName + "-scene");
return jmeRoot;
}
use of com.jme3.scene.plugins.fbx.objects.FbxNode in project jmonkeyengine by jMonkeyEngine.
the class FbxLoader method applyBindPoses.
/**
* Copies the bind poses from FBX BindPose objects to FBX nodes.
* Must be called prior to {@link #updateWorldTransforms()}.
*/
private void applyBindPoses() {
for (FbxBindPose bindPose : bindPoses) {
Map<FbxId, Matrix4f> bindPoseData = bindPose.getJmeObject();
logger.log(Level.INFO, "Applying {0} bind poses", bindPoseData.size());
for (Map.Entry<FbxId, Matrix4f> entry : bindPoseData.entrySet()) {
FbxObject obj = objectMap.get(entry.getKey());
if (obj instanceof FbxNode) {
FbxNode node = (FbxNode) obj;
node.setWorldBindPose(entry.getValue());
} else {
logger.log(Level.WARNING, "Bind pose can only be applied to FBX nodes. Ignoring.");
}
}
}
}
use of com.jme3.scene.plugins.fbx.objects.FbxNode in project jmonkeyengine by jMonkeyEngine.
the class SceneLoader method buildAnimations.
private void buildAnimations() {
if (skeleton == null)
return;
if (animList == null || animList.list.size() == 0) {
animList = new AnimationList();
for (long layerId : alayerMap.keySet()) {
FbxObject layer = alayerMap.get(layerId);
animList.add(layer.name, layer.name, 0, -1);
}
}
// Extract aminations
HashMap<String, Animation> anims = new HashMap<String, Animation>();
for (AnimInverval animInfo : animList.list) {
float realLength = 0;
float length = (animInfo.lastFrame - animInfo.firstFrame) / this.animFrameRate;
float animStart = animInfo.firstFrame / this.animFrameRate;
float animStop = animInfo.lastFrame / this.animFrameRate;
Animation anim = new Animation(animInfo.name, length);
// Search source layer for animation nodes
long sourceLayerId = 0L;
for (long layerId : alayerMap.keySet()) {
FbxObject layer = alayerMap.get(layerId);
if (layer.name.equals(animInfo.layerName)) {
sourceLayerId = layerId;
break;
}
}
// Build bone tracks
for (FbxNode limb : limbMap.values()) {
// Animation channels may have different keyframes (non-baked animation).
// So we have to restore intermediate values for all channels cause of JME requires
// a bone track as a single channel with collective transformation for each keyframe
// Sorted unique timestamps
Set<Long> stamps = new TreeSet<Long>();
FbxAnimNode animTranslation = limb.animTranslation(sourceLayerId);
FbxAnimNode animRotation = limb.animRotation(sourceLayerId);
FbxAnimNode animScale = limb.animScale(sourceLayerId);
boolean haveTranslation = haveAnyChannel(animTranslation);
boolean haveRotation = haveAnyChannel(animRotation);
boolean haveScale = haveAnyChannel(animScale);
// Collect keyframes stamps
if (haveTranslation)
animTranslation.exportTimes(stamps);
if (haveRotation)
animRotation.exportTimes(stamps);
if (haveScale)
animScale.exportTimes(stamps);
if (stamps.isEmpty())
continue;
long[] keyTimes = new long[stamps.size()];
int cnt = 0;
for (long t : stamps) keyTimes[cnt++] = t;
// Calculate keys interval by animation time interval
int firstKeyIndex = 0;
int lastKeyIndex = keyTimes.length - 1;
for (int i = 0; i < keyTimes.length; ++i) {
// Translate into seconds
float time = (float) (((double) keyTimes[i]) * secondsPerUnit);
if (time <= animStart)
firstKeyIndex = i;
if (time >= animStop && animStop >= 0) {
lastKeyIndex = i;
break;
}
}
int keysCount = lastKeyIndex - firstKeyIndex + 1;
if (keysCount <= 0)
continue;
float[] times = new float[keysCount];
Vector3f[] translations = new Vector3f[keysCount];
Quaternion[] rotations = new Quaternion[keysCount];
Vector3f[] scales = null;
// Calculate keyframes times
for (int i = 0; i < keysCount; ++i) {
int keyIndex = firstKeyIndex + i;
// Translate into seconds
float time = (float) (((double) keyTimes[keyIndex]) * secondsPerUnit);
times[i] = time - animStart;
realLength = Math.max(realLength, times[i]);
}
// Load keyframes from animation curves
if (haveTranslation) {
for (int i = 0; i < keysCount; ++i) {
int keyIndex = firstKeyIndex + i;
FbxAnimNode n = animTranslation;
// Why do it here but not in other places? FBX magic?
Vector3f tvec = n.getValue(keyTimes[keyIndex], n.value).subtractLocal(n.value);
translations[i] = tvec.divideLocal(unitSize);
}
} else {
for (int i = 0; i < keysCount; ++i) translations[i] = Vector3f.ZERO;
}
RotationOrder ro = RotationOrder.EULER_XYZ;
if (haveRotation) {
for (int i = 0; i < keysCount; ++i) {
int keyIndex = firstKeyIndex + i;
FbxAnimNode n = animRotation;
Vector3f tvec = n.getValue(keyTimes[keyIndex], n.value);
rotations[i] = ro.rotate(tvec);
}
} else {
for (int i = 0; i < keysCount; ++i) rotations[i] = Quaternion.IDENTITY;
}
if (haveScale) {
scales = new Vector3f[keysCount];
for (int i = 0; i < keysCount; ++i) {
int keyIndex = firstKeyIndex + i;
FbxAnimNode n = animScale;
Vector3f tvec = n.getValue(keyTimes[keyIndex], n.value);
scales[i] = tvec;
}
}
BoneTrack track = null;
if (haveScale)
track = new BoneTrack(limb.boneIndex, times, translations, rotations, scales);
else
track = new BoneTrack(limb.boneIndex, times, translations, rotations);
anim.addTrack(track);
}
if (realLength != length && animInfo.lastFrame == -1) {
Track[] tracks = anim.getTracks();
if (tracks == null || tracks.length == 0)
continue;
anim = new Animation(animInfo.name, realLength);
for (Track track : tracks) anim.addTrack(track);
}
anims.put(anim.getName(), anim);
}
animControl.setAnimations(anims);
}
use of com.jme3.scene.plugins.fbx.objects.FbxNode in project jmonkeyengine by jMonkeyEngine.
the class SceneLoader method linkScene.
private void linkScene() {
logger.log(Level.FINE, "Linking scene objects");
long startTime = System.currentTimeMillis();
applySkinning();
buildAnimations();
for (FbxMesh mesh : geomMap.values()) mesh.clearMaterials();
// Remove bones from node structures : JME creates attach node by itself
for (FbxNode limb : limbMap.values()) limb.node.removeFromParent();
long estimatedTime = System.currentTimeMillis() - startTime;
logger.log(Level.FINE, "Linking done in {0} ms", estimatedTime);
}
Aggregations