|
@@ -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
|