From dcd5fd5b4e1da17ec07a7565b13c15da3ae7b60f Mon Sep 17 00:00:00 2001 From: "Kae..pl" Date: Wed, 13 Feb 2013 21:52:52 +0000 Subject: [PATCH] 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 --- .../blender/animations/ArmatureHelper.java | 5 +- .../blender/animations/BoneContext.java | 29 +++- .../blender/constraints/BoneConstraint.java | 145 ++++++++++++------ .../blender/constraints/Constraint.java | 10 +- .../constraints/SkeletonConstraint.java | 5 + .../constraints/SpatialConstraint.java | 1 - .../blender/modifiers/ArmatureModifier.java | 3 +- 7 files changed, 137 insertions(+), 61 deletions(-) diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/animations/ArmatureHelper.java b/engine/src/blender/com/jme3/scene/plugins/blender/animations/ArmatureHelper.java index 61bc7b4c4..79db7fa49 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/animations/ArmatureHelper.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/animations/ArmatureHelper.java @@ -35,6 +35,7 @@ import com.jme3.animation.Bone; import com.jme3.animation.BoneTrack; import com.jme3.animation.Skeleton; import com.jme3.math.Matrix4f; +import com.jme3.scene.Spatial; import com.jme3.scene.plugins.blender.AbstractBlenderHelper; import com.jme3.scene.plugins.blender.BlenderContext; 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 * file */ - public void buildBones(Structure boneStructure, Bone parent, List result, Matrix4f arbt, final Map bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException { - BoneContext bc = new BoneContext(boneStructure, arbt, bonesPoseChannels, blenderContext); + public void buildBones(Long armatureObjectOMA, Structure boneStructure, Bone parent, List result, Matrix4f arbt, final Map bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException { + BoneContext bc = new BoneContext(armatureObjectOMA, boneStructure, arbt, bonesPoseChannels, blenderContext); bc.buildBone(result, bonesOMAs, blenderContext); } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/animations/BoneContext.java b/engine/src/blender/com/jme3/scene/plugins/blender/animations/BoneContext.java index 9670f605c..956b93c00 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/animations/BoneContext.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/animations/BoneContext.java @@ -1,5 +1,9 @@ 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; @@ -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.Structure; 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. @@ -20,6 +21,8 @@ import java.util.Map; * @author Marcin Roguski (Kaelthas) */ public class BoneContext { + /** The OMA of the bone's armature object. */ + private Long armatureObjectOMA; /** The structure of the bone. */ private Structure boneStructure; /** Bone's pose channel structure. */ @@ -48,6 +51,8 @@ public class BoneContext { /** * Constructor. Creates the basic set of bone's data. * + * @param armatureObjectOMA + * the OMA of the bone's armature object * @param boneStructure * the bone's structure * @param objectToArmatureMatrix @@ -60,8 +65,8 @@ public class BoneContext { * an exception is thrown when problem with blender data reading * occurs */ - public BoneContext(Structure boneStructure, Matrix4f objectToArmatureMatrix, final Map bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException { - this(boneStructure, null, objectToArmatureMatrix, bonesPoseChannels, blenderContext); + public BoneContext(Long armatureObjectOMA, Structure boneStructure, Matrix4f objectToArmatureMatrix, final Map bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException { + this(boneStructure, armatureObjectOMA, null, objectToArmatureMatrix, bonesPoseChannels, blenderContext); } /** @@ -69,6 +74,8 @@ public class BoneContext { * * @param boneStructure * the bone's structure + * @param armatureObjectOMA + * the OMA of the bone's armature object * @param parent * bone's parent (null if the bone is the root bone) * @param objectToArmatureMatrix @@ -81,9 +88,10 @@ public class BoneContext { * an exception is thrown when problem with blender data reading * occurs */ - private BoneContext(Structure boneStructure, BoneContext parent, Matrix4f objectToArmatureMatrix, final Map bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException { + private BoneContext(Structure boneStructure, Long armatureObjectOMA, BoneContext parent, Matrix4f objectToArmatureMatrix, final Map bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException { this.parent = parent; this.boneStructure = boneStructure; + this.armatureObjectOMA = armatureObjectOMA; boneName = boneStructure.getFieldValue("name").toString(); ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class); armatureMatrix = objectHelper.getMatrix(boneStructure, "arm_mat", true); @@ -92,7 +100,7 @@ public class BoneContext { this.computeRestMatrix(objectToArmatureMatrix); List childbase = ((Structure) boneStructure.getFieldValue("childbase")).evaluateListBase(blenderContext); 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()); @@ -207,4 +215,11 @@ public class BoneContext { public Long getBoneOma() { return boneStructure.getOldMemoryAddress(); } + + /** + * @return OMA of the bone's armature object + */ + public Long getArmatureObjectOMA() { + return armatureObjectOMA; + } } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/BoneConstraint.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/BoneConstraint.java index fe44031c7..593fa5667 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/BoneConstraint.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/BoneConstraint.java @@ -1,6 +1,7 @@ package com.jme3.scene.plugins.blender.constraints; import java.util.Arrays; +import java.util.logging.Level; import java.util.logging.Logger; import com.jme3.animation.Animation; @@ -10,14 +11,15 @@ import com.jme3.animation.Track; import com.jme3.math.Quaternion; import com.jme3.math.Transform; 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.animations.ArmatureHelper; import com.jme3.scene.plugins.blender.animations.BoneContext; import com.jme3.scene.plugins.blender.animations.Ipo; import com.jme3.scene.plugins.blender.constraints.ConstraintHelper.Space; import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; import com.jme3.scene.plugins.blender.file.Structure; -import com.jme3.scene.plugins.blender.objects.ObjectHelper; import com.jme3.scene.plugins.ogre.AnimData; /** @@ -26,52 +28,97 @@ import com.jme3.scene.plugins.ogre.AnimData; */ /*package*/ class BoneConstraint extends Constraint { 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) throws BlenderFileException { 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 - public void performBakingOperation() { - Bone owner = blenderContext.getBoneContext(ownerOMA).getBone(); - Bone target = null; - - if(targetArmatureOMA != null) {//first make sure the target is loaded - ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class); - try { - objectHelper.toObject((Structure) blenderContext.getLoadedFeature(targetArmatureOMA, LoadedFeatureDataType.LOADED_STRUCTURE), blenderContext); - } catch (BlenderFileException e) { - LOGGER.warning("Problems occured during target object loading. The constraint " + name + " will not be applied."); - return ; + protected boolean validate() { + if(targetOMA != 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(nodeTarget == null || nodeTarget.getUserData(ArmatureHelper.ARMETURE_NODE_MARKER) != null) { + //if the target is not an object node then it is an Armature, so make sure the bone is in the current skeleton + BoneContext boneContext = blenderContext.getBoneContext(ownerOMA); + if(targetOMA.longValue() != boneContext.getArmatureObjectOMA().longValue()) { + LOGGER.log(Level.WARNING, "Bone constraint {0} must target bone in the its own skeleton! Targeting bone in another skeleton is not supported!", name); + return false; + } + } else { + isNodeTarget = true; } - - BoneContext boneContext = blenderContext.getBoneByName(subtargetName); - target = boneContext.getBone(); - this.targetOMA = boneContext.getBoneOma(); } - this.prepareTracksForApplyingConstraints(); - AnimData animData = blenderContext.getAnimData(ownerOMA); - if(animData != null) { - for(Animation animation : animData.anims) { - Transform ownerTransform = constraintHelper.getBoneTransform(ownerSpace, owner); - Transform targetTransform = target != null ? constraintHelper.getBoneTransform(targetSpace, target) : null; - - BoneTrack boneTrack = constraintHelper.getTrack(owner, animData.skeleton, animation); - BoneTrack targetTrack = target != null ? constraintHelper.getTrack(target, animData.skeleton, animation) : null; + return true; + } + + @Override + public void performBakingOperation() { + Bone owner = blenderContext.getBoneContext(ownerOMA).getBone(); + + if(targetOMA != 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. * - * @param boneOMA - * OMA of the bone - * @return true if the bone has animations and false otherwise + * @param animOwnerOMA + * OMA of the animation's owner + * @return true if the target has animations and false otherwise */ - protected boolean hasAnimation(Long boneOMA) { - AnimData animData = blenderContext.getAnimData(boneOMA); + protected boolean hasAnimation(Long animOwnerOMA) { + AnimData animData = blenderContext.getAnimData(animOwnerOMA); if(animData != null) { - Bone bone = blenderContext.getBoneContext(boneOMA).getBone(); - int boneIndex = animData.skeleton.getBoneIndex(bone); - for(Animation animation : animData.anims) { - for(Track track : animation.getTracks()) { - if(track instanceof BoneTrack && ((BoneTrack) track).getTargetBoneIndex() == boneIndex) { - return true; + if(!isNodeTarget) { + Bone bone = blenderContext.getBoneContext(animOwnerOMA).getBone(); + int boneIndex = animData.skeleton.getBoneIndex(bone); + for(Animation animation : animData.anims) { + for(Track track : animation.getTracks()) { + if(track instanceof BoneTrack && ((BoneTrack) track).getTargetBoneIndex() == boneIndex) { + return true; + } } } + } else { + return true; } } return false; diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/Constraint.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/Constraint.java index d7286be98..07792e652 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/Constraint.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/Constraint.java @@ -21,8 +21,6 @@ import com.jme3.scene.plugins.blender.file.Structure; public abstract class Constraint { private static final Logger LOGGER = Logger.getLogger(Constraint.class.getName()); - /** Indicates if the constraint is invalid. */ - protected boolean invalid; /** The name of this constraint. */ protected final String name; /** Indicates if the constraint is already baked or not. */ @@ -89,7 +87,7 @@ public abstract class Constraint { * order is kept. */ public void bake() { - if(invalid) { + if(!this.validate()) { LOGGER.warning("The constraint " + name + " is invalid and will not be applied."); } else if(!baked) { 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. */ diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/SkeletonConstraint.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/SkeletonConstraint.java index 887018320..8c4c8593b 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/SkeletonConstraint.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/SkeletonConstraint.java @@ -27,6 +27,11 @@ import com.jme3.scene.plugins.blender.file.Structure; LOGGER.warning("Applying constraints to skeleton is not supported."); } + @Override + protected boolean validate() { + return true; + } + @Override protected void prepareTracksForApplyingConstraints() { } } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/SpatialConstraint.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/SpatialConstraint.java index 461b83faa..cc4ddff52 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/SpatialConstraint.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/SpatialConstraint.java @@ -39,7 +39,6 @@ import com.jme3.scene.plugins.ogre.AnimData; public SpatialConstraint(Structure constraintStructure, Long ownerOMA, Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException { super(constraintStructure, ownerOMA, influenceIpo, blenderContext); - targetOMA = targetArmatureOMA;//spatial constraint uses only targetOMA and not armatureTargetOMA which is set by BoneConstraint } @Override diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ArmatureModifier.java b/engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ArmatureModifier.java index cc46cd309..6dfae7d0c 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ArmatureModifier.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ArmatureModifier.java @@ -102,11 +102,12 @@ import com.jme3.util.BufferUtils; List bonebase = ((Structure) armatureStructure.getFieldValue("bonebase")).evaluateListBase(blenderContext); List bonesList = new ArrayList(); 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("")); Bone[] bones = bonesList.toArray(new Bone[bonesList.size()]); skeleton = new Skeleton(bones); + blenderContext.setSkeleton(armatureObject.getOldMemoryAddress(), skeleton); this.objectStructure = objectStructure; this.meshStructure = meshStructure;