Making sure that bone constraint will target either object or bone in its own armature. Allowing bone to target object (and not only bone as it was until now).

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10397 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
Kae..pl 12 years ago
parent 81b8ed4a47
commit dcd5fd5b4e
  1. 5
      engine/src/blender/com/jme3/scene/plugins/blender/animations/ArmatureHelper.java
  2. 29
      engine/src/blender/com/jme3/scene/plugins/blender/animations/BoneContext.java
  3. 145
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/BoneConstraint.java
  4. 10
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/Constraint.java
  5. 5
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/SkeletonConstraint.java
  6. 1
      engine/src/blender/com/jme3/scene/plugins/blender/constraints/SpatialConstraint.java
  7. 3
      engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ArmatureModifier.java

@ -35,6 +35,7 @@ import com.jme3.animation.Bone;
import com.jme3.animation.BoneTrack; import com.jme3.animation.BoneTrack;
import com.jme3.animation.Skeleton; import com.jme3.animation.Skeleton;
import com.jme3.math.Matrix4f; import com.jme3.math.Matrix4f;
import com.jme3.scene.Spatial;
import com.jme3.scene.plugins.blender.AbstractBlenderHelper; import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
import com.jme3.scene.plugins.blender.BlenderContext; import com.jme3.scene.plugins.blender.BlenderContext;
import com.jme3.scene.plugins.blender.curves.BezierCurve; import com.jme3.scene.plugins.blender.curves.BezierCurve;
@ -92,8 +93,8 @@ public class ArmatureHelper extends AbstractBlenderHelper {
* an exception is thrown when there is problem with the blender * an exception is thrown when there is problem with the blender
* file * file
*/ */
public void buildBones(Structure boneStructure, Bone parent, List<Bone> result, Matrix4f arbt, final Map<Long, Structure> bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException { public void buildBones(Long armatureObjectOMA, Structure boneStructure, Bone parent, List<Bone> result, Matrix4f arbt, final Map<Long, Structure> bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException {
BoneContext bc = new BoneContext(boneStructure, arbt, bonesPoseChannels, blenderContext); BoneContext bc = new BoneContext(armatureObjectOMA, boneStructure, arbt, bonesPoseChannels, blenderContext);
bc.buildBone(result, bonesOMAs, blenderContext); bc.buildBone(result, bonesOMAs, blenderContext);
} }

@ -1,5 +1,9 @@
package com.jme3.scene.plugins.blender.animations; 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.animation.Bone;
import com.jme3.math.Matrix4f; import com.jme3.math.Matrix4f;
import com.jme3.math.Quaternion; import com.jme3.math.Quaternion;
@ -10,9 +14,6 @@ import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
import com.jme3.scene.plugins.blender.file.DynamicArray; import com.jme3.scene.plugins.blender.file.DynamicArray;
import com.jme3.scene.plugins.blender.file.Structure; import com.jme3.scene.plugins.blender.file.Structure;
import com.jme3.scene.plugins.blender.objects.ObjectHelper; import com.jme3.scene.plugins.blender.objects.ObjectHelper;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/** /**
* This class holds the basic data that describes a bone. * This class holds the basic data that describes a bone.
@ -20,6 +21,8 @@ import java.util.Map;
* @author Marcin Roguski (Kaelthas) * @author Marcin Roguski (Kaelthas)
*/ */
public class BoneContext { public class BoneContext {
/** The OMA of the bone's armature object. */
private Long armatureObjectOMA;
/** The structure of the bone. */ /** The structure of the bone. */
private Structure boneStructure; private Structure boneStructure;
/** Bone's pose channel structure. */ /** Bone's pose channel structure. */
@ -48,6 +51,8 @@ public class BoneContext {
/** /**
* Constructor. Creates the basic set of bone's data. * Constructor. Creates the basic set of bone's data.
* *
* @param armatureObjectOMA
* the OMA of the bone's armature object
* @param boneStructure * @param boneStructure
* the bone's structure * the bone's structure
* @param objectToArmatureMatrix * @param objectToArmatureMatrix
@ -60,8 +65,8 @@ public class BoneContext {
* an exception is thrown when problem with blender data reading * an exception is thrown when problem with blender data reading
* occurs * occurs
*/ */
public BoneContext(Structure boneStructure, Matrix4f objectToArmatureMatrix, final Map<Long, Structure> bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException { public BoneContext(Long armatureObjectOMA, Structure boneStructure, Matrix4f objectToArmatureMatrix, final Map<Long, Structure> bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException {
this(boneStructure, null, objectToArmatureMatrix, bonesPoseChannels, blenderContext); this(boneStructure, armatureObjectOMA, null, objectToArmatureMatrix, bonesPoseChannels, blenderContext);
} }
/** /**
@ -69,6 +74,8 @@ public class BoneContext {
* *
* @param boneStructure * @param boneStructure
* the bone's structure * the bone's structure
* @param armatureObjectOMA
* the OMA of the bone's armature object
* @param parent * @param parent
* bone's parent (null if the bone is the root bone) * bone's parent (null if the bone is the root bone)
* @param objectToArmatureMatrix * @param objectToArmatureMatrix
@ -81,9 +88,10 @@ public class BoneContext {
* an exception is thrown when problem with blender data reading * an exception is thrown when problem with blender data reading
* occurs * occurs
*/ */
private BoneContext(Structure boneStructure, BoneContext parent, Matrix4f objectToArmatureMatrix, final Map<Long, Structure> bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException { private BoneContext(Structure boneStructure, Long armatureObjectOMA, BoneContext parent, Matrix4f objectToArmatureMatrix, final Map<Long, Structure> bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException {
this.parent = parent; this.parent = parent;
this.boneStructure = boneStructure; this.boneStructure = boneStructure;
this.armatureObjectOMA = armatureObjectOMA;
boneName = boneStructure.getFieldValue("name").toString(); boneName = boneStructure.getFieldValue("name").toString();
ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class); ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
armatureMatrix = objectHelper.getMatrix(boneStructure, "arm_mat", true); armatureMatrix = objectHelper.getMatrix(boneStructure, "arm_mat", true);
@ -92,7 +100,7 @@ public class BoneContext {
this.computeRestMatrix(objectToArmatureMatrix); this.computeRestMatrix(objectToArmatureMatrix);
List<Structure> childbase = ((Structure) boneStructure.getFieldValue("childbase")).evaluateListBase(blenderContext); List<Structure> childbase = ((Structure) boneStructure.getFieldValue("childbase")).evaluateListBase(blenderContext);
for (Structure child : childbase) { for (Structure child : childbase) {
this.children.add(new BoneContext(child, this, objectToArmatureMatrix, bonesPoseChannels, blenderContext)); this.children.add(new BoneContext(child, armatureObjectOMA, this, objectToArmatureMatrix, bonesPoseChannels, blenderContext));
} }
poseChannel = bonesPoseChannels.get(boneStructure.getOldMemoryAddress()); poseChannel = bonesPoseChannels.get(boneStructure.getOldMemoryAddress());
@ -207,4 +215,11 @@ public class BoneContext {
public Long getBoneOma() { public Long getBoneOma() {
return boneStructure.getOldMemoryAddress(); return boneStructure.getOldMemoryAddress();
} }
/**
* @return OMA of the bone's armature object
*/
public Long getArmatureObjectOMA() {
return armatureObjectOMA;
}
} }

@ -1,6 +1,7 @@
package com.jme3.scene.plugins.blender.constraints; package com.jme3.scene.plugins.blender.constraints;
import java.util.Arrays; import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import com.jme3.animation.Animation; import com.jme3.animation.Animation;
@ -10,14 +11,15 @@ import com.jme3.animation.Track;
import com.jme3.math.Quaternion; import com.jme3.math.Quaternion;
import com.jme3.math.Transform; import com.jme3.math.Transform;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.scene.Spatial;
import com.jme3.scene.plugins.blender.BlenderContext; import com.jme3.scene.plugins.blender.BlenderContext;
import com.jme3.scene.plugins.blender.BlenderContext.LoadedFeatureDataType; import com.jme3.scene.plugins.blender.BlenderContext.LoadedFeatureDataType;
import com.jme3.scene.plugins.blender.animations.ArmatureHelper;
import com.jme3.scene.plugins.blender.animations.BoneContext; import com.jme3.scene.plugins.blender.animations.BoneContext;
import com.jme3.scene.plugins.blender.animations.Ipo; import com.jme3.scene.plugins.blender.animations.Ipo;
import com.jme3.scene.plugins.blender.constraints.ConstraintHelper.Space; import com.jme3.scene.plugins.blender.constraints.ConstraintHelper.Space;
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
import com.jme3.scene.plugins.blender.file.Structure; import com.jme3.scene.plugins.blender.file.Structure;
import com.jme3.scene.plugins.blender.objects.ObjectHelper;
import com.jme3.scene.plugins.ogre.AnimData; import com.jme3.scene.plugins.ogre.AnimData;
/** /**
@ -26,52 +28,97 @@ import com.jme3.scene.plugins.ogre.AnimData;
*/ */
/*package*/ class BoneConstraint extends Constraint { /*package*/ class BoneConstraint extends Constraint {
private static final Logger LOGGER = Logger.getLogger(BoneConstraint.class.getName()); private static final Logger LOGGER = Logger.getLogger(BoneConstraint.class.getName());
/** The OMA of the target armature. */
protected Long targetArmatureOMA;
protected boolean isNodeTarget;
/**
* The bone constraint constructor.
*
* @param constraintStructure
* the constraint's structure
* @param ownerOMA
* the OMA of the bone that owns the constraint
* @param influenceIpo
* the influence interpolation curve
* @param blenderContext
* the blender context
* @throws BlenderFileException
* exception thrown when problems with blender file occur
*/
public BoneConstraint(Structure constraintStructure, Long ownerOMA, Ipo influenceIpo, BlenderContext blenderContext) public BoneConstraint(Structure constraintStructure, Long ownerOMA, Ipo influenceIpo, BlenderContext blenderContext)
throws BlenderFileException { throws BlenderFileException {
super(constraintStructure, ownerOMA, influenceIpo, blenderContext); super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
targetArmatureOMA = targetOMA;
if(targetArmatureOMA != null && targetArmatureOMA <= 0L) {
targetArmatureOMA = null;
}
targetOMA = null;
if(targetArmatureOMA != null && targetArmatureOMA > 0L && (subtargetName == null || subtargetName.length() == 0)) {
invalid = true;
}
} }
@Override @Override
public void performBakingOperation() { protected boolean validate() {
Bone owner = blenderContext.getBoneContext(ownerOMA).getBone(); if(targetOMA != null) {
Bone target = null; Spatial nodeTarget = (Spatial)blenderContext.getLoadedFeature(targetOMA, LoadedFeatureDataType.LOADED_FEATURE);
//the second part of the if expression verifies if the found node (if any) is an armature node
if(targetArmatureOMA != null) {//first make sure the target is loaded if(nodeTarget == null || nodeTarget.getUserData(ArmatureHelper.ARMETURE_NODE_MARKER) != null) {
ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class); //if the target is not an object node then it is an Armature, so make sure the bone is in the current skeleton
try { BoneContext boneContext = blenderContext.getBoneContext(ownerOMA);
objectHelper.toObject((Structure) blenderContext.getLoadedFeature(targetArmatureOMA, LoadedFeatureDataType.LOADED_STRUCTURE), blenderContext); if(targetOMA.longValue() != boneContext.getArmatureObjectOMA().longValue()) {
} catch (BlenderFileException e) { LOGGER.log(Level.WARNING, "Bone constraint {0} must target bone in the its own skeleton! Targeting bone in another skeleton is not supported!", name);
LOGGER.warning("Problems occured during target object loading. The constraint " + name + " will not be applied."); return false;
return ; }
} else {
isNodeTarget = true;
} }
BoneContext boneContext = blenderContext.getBoneByName(subtargetName);
target = boneContext.getBone();
this.targetOMA = boneContext.getBoneOma();
} }
this.prepareTracksForApplyingConstraints(); return true;
AnimData animData = blenderContext.getAnimData(ownerOMA); }
if(animData != null) {
for(Animation animation : animData.anims) { @Override
Transform ownerTransform = constraintHelper.getBoneTransform(ownerSpace, owner); public void performBakingOperation() {
Transform targetTransform = target != null ? constraintHelper.getBoneTransform(targetSpace, target) : null; Bone owner = blenderContext.getBoneContext(ownerOMA).getBone();
BoneTrack boneTrack = constraintHelper.getTrack(owner, animData.skeleton, animation); if(targetOMA != null) {
BoneTrack targetTrack = target != null ? constraintHelper.getTrack(target, animData.skeleton, animation) : null; if(isNodeTarget) {
Spatial target = (Spatial) blenderContext.getLoadedFeature(targetOMA, LoadedFeatureDataType.LOADED_FEATURE);
this.prepareTracksForApplyingConstraints();
AnimData animData = blenderContext.getAnimData(ownerOMA);
if(animData != null) {
for(Animation animation : animData.anims) {
Transform ownerTransform = constraintHelper.getBoneTransform(ownerSpace, owner);
Transform targetTransform = constraintHelper.getNodeObjectTransform(targetSpace, targetOMA, blenderContext);
Track boneTrack = constraintHelper.getTrack(owner, animData.skeleton, animation);
Track targetTrack = constraintHelper.getTrack(target, animation);
constraintDefinition.bake(ownerTransform, targetTransform, boneTrack, targetTrack, this.ipo);
}
}
} else {
BoneContext boneContext = blenderContext.getBoneByName(subtargetName);
Bone target = boneContext.getBone();
this.targetOMA = boneContext.getBoneOma();
constraintDefinition.bake(ownerTransform, targetTransform, boneTrack, targetTrack, this.ipo); this.prepareTracksForApplyingConstraints();
AnimData animData = blenderContext.getAnimData(ownerOMA);
if(animData != null) {
for(Animation animation : animData.anims) {
Transform ownerTransform = constraintHelper.getBoneTransform(ownerSpace, owner);
Transform targetTransform = constraintHelper.getBoneTransform(targetSpace, target);
Track boneTrack = constraintHelper.getTrack(owner, animData.skeleton, animation);
Track targetTrack = constraintHelper.getTrack(target, animData.skeleton, animation);
constraintDefinition.bake(ownerTransform, targetTransform, boneTrack, targetTrack, this.ipo);
}
}
}
} else {
this.prepareTracksForApplyingConstraints();
AnimData animData = blenderContext.getAnimData(ownerOMA);
if(animData != null) {
for(Animation animation : animData.anims) {
Transform ownerTransform = constraintHelper.getBoneTransform(ownerSpace, owner);
Track boneTrack = constraintHelper.getTrack(owner, animData.skeleton, animation);
constraintDefinition.bake(ownerTransform, null, boneTrack, null, this.ipo);
}
} }
} }
} }
@ -112,21 +159,25 @@ import com.jme3.scene.plugins.ogre.AnimData;
/** /**
* The method determines if the bone has animations. * The method determines if the bone has animations.
* *
* @param boneOMA * @param animOwnerOMA
* OMA of the bone * OMA of the animation's owner
* @return <b>true</b> if the bone has animations and <b>false</b> otherwise * @return <b>true</b> if the target has animations and <b>false</b> otherwise
*/ */
protected boolean hasAnimation(Long boneOMA) { protected boolean hasAnimation(Long animOwnerOMA) {
AnimData animData = blenderContext.getAnimData(boneOMA); AnimData animData = blenderContext.getAnimData(animOwnerOMA);
if(animData != null) { if(animData != null) {
Bone bone = blenderContext.getBoneContext(boneOMA).getBone(); if(!isNodeTarget) {
int boneIndex = animData.skeleton.getBoneIndex(bone); Bone bone = blenderContext.getBoneContext(animOwnerOMA).getBone();
for(Animation animation : animData.anims) { int boneIndex = animData.skeleton.getBoneIndex(bone);
for(Track track : animation.getTracks()) { for(Animation animation : animData.anims) {
if(track instanceof BoneTrack && ((BoneTrack) track).getTargetBoneIndex() == boneIndex) { for(Track track : animation.getTracks()) {
return true; if(track instanceof BoneTrack && ((BoneTrack) track).getTargetBoneIndex() == boneIndex) {
return true;
}
} }
} }
} else {
return true;
} }
} }
return false; return false;

@ -21,8 +21,6 @@ import com.jme3.scene.plugins.blender.file.Structure;
public abstract class Constraint { public abstract class Constraint {
private static final Logger LOGGER = Logger.getLogger(Constraint.class.getName()); private static final Logger LOGGER = Logger.getLogger(Constraint.class.getName());
/** Indicates if the constraint is invalid. */
protected boolean invalid;
/** The name of this constraint. */ /** The name of this constraint. */
protected final String name; protected final String name;
/** Indicates if the constraint is already baked or not. */ /** Indicates if the constraint is already baked or not. */
@ -89,7 +87,7 @@ public abstract class Constraint {
* order is kept. * order is kept.
*/ */
public void bake() { public void bake() {
if(invalid) { if(!this.validate()) {
LOGGER.warning("The constraint " + name + " is invalid and will not be applied."); LOGGER.warning("The constraint " + name + " is invalid and will not be applied.");
} else if(!baked) { } else if(!baked) {
if(targetOMA != null) { if(targetOMA != null) {
@ -108,6 +106,12 @@ public abstract class Constraint {
} }
} }
/**
* Performs validation before baking. Checks factors that can prevent constraint from baking that could not be
* checked during constraint loading.
*/
protected abstract boolean validate();
/** /**
* This method should be overwridden and perform the baking opertion. * This method should be overwridden and perform the baking opertion.
*/ */

@ -27,6 +27,11 @@ import com.jme3.scene.plugins.blender.file.Structure;
LOGGER.warning("Applying constraints to skeleton is not supported."); LOGGER.warning("Applying constraints to skeleton is not supported.");
} }
@Override
protected boolean validate() {
return true;
}
@Override @Override
protected void prepareTracksForApplyingConstraints() { } protected void prepareTracksForApplyingConstraints() { }
} }

@ -39,7 +39,6 @@ import com.jme3.scene.plugins.ogre.AnimData;
public SpatialConstraint(Structure constraintStructure, Long ownerOMA, Ipo influenceIpo, BlenderContext blenderContext) public SpatialConstraint(Structure constraintStructure, Long ownerOMA, Ipo influenceIpo, BlenderContext blenderContext)
throws BlenderFileException { throws BlenderFileException {
super(constraintStructure, ownerOMA, influenceIpo, blenderContext); super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
targetOMA = targetArmatureOMA;//spatial constraint uses only targetOMA and not armatureTargetOMA which is set by BoneConstraint
} }
@Override @Override

@ -102,11 +102,12 @@ import com.jme3.util.BufferUtils;
List<Structure> bonebase = ((Structure) armatureStructure.getFieldValue("bonebase")).evaluateListBase(blenderContext); List<Structure> bonebase = ((Structure) armatureStructure.getFieldValue("bonebase")).evaluateListBase(blenderContext);
List<Bone> bonesList = new ArrayList<Bone>(); List<Bone> bonesList = new ArrayList<Bone>();
for (int i = 0; i < bonebase.size(); ++i) { for (int i = 0; i < bonebase.size(); ++i) {
armatureHelper.buildBones(bonebase.get(i), null, bonesList, objectToArmatureTransformation, bonesPoseChannels, blenderContext); armatureHelper.buildBones(armatureObject.getOldMemoryAddress(), bonebase.get(i), null, bonesList, objectToArmatureTransformation, bonesPoseChannels, blenderContext);
} }
bonesList.add(0, new Bone("")); bonesList.add(0, new Bone(""));
Bone[] bones = bonesList.toArray(new Bone[bonesList.size()]); Bone[] bones = bonesList.toArray(new Bone[bonesList.size()]);
skeleton = new Skeleton(bones); skeleton = new Skeleton(bones);
blenderContext.setSkeleton(armatureObject.getOldMemoryAddress(), skeleton);
this.objectStructure = objectStructure; this.objectStructure = objectStructure;
this.meshStructure = meshStructure; this.meshStructure = meshStructure;

Loading…
Cancel
Save