@ -8,7 +8,10 @@ import com.jme3.animation.Skeleton;
import com.jme3.math.Matrix4f ;
import com.jme3.math.Quaternion ;
import com.jme3.math.Vector3f ;
import com.jme3.scene.Spatial ;
import com.jme3.scene.plugins.blender.BlenderContext ;
import com.jme3.scene.plugins.blender.BlenderContext.LoadedFeatureDataType ;
import com.jme3.scene.plugins.blender.constraints.ConstraintHelper ;
import com.jme3.scene.plugins.blender.file.BlenderFileException ;
import com.jme3.scene.plugins.blender.file.Structure ;
import com.jme3.scene.plugins.blender.objects.ObjectHelper ;
@ -19,27 +22,36 @@ import com.jme3.scene.plugins.blender.objects.ObjectHelper;
* @author Marcin Roguski ( Kaelthas )
* /
public class BoneContext {
private BlenderContext blenderContext ;
// the flags of the bone
private static final int CONNECTED_TO_PARENT = 0x10 ;
/ * *
* The bones ' matrices have , unlike objects ' , the coordinate system identical to JME ' s ( Y axis is UP , X to the right and Z toward us ) .
* So in order to have them loaded properly we need to transform their armature matrix ( which blender sees as rotated ) to make sure we get identical results .
* /
private static final Matrix4f BONE_ARMATURE_TRANSFORMATION_MATRIX = new Matrix4f ( 1 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , - 1 , 0 , 0 , 0 , 0 , 0 , 1 ) ;
private BlenderContext blenderContext ;
/** The OMA of the bone's armature object. */
private Long armatureObjectOMA ;
private Long armatureObjectOMA ;
/** The structure of the bone. */
private Structure boneStructure ;
private Structure boneStructure ;
/** Bone's name. */
private String boneName ;
/** The bone's armature matrix. */
private Matrix4f armatureMatrix ;
private String boneName ;
/** The bone's flag. */
private int flag ;
/** The bone's matrix in world space. */
private Matrix4f globalBoneMatrix ;
/** The bone's matrix in the model space. */
private Matrix4f boneMatrixInModelSpace ;
/** The parent context. */
private BoneContext parent ;
private BoneContext parent ;
/** The children of this context. */
private List < BoneContext > children = new ArrayList < BoneContext > ( ) ;
private List < BoneContext > children = new ArrayList < BoneContext > ( ) ;
/** Created bone (available after calling 'buildBone' method). */
private Bone bone ;
/** The bone's rest matrix. */
private Matrix4f restMatrix ;
/** Bone's total inverse transformation. */
private Matrix4f inverseTotalTransformation ;
private Bone bone ;
/** The length of the bone. */
private float length ;
private float length ;
/ * *
* Constructor . Creates the basic set of bone ' s data .
@ -79,21 +91,26 @@ public class BoneContext {
this . boneStructure = boneStructure ;
this . armatureObjectOMA = armatureObjectOMA ;
boneName = boneStructure . getFieldValue ( "name" ) . toString ( ) ;
flag = ( ( Number ) boneStructure . getFieldValue ( "flag" ) ) . intValue ( ) ;
length = ( ( Number ) boneStructure . getFieldValue ( "length" ) ) . floatValue ( ) ;
ObjectHelper objectHelper = blenderContext . getHelper ( ObjectHelper . class ) ;
armatureMatrix = objectHelper . getMatrix ( boneStructure , "arm_mat" , blenderContext . getBlenderKey ( ) . isFixUpAxis ( ) ) ;
// compute the bone's rest matrix
restMatrix = armatureMatrix . clone ( ) ;
inverseTotalTransformation = restMatrix . invert ( ) ;
if ( parent ! = null ) {
restMatrix = parent . inverseTotalTransformation . mult ( restMatrix ) ;
}
// first get the bone matrix in its armature space
globalBoneMatrix = objectHelper . getMatrix ( boneStructure , "arm_mat" , blenderContext . getBlenderKey ( ) . isFixUpAxis ( ) ) ;
// then make sure it is rotated in a proper way to fit the jme bone transformation conventions
globalBoneMatrix . multLocal ( BONE_ARMATURE_TRANSFORMATION_MATRIX ) ;
Spatial armature = ( Spatial ) blenderContext . getLoadedFeature ( armatureObjectOMA , LoadedFeatureDataType . LOADED_FEATURE ) ;
ConstraintHelper constraintHelper = blenderContext . getHelper ( ConstraintHelper . class ) ;
Matrix4f armatureWorldMatrix = constraintHelper . toMatrix ( armature . getWorldTransform ( ) ) ;
// and now compute the final bone matrix in world space
globalBoneMatrix = armatureWorldMatrix . mult ( globalBoneMatrix ) ;
// create the children
List < Structure > childbase = ( ( Structure ) boneStructure . getFieldValue ( "childbase" ) ) . evaluateListBase ( blenderContext ) ;
for ( Structure child : childbase ) {
this . children . add ( new BoneContext ( child , armatureObjectOMA , this , blenderContext ) ) ;
children . add ( new BoneContext ( child , armatureObjectOMA , this , blenderContext ) ) ;
}
blenderContext . setBoneContext ( boneStructure . getOldMemoryAddress ( ) , this ) ;
@ -104,31 +121,36 @@ public class BoneContext {
*
* @param bones
* a list of bones where the newly created bone will be added
* @param objectToArmatureMatrix
* object to armature transformation matrix
* @param skeletonOwnerOma
* the spatial of the object that will own the skeleton
* @param blenderContext
* the blender context
* @return newly created bone
* /
public Bone buildBone ( List < Bone > bones , Matrix4f objectToArmatureMatrix , BlenderContext blenderContext ) {
public Bone buildBone ( List < Bone > bones , Long skeletonOwnerOma , BlenderContext blenderContext ) {
Long boneOMA = boneStructure . getOldMemoryAddress ( ) ;
bone = new Bone ( boneName ) ;
bones . add ( bone ) ;
blenderContext . addLoadedFeatures ( boneOMA , boneName , boneStructure , bone ) ;
ObjectHelper objectHelper = blenderContext . getHelper ( ObjectHelper . class ) ;
Vector3f poseLocation = restMatrix . toTranslationVector ( ) ;
Quaternion rotation = restMatrix . toRotationQuat ( ) . normalizeLocal ( ) ;
Vector3f scale = restMatrix . toScaleVector ( ) ;
if ( parent = = null ) {
Quaternion rotationQuaternion = objectToArmatureMatrix . toRotationQuat ( ) . normalizeLocal ( ) ;
scale . multLocal ( objectToArmatureMatrix . toScaleVector ( ) ) ;
rotationQuaternion . multLocal ( poseLocation . addLocal ( objectToArmatureMatrix . toTranslationVector ( ) ) ) ;
rotation . multLocal ( rotationQuaternion ) ;
Structure skeletonOwnerObjectStructure = ( Structure ) blenderContext . getLoadedFeature ( skeletonOwnerOma , LoadedFeatureDataType . LOADED_STRUCTURE ) ;
Matrix4f invertedObjectOwnerGlobalMatrix = objectHelper . getMatrix ( skeletonOwnerObjectStructure , "imat" , blenderContext . getBlenderKey ( ) . isFixUpAxis ( ) ) ;
if ( objectHelper . isParent ( skeletonOwnerOma , armatureObjectOMA ) ) {
boneMatrixInModelSpace = globalBoneMatrix . mult ( invertedObjectOwnerGlobalMatrix ) ;
} else {
boneMatrixInModelSpace = invertedObjectOwnerGlobalMatrix . mult ( globalBoneMatrix ) ;
}
Matrix4f boneLocalMatrix = parent = = null ? boneMatrixInModelSpace : parent . boneMatrixInModelSpace . invert ( ) . multLocal ( boneMatrixInModelSpace ) ;
Vector3f poseLocation = parent = = null | | ! this . is ( CONNECTED_TO_PARENT ) ? boneLocalMatrix . toTranslationVector ( ) : new Vector3f ( 0 , parent . length , 0 ) ;
Quaternion rotation = boneLocalMatrix . toRotationQuat ( ) . normalizeLocal ( ) ;
Vector3f scale = boneLocalMatrix . toScaleVector ( ) ;
bone . setBindTransforms ( poseLocation , rotation , scale ) ;
for ( BoneContext child : children ) {
bone . addChild ( child . buildBone ( bones , objectToArmatureMatrix , blenderContext ) ) ;
bone . addChild ( child . buildBone ( bones , skeletonOwnerOma , blenderContext ) ) ;
}
return bone ;
@ -168,4 +190,14 @@ public class BoneContext {
public Skeleton getSkeleton ( ) {
return blenderContext . getSkeleton ( armatureObjectOMA ) ;
}
/ * *
* Tells if the bone is of specified property defined by its flag .
* @param flagMask
* the mask of the flag ( constants defined in this class )
* @return < b > true < / b > if the bone IS of specified proeprty and < b > false < / b > otherwise
* /
private boolean is ( int flagMask ) {
return ( flag & flagMask ) ! = 0 ;
}
}