- simplified implementation for bones loading - static bones poses discarded - loading of object animation for blender 2.50+ added (didn't work for these versions before) - several small bugfixes git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9115 75d07b2b-3a1a-0410-a2c5-0572b91ccdca3.0
parent
fb68a176b5
commit
3a84693f68
@ -0,0 +1,204 @@ |
||||
package com.jme3.scene.plugins.blender.animations; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
import com.jme3.animation.Bone; |
||||
import com.jme3.math.Matrix4f; |
||||
import com.jme3.math.Quaternion; |
||||
import com.jme3.math.Transform; |
||||
import com.jme3.math.Vector3f; |
||||
import com.jme3.scene.plugins.blender.BlenderContext; |
||||
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; |
||||
import com.jme3.scene.plugins.blender.file.DynamicArray; |
||||
import com.jme3.scene.plugins.blender.file.Structure; |
||||
import com.jme3.scene.plugins.blender.objects.ObjectHelper; |
||||
|
||||
/** |
||||
* This class holds the basic data that describes a bone. |
||||
* |
||||
* @author Marcin Roguski (Kaelthas) |
||||
*/ |
||||
public class BoneContext { |
||||
/** The structure of the bone. */ |
||||
private Structure boneStructure; |
||||
/** Bone's pose channel structure. */ |
||||
private Structure poseChannel; |
||||
/** Bone's name. */ |
||||
private String boneName; |
||||
/** This variable indicates if the Y axis should be the UP axis. */ |
||||
private boolean fixUpAxis; |
||||
/** The bone's armature matrix. */ |
||||
private Matrix4f armatureMatrix; |
||||
/** The parent context. */ |
||||
private BoneContext parent; |
||||
/** The children of this context. */ |
||||
private List<BoneContext> children = new ArrayList<BoneContext>(); |
||||
/** Created bone (available after calling 'buildBone' method). */ |
||||
private Bone bone; |
||||
/** Bone's pose transform (available after calling 'buildBone' method). */ |
||||
private Transform poseTransform = new Transform(); |
||||
/** The bone's rest matrix. */ |
||||
private Matrix4f restMatrix; |
||||
/** Bone's total inverse transformation. */ |
||||
private Matrix4f inverseTotalTransformation; |
||||
/** Bone's parent inverse matrix. */ |
||||
private Matrix4f inverseParentMatrix; |
||||
|
||||
/** |
||||
* Constructor. Creates the basic set of bone's data. |
||||
* |
||||
* @param boneStructure |
||||
* the bone's structure |
||||
* @param objectToArmatureMatrix |
||||
* object-to-armature transformation matrix |
||||
* @param bonesPoseChannels |
||||
* a map of pose channels for each bone OMA |
||||
* @param blenderContext |
||||
* the blender context |
||||
* @throws BlenderFileException |
||||
* an exception is thrown when problem with blender data reading |
||||
* occurs |
||||
*/ |
||||
public BoneContext(Structure boneStructure, Matrix4f objectToArmatureMatrix, final Map<Long, Structure> bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException { |
||||
this(boneStructure, null, objectToArmatureMatrix, bonesPoseChannels, blenderContext); |
||||
} |
||||
|
||||
/** |
||||
* Constructor. Creates the basic set of bone's data. |
||||
* |
||||
* @param boneStructure |
||||
* the bone's structure |
||||
* @param parent |
||||
* bone's parent (null if the bone is the root bone) |
||||
* @param objectToArmatureMatrix |
||||
* object-to-armature transformation matrix |
||||
* @param bonesPoseChannels |
||||
* a map of pose channels for each bone OMA |
||||
* @param blenderContext |
||||
* the blender context |
||||
* @throws BlenderFileException |
||||
* an exception is thrown when problem with blender data reading |
||||
* occurs |
||||
*/ |
||||
private BoneContext(Structure boneStructure, BoneContext parent, Matrix4f objectToArmatureMatrix, final Map<Long, Structure> bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException { |
||||
this.parent = parent; |
||||
this.boneStructure = boneStructure; |
||||
boneName = boneStructure.getFieldValue("name").toString(); |
||||
ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class); |
||||
armatureMatrix = objectHelper.getMatrix(boneStructure, "arm_mat", true); |
||||
|
||||
fixUpAxis = blenderContext.getBlenderKey().isFixUpAxis(); |
||||
this.computeRestMatrix(objectToArmatureMatrix); |
||||
List<Structure> childbase = ((Structure) boneStructure.getFieldValue("childbase")).evaluateListBase(blenderContext); |
||||
for (Structure child : childbase) { |
||||
this.children.add(new BoneContext(child, this, objectToArmatureMatrix, bonesPoseChannels, blenderContext)); |
||||
} |
||||
|
||||
poseChannel = bonesPoseChannels.get(boneStructure.getOldMemoryAddress()); |
||||
|
||||
blenderContext.setBoneContext(boneStructure.getOldMemoryAddress(), this); |
||||
} |
||||
|
||||
/** |
||||
* This method computes the rest matrix for the bone. |
||||
* |
||||
* @param objectToArmatureMatrix |
||||
* object-to-armature transformation matrix |
||||
*/ |
||||
private void computeRestMatrix(Matrix4f objectToArmatureMatrix) { |
||||
if (parent != null) { |
||||
inverseParentMatrix = parent.inverseTotalTransformation.clone(); |
||||
} else if (fixUpAxis) { |
||||
inverseParentMatrix = objectToArmatureMatrix.clone(); |
||||
} else { |
||||
inverseParentMatrix = Matrix4f.IDENTITY.clone(); |
||||
} |
||||
|
||||
restMatrix = armatureMatrix.clone(); |
||||
inverseTotalTransformation = restMatrix.invert(); |
||||
|
||||
restMatrix = inverseParentMatrix.mult(restMatrix); |
||||
|
||||
for (BoneContext child : this.children) { |
||||
child.computeRestMatrix(objectToArmatureMatrix); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* This method computes the pose transform for the bone. |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
private void computePoseTransform() { |
||||
DynamicArray<Number> loc = (DynamicArray<Number>) poseChannel.getFieldValue("loc"); |
||||
DynamicArray<Number> size = (DynamicArray<Number>) poseChannel.getFieldValue("size"); |
||||
DynamicArray<Number> quat = (DynamicArray<Number>) poseChannel.getFieldValue("quat"); |
||||
if (fixUpAxis) { |
||||
poseTransform.setTranslation(loc.get(0).floatValue(), -loc.get(2).floatValue(), loc.get(1).floatValue()); |
||||
poseTransform.setRotation(new Quaternion(quat.get(1).floatValue(), quat.get(3).floatValue(), -quat.get(2).floatValue(), quat.get(0).floatValue())); |
||||
poseTransform.setScale(size.get(0).floatValue(), size.get(2).floatValue(), size.get(1).floatValue()); |
||||
} else { |
||||
poseTransform.setTranslation(loc.get(0).floatValue(), loc.get(1).floatValue(), loc.get(2).floatValue()); |
||||
poseTransform.setRotation(new Quaternion(quat.get(0).floatValue(), quat.get(1).floatValue(), quat.get(2).floatValue(), quat.get(3).floatValue())); |
||||
poseTransform.setScale(size.get(0).floatValue(), size.get(1).floatValue(), size.get(2).floatValue()); |
||||
} |
||||
|
||||
Transform localTransform = new Transform(bone.getLocalPosition(), bone.getLocalRotation()); |
||||
localTransform.setScale(bone.getLocalScale()); |
||||
localTransform.getTranslation().addLocal(poseTransform.getTranslation()); |
||||
localTransform.getRotation().multLocal(poseTransform.getRotation()); |
||||
localTransform.getScale().multLocal(poseTransform.getScale()); |
||||
|
||||
poseTransform.set(localTransform); |
||||
} |
||||
|
||||
/** |
||||
* This method builds the bone. It recursively builds the bone's children. |
||||
* |
||||
* @param bones |
||||
* a list of bones where the newly created bone will be added |
||||
* @param boneOMAs |
||||
* the map between bone and its old memory address |
||||
* @param blenderContext |
||||
* the blender context |
||||
* @return newly created bone |
||||
*/ |
||||
public Bone buildBone(List<Bone> bones, Map<Bone, Long> boneOMAs, BlenderContext blenderContext) { |
||||
Long boneOMA = boneStructure.getOldMemoryAddress(); |
||||
bone = new Bone(boneName); |
||||
bones.add(bone); |
||||
boneOMAs.put(bone, boneOMA); |
||||
blenderContext.addLoadedFeatures(boneOMA, boneName, boneStructure, bone); |
||||
|
||||
Matrix4f pose = this.restMatrix.clone(); |
||||
ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class); |
||||
|
||||
Vector3f poseLocation = pose.toTranslationVector(); |
||||
Quaternion rotation = pose.toRotationQuat(); |
||||
Vector3f scale = objectHelper.getScale(pose); |
||||
|
||||
bone.setBindTransforms(poseLocation, rotation, scale); |
||||
for (BoneContext child : children) { |
||||
bone.addChild(child.buildBone(bones, boneOMAs, blenderContext)); |
||||
} |
||||
|
||||
this.computePoseTransform(); |
||||
|
||||
return bone; |
||||
} |
||||
|
||||
/** |
||||
* @return bone's pose transformation |
||||
*/ |
||||
public Transform getPoseTransform() { |
||||
return poseTransform; |
||||
} |
||||
|
||||
/** |
||||
* @return built bone (available after calling 'buildBone' method) |
||||
*/ |
||||
public Bone getBone() { |
||||
return bone; |
||||
} |
||||
} |
Loading…
Reference in new issue