Explorar o código

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
Kae..pl %!s(int64=12) %!d(string=hai) anos
pai
achega
dcd5fd5b4e

+ 3 - 2
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<Bone> result, Matrix4f arbt, final Map<Long, Structure> bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException {
-		BoneContext bc = new BoneContext(boneStructure, arbt, bonesPoseChannels, blenderContext);
+	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(armatureObjectOMA, boneStructure, arbt, bonesPoseChannels, blenderContext);
 		bc.buildBone(result, bonesOMAs, blenderContext);
 	}
 

+ 22 - 7
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<Long, Structure> bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException {
-		this(boneStructure, null, objectToArmatureMatrix, bonesPoseChannels, blenderContext);
+	public BoneContext(Long armatureObjectOMA, Structure boneStructure, Matrix4f objectToArmatureMatrix, final Map<Long, Structure> 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<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.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<Structure> 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;
+	}
 }

+ 98 - 47
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 <b>true</b> if the bone has animations and <b>false</b> otherwise
+	 * @param animOwnerOMA
+	 *            OMA of the animation's owner
+	 * @return <b>true</b> if the target has animations and <b>false</b> 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;

+ 7 - 3
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.
 	 */

+ 5 - 0
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() { }
 }

+ 0 - 1
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

+ 2 - 1
engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ArmatureModifier.java

@@ -102,11 +102,12 @@ import com.jme3.util.BufferUtils;
 				List<Structure> bonebase = ((Structure) armatureStructure.getFieldValue("bonebase")).evaluateListBase(blenderContext);
 				List<Bone> bonesList = new ArrayList<Bone>();
 				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;