|
|
|
@ -13,6 +13,8 @@ import com.jme3.scene.plugins.blender.BlenderContext; |
|
|
|
|
import com.jme3.scene.plugins.blender.BlenderContext.LoadedDataType; |
|
|
|
|
import com.jme3.scene.plugins.blender.constraints.ConstraintHelper; |
|
|
|
|
import com.jme3.scene.plugins.blender.file.BlenderFileException; |
|
|
|
|
import com.jme3.scene.plugins.blender.file.DynamicArray; |
|
|
|
|
import com.jme3.scene.plugins.blender.file.Pointer; |
|
|
|
|
import com.jme3.scene.plugins.blender.file.Structure; |
|
|
|
|
import com.jme3.scene.plugins.blender.objects.ObjectHelper; |
|
|
|
|
|
|
|
|
@ -33,6 +35,13 @@ public class BoneContext { |
|
|
|
|
*/ |
|
|
|
|
public 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 static final int IKFLAG_LOCK_X = 0x01; |
|
|
|
|
private static final int IKFLAG_LOCK_Y = 0x02; |
|
|
|
|
private static final int IKFLAG_LOCK_Z = 0x04; |
|
|
|
|
private static final int IKFLAG_LIMIT_X = 0x08; |
|
|
|
|
private static final int IKFLAG_LIMIT_Y = 0x10; |
|
|
|
|
private static final int IKFLAG_LIMIT_Z = 0x20; |
|
|
|
|
|
|
|
|
|
private BlenderContext blenderContext; |
|
|
|
|
/** The OMA of the bone's armature object. */ |
|
|
|
|
private Long armatureObjectOMA; |
|
|
|
@ -58,6 +67,21 @@ public class BoneContext { |
|
|
|
|
private float length; |
|
|
|
|
/** The bone's deform envelope. */ |
|
|
|
|
private BoneEnvelope boneEnvelope; |
|
|
|
|
|
|
|
|
|
// The below data is used only for IK constraint computations.
|
|
|
|
|
|
|
|
|
|
/** The bone's stretch value. */ |
|
|
|
|
private float ikStretch; |
|
|
|
|
/** Bone's rotation minimum values. */ |
|
|
|
|
private Vector3f limitMin; |
|
|
|
|
/** Bone's rotation maximum values. */ |
|
|
|
|
private Vector3f limitMax; |
|
|
|
|
/** The bone's stiffness values (how much it rotates during IK computations. */ |
|
|
|
|
private Vector3f stiffness; |
|
|
|
|
/** Values that indicate if any axis' rotation should be limited by some angle. */ |
|
|
|
|
private boolean[] limits; |
|
|
|
|
/** Values that indicate if any axis' rotation should be disabled during IK computations. */ |
|
|
|
|
private boolean[] locks; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Constructor. Creates the basic set of bone's data. |
|
|
|
@ -91,6 +115,7 @@ public class BoneContext { |
|
|
|
|
* an exception is thrown when problem with blender data reading |
|
|
|
|
* occurs |
|
|
|
|
*/ |
|
|
|
|
@SuppressWarnings("unchecked") |
|
|
|
|
private BoneContext(Structure boneStructure, Long armatureObjectOMA, BoneContext parent, BlenderContext blenderContext) throws BlenderFileException { |
|
|
|
|
this.parent = parent; |
|
|
|
|
this.blenderContext = blenderContext; |
|
|
|
@ -108,7 +133,8 @@ public class BoneContext { |
|
|
|
|
globalBoneMatrix.multLocal(BONE_ARMATURE_TRANSFORMATION_MATRIX); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Spatial armature = (Spatial) objectHelper.toObject(blenderContext.getFileBlock(armatureObjectOMA).getStructure(blenderContext), blenderContext); |
|
|
|
|
Structure armatureStructure = blenderContext.getFileBlock(armatureObjectOMA).getStructure(blenderContext); |
|
|
|
|
Spatial armature = (Spatial) objectHelper.toObject(armatureStructure, blenderContext); |
|
|
|
|
ConstraintHelper constraintHelper = blenderContext.getHelper(ConstraintHelper.class); |
|
|
|
|
Matrix4f armatureWorldMatrix = constraintHelper.toMatrix(armature.getWorldTransform(), new Matrix4f()); |
|
|
|
|
|
|
|
|
@ -120,6 +146,32 @@ public class BoneContext { |
|
|
|
|
boneEnvelope = new BoneEnvelope(boneStructure, armatureWorldMatrix, blenderContext.getBlenderKey().isFixUpAxis()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// load bone's pose channel data
|
|
|
|
|
Pointer pPose = (Pointer) armatureStructure.getFieldValue("pose"); |
|
|
|
|
if (pPose != null && pPose.isNotNull()) { |
|
|
|
|
List<Structure> poseChannels = ((Structure) pPose.fetchData().get(0).getFieldValue("chanbase")).evaluateListBase(); |
|
|
|
|
for (Structure poseChannel : poseChannels) { |
|
|
|
|
Long boneOMA = ((Pointer) poseChannel.getFieldValue("bone")).getOldMemoryAddress(); |
|
|
|
|
if (boneOMA.equals(this.boneStructure.getOldMemoryAddress())) { |
|
|
|
|
ikStretch = ((Number) poseChannel.getFieldValue("ikstretch")).floatValue(); |
|
|
|
|
DynamicArray<Number> limitMin = (DynamicArray<Number>) poseChannel.getFieldValue("limitmin"); |
|
|
|
|
this.limitMin = new Vector3f(limitMin.get(0).floatValue(), limitMin.get(1).floatValue(), limitMin.get(2).floatValue()); |
|
|
|
|
|
|
|
|
|
DynamicArray<Number> limitMax = (DynamicArray<Number>) poseChannel.getFieldValue("limitmax"); |
|
|
|
|
this.limitMax = new Vector3f(limitMax.get(0).floatValue(), limitMax.get(1).floatValue(), limitMax.get(2).floatValue()); |
|
|
|
|
|
|
|
|
|
DynamicArray<Number> stiffness = (DynamicArray<Number>) poseChannel.getFieldValue("stiffness"); |
|
|
|
|
this.stiffness = new Vector3f(stiffness.get(0).floatValue(), stiffness.get(1).floatValue(), stiffness.get(2).floatValue()); |
|
|
|
|
|
|
|
|
|
int ikFlag = ((Number) poseChannel.getFieldValue("ikflag")).intValue(); |
|
|
|
|
locks = new boolean[] { (ikFlag & IKFLAG_LOCK_X) != 0, (ikFlag & IKFLAG_LOCK_Y) != 0, (ikFlag & IKFLAG_LOCK_Z) != 0 }; |
|
|
|
|
// limits are enabled when locks are disabled, so we ween to take that into account here
|
|
|
|
|
limits = new boolean[] { (ikFlag & IKFLAG_LIMIT_X & ~IKFLAG_LOCK_X) != 0, (ikFlag & IKFLAG_LIMIT_Y & ~IKFLAG_LOCK_Y) != 0, (ikFlag & IKFLAG_LIMIT_Z & ~IKFLAG_LOCK_Z) != 0 }; |
|
|
|
|
break;// we have found what we need, no need to search further
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// create the children
|
|
|
|
|
List<Structure> childbase = ((Structure) boneStructure.getFieldValue("childbase")).evaluateListBase(); |
|
|
|
|
for (Structure child : childbase) { |
|
|
|
@ -234,6 +286,76 @@ public class BoneContext { |
|
|
|
|
return boneEnvelope; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* @return bone's stretch factor |
|
|
|
|
*/ |
|
|
|
|
public float getIkStretch() { |
|
|
|
|
return ikStretch; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* @return indicates if the X rotation should be limited |
|
|
|
|
*/ |
|
|
|
|
public boolean isLimitX() { |
|
|
|
|
return limits != null ? limits[0] : false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* @return indicates if the Y rotation should be limited |
|
|
|
|
*/ |
|
|
|
|
public boolean isLimitY() { |
|
|
|
|
return limits != null ? limits[1] : false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* @return indicates if the Z rotation should be limited |
|
|
|
|
*/ |
|
|
|
|
public boolean isLimitZ() { |
|
|
|
|
return limits != null ? limits[2] : false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* @return indicates if the X rotation should be disabled |
|
|
|
|
*/ |
|
|
|
|
public boolean isLockX() { |
|
|
|
|
return locks != null ? locks[0] : false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* @return indicates if the Y rotation should be disabled |
|
|
|
|
*/ |
|
|
|
|
public boolean isLockY() { |
|
|
|
|
return locks != null ? locks[1] : false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* @return indicates if the Z rotation should be disabled |
|
|
|
|
*/ |
|
|
|
|
public boolean isLockZ() { |
|
|
|
|
return locks != null ? locks[2] : false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* @return the minimum values in rotation limitation (if limitation is enabled for specific axis). |
|
|
|
|
*/ |
|
|
|
|
public Vector3f getLimitMin() { |
|
|
|
|
return limitMin; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* @return the maximum values in rotation limitation (if limitation is enabled for specific axis). |
|
|
|
|
*/ |
|
|
|
|
public Vector3f getLimitMax() { |
|
|
|
|
return limitMax; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* @return the stiffness of the bone |
|
|
|
|
*/ |
|
|
|
|
public Vector3f getStiffness() { |
|
|
|
|
return stiffness; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Tells if the bone is of specified property defined by its flag. |
|
|
|
|
* @param flagMask |
|
|
|
|