diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/BoneContext.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/BoneContext.java index f21b36f00..0eb50fb65 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/BoneContext.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/BoneContext.java @@ -67,9 +67,9 @@ 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. */ @@ -366,6 +366,30 @@ public class BoneContext { return (flag & flagMask) != 0; } + /** + * @return the root bone context of this bone context + */ + public BoneContext getRoot() { + BoneContext result = this; + while (result.parent != null) { + result = result.parent; + } + return result; + } + + /** + * @return a number of bones from this bone to its root + */ + public int getDistanceFromRoot() { + int result = 0; + BoneContext boneContext = this; + while (boneContext.parent != null) { + boneContext = boneContext.parent; + ++result; + } + return result; + } + @Override public String toString() { return "BoneContext: " + boneName; diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/BoneConstraint.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/BoneConstraint.java index bab8f843d..fdba8af3f 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/BoneConstraint.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/BoneConstraint.java @@ -62,7 +62,7 @@ import com.jme3.scene.plugins.blender.objects.ObjectHelper; } } } - return true; + return constraintDefinition == null ? true : constraintDefinition.isTargetRequired(); } @Override @@ -70,4 +70,19 @@ import com.jme3.scene.plugins.blender.objects.ObjectHelper; super.apply(frame); blenderContext.getBoneContext(ownerOMA).getBone().updateModelTransforms(); } + + @Override + public Long getTargetOMA() { + if(targetOMA != null && subtargetName != null && !subtargetName.trim().isEmpty()) { + Spatial nodeTarget = (Spatial) blenderContext.getLoadedFeature(targetOMA, LoadedDataType.FEATURE); + if(nodeTarget != null) { + if(blenderContext.getMarkerValue(ObjectHelper.ARMATURE_NODE_MARKER, nodeTarget) != null) { + BoneContext boneContext = blenderContext.getBoneByName(targetOMA, subtargetName); + return boneContext != null ? boneContext.getBoneOma() : 0L; + } + return targetOMA; + } + } + return 0L; + } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/Constraint.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/Constraint.java index ec220ebdc..91cfd2f3f 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/Constraint.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/Constraint.java @@ -116,14 +116,31 @@ public abstract class Constraint { */ public abstract boolean validate(); + /** + * @return the OMA of the target or 0 if no target is specified for the constraint + */ + public abstract Long getTargetOMA(); + /** * Applies the constraint to owner (and in some cases can alter other bones of the skeleton). * @param frame * the frame of the animation */ public void apply(int frame) { + if (LOGGER.isLoggable(Level.FINEST)) { + LOGGER.log(Level.FINEST, "Applying constraint: {0} for frame {1}", new Object[] { name, frame }); + } Transform targetTransform = targetOMA != null ? constraintHelper.getTransform(targetOMA, subtargetName, targetSpace) : null; - constraintDefinition.bake(ownerSpace, targetSpace, targetTransform, (float)ipo.calculateValue(frame)); + constraintDefinition.bake(ownerSpace, targetSpace, targetTransform, (float) ipo.calculateValue(frame)); + } + + /** + * @return determines if the definition of the constraint will change the bone in any way; in most cases + * it is possible to tell that even before the constraint baking simulation is started, so we can discard such bones from constraint + * computing to improve the computation speed and lower the computations complexity + */ + public boolean isTrackToBeChanged() { + return constraintDefinition == null ? false : constraintDefinition.isTrackToBeChanged(); } @Override @@ -163,4 +180,9 @@ public abstract class Constraint { } return true; } + + @Override + public String toString() { + return "Constraint(name = " + name + ", def = " + constraintDefinition + ")"; + } } \ No newline at end of file diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SimulationNode.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SimulationNode.java index 5f13ad316..458deee46 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SimulationNode.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SimulationNode.java @@ -1,6 +1,8 @@ package com.jme3.scene.plugins.blender.constraints; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -132,7 +134,7 @@ public class SimulationNode { } } Node node = blenderContext.getControlledNode(skeleton); - Long animatedNodeOMA = ((Number)blenderContext.getMarkerValue(ObjectHelper.OMA_MARKER, node)).longValue(); + Long animatedNodeOMA = ((Number) blenderContext.getMarkerValue(ObjectHelper.OMA_MARKER, node)).longValue(); animations = blenderContext.getAnimations(animatedNodeOMA); } else { animations = blenderContext.getAnimations(featureOMA); @@ -206,7 +208,7 @@ public class SimulationNode { int maxFrame = (int) animationTimeBoundaries[0]; float maxTime = animationTimeBoundaries[1]; - VirtualTrack vTrack = new VirtualTrack(maxFrame, maxTime); + VirtualTrack vTrack = new VirtualTrack(spatial.getName(), maxFrame, maxTime); for (Track track : animation.getTracks()) { for (int frame = 0; frame < maxFrame; ++frame) { spatial.setLocalTranslation(((SpatialTrack) track).getTranslations()[frame]); @@ -252,6 +254,8 @@ public class SimulationNode { if (animations != null) { TempVars vars = TempVars.get(); AnimChannel animChannel = animControl.createChannel(); + + List bonesWithConstraints = this.collectBonesWithConstraints(skeleton); for (Animation animation : animations) { float[] animationTimeBoundaries = this.computeAnimationTimeBoundaries(animation); int maxFrame = (int) animationTimeBoundaries[0]; @@ -271,11 +275,8 @@ public class SimulationNode { } // ... and then apply constraints from the root bone to the last child ... - for (Bone rootBone : skeleton.getRoots()) { - if (skeleton.getBoneIndex(rootBone) > 0) { - // ommit the 0 - indexed root bone as it is the bone added by importer - this.applyConstraints(rootBone, alteredOmas, frame); - } + for (Bone rootBone : bonesWithConstraints) { + this.applyConstraints(rootBone, alteredOmas, frame); } // ... add virtual tracks if neccessary, for bones that were altered but had no tracks before ... @@ -283,7 +284,7 @@ public class SimulationNode { BoneContext boneContext = blenderContext.getBoneContext(boneOMA); int boneIndex = skeleton.getBoneIndex(boneContext.getBone()); if (!tracks.containsKey(boneIndex)) { - tracks.put(boneIndex, new VirtualTrack(maxFrame, maxTime)); + tracks.put(boneIndex, new VirtualTrack(boneContext.getBone().getName(), maxFrame, maxTime)); } } alteredOmas.clear(); @@ -292,12 +293,12 @@ public class SimulationNode { for (Entry trackEntry : tracks.entrySet()) { Bone bone = skeleton.getBone(trackEntry.getKey()); Transform startTransform = boneStartTransforms.get(bone); - + // track contains differences between the frame position and bind positions of bones/spatials Vector3f bonePositionDifference = bone.getLocalPosition().subtract(startTransform.getTranslation()); Quaternion boneRotationDifference = startTransform.getRotation().inverse().mult(bone.getLocalRotation()).normalizeLocal(); Vector3f boneScaleDifference = bone.getLocalScale().divide(startTransform.getScale()); - + trackEntry.getValue().setTransform(frame, new Transform(bonePositionDifference, boneRotationDifference, boneScaleDifference)); } } @@ -349,9 +350,6 @@ public class SimulationNode { alteredOmas.add(boneContext.getBoneOma()); } } - for (Bone child : bone.getChildren()) { - this.applyConstraints(child, alteredOmas, frame); - } } /** @@ -366,6 +364,150 @@ public class SimulationNode { } } + /** + * Collects the bones that will take part in constraint computations. + * The result will not include bones whose constraints will not change them or are invalid. + * The bones are sorted so that the constraint applying is done in the proper order. + * @param skeleton + * the simulated skeleton + * @return a list of bones that will take part in constraints computations + */ + private List collectBonesWithConstraints(Skeleton skeleton) { + Map> bonesWithConstraints = new HashMap>(); + for (int i = 1; i < skeleton.getBoneCount(); ++i) {// ommit the 0 - indexed root bone as it is the bone added by importer + Bone bone = skeleton.getBone(i); + BoneContext boneContext = blenderContext.getBoneContext(bone); + List constraints = this.findConstraints(boneContext.getBoneOma(), blenderContext); + if (constraints != null && constraints.size() > 0) { + bonesWithConstraints.put(boneContext, constraints); + } + } + + // first sort out constraints that are not implemented or invalid or will not affect the bone's tracks + List bonesToRemove = new ArrayList(bonesWithConstraints.size()); + for (Entry> entry : bonesWithConstraints.entrySet()) { + List validConstraints = new ArrayList(entry.getValue().size()); + for (Constraint constraint : entry.getValue()) {// TODO: sprawdzić czy wprowadza jakiekolwiek zmiany + if (constraint.isImplemented() && constraint.validate() && constraint.isTrackToBeChanged()) { + validConstraints.add(constraint); + } + } + if (validConstraints.size() > 0) { + entry.setValue(validConstraints); + } else { + bonesToRemove.add(entry.getKey()); + } + } + for (BoneContext boneContext : bonesToRemove) { + bonesWithConstraints.remove(boneContext); + } + + List bonesConstrainedWithoutTarget = new ArrayList(); + Set remainedOMAS = new HashSet(); + // later move all bones with not dependant constraints to the front + bonesToRemove.clear(); + for (Entry> entry : bonesWithConstraints.entrySet()) { + boolean hasDependantConstraints = false; + for (Constraint constraint : entry.getValue()) { + if (constraint.targetOMA != null) { + hasDependantConstraints = true; + break; + } + } + + if (!hasDependantConstraints) { + bonesConstrainedWithoutTarget.add(entry.getKey()); + bonesToRemove.add(entry.getKey()); + } else { + remainedOMAS.add(entry.getKey().getBoneOma()); + } + } + for (BoneContext boneContext : bonesToRemove) { + bonesWithConstraints.remove(boneContext); + } + + this.sortBonesByChain(bonesConstrainedWithoutTarget); + + // another step is to add those bones whose constraints depend only on bones already added to the result or to those + // that are not included neither in the result nor in the remaining map + // do this as long as bones are being moved to the result and the 'bonesWithConstraints' is not empty + List bonesConstrainedWithTarget = new ArrayList(); + do { + bonesToRemove.clear(); + for (Entry> entry : bonesWithConstraints.entrySet()) { + boolean unconstrainedBone = true; + for (Constraint constraint : entry.getValue()) { + if (remainedOMAS.contains(constraint.getTargetOMA())) { + unconstrainedBone = false; + break; + } + } + if (unconstrainedBone) { + bonesToRemove.add(entry.getKey()); + bonesConstrainedWithTarget.add(entry.getKey()); + } + } + + for (BoneContext boneContext : bonesToRemove) { + bonesWithConstraints.remove(boneContext); + remainedOMAS.remove(boneContext.getBoneOma()); + } + } while (bonesWithConstraints.size() > 0 && bonesToRemove.size() > 0); + this.sortBonesByChain(bonesConstrainedWithoutTarget); + + // prepare the result + List result = new ArrayList(); + for (BoneContext boneContext : bonesConstrainedWithoutTarget) { + result.add(boneContext.getBone()); + } + for (BoneContext boneContext : bonesConstrainedWithTarget) { + result.add(boneContext.getBone()); + } + + // in the end prepare the mapping between bone OMA + if (bonesWithConstraints.size() > 0) { + LOGGER.warning("Some bones have loops in their constraints' definitions. The result might not be properly computed!"); + for (BoneContext boneContext : bonesWithConstraints.keySet()) { + result.add(boneContext.getBone()); + } + } + + return result; + } + + /** + * The method sorts the given bones from root to top. + * If the list contains bones from different branches then those branches will be listed + * one after another - which means that bones will be grouped by branches they belong to. + * @param bones + * a list of bones + */ + private void sortBonesByChain(List bones) { + Map> branches = new HashMap>(); + + for (BoneContext bone : bones) { + BoneContext root = bone.getRoot(); + List list = branches.get(root); + if (list == null) { + list = new ArrayList(); + branches.put(root, list); + } + list.add(bone); + } + + // sort the bones in each branch from root to leaf + bones.clear(); + for (Entry> entry : branches.entrySet()) { + Collections.sort(entry.getValue(), new Comparator() { + @Override + public int compare(BoneContext o1, BoneContext o2) { + return o1.getDistanceFromRoot() - o2.getDistanceFromRoot(); + } + }); + bones.addAll(entry.getValue()); + } + } + /** * Computes the maximum frame and time for the animation. Different tracks * can have different lengths so here the maximum one is being found. @@ -376,7 +518,7 @@ public class SimulationNode { */ private float[] computeAnimationTimeBoundaries(Animation animation) { int maxFrame = Integer.MIN_VALUE; - float maxTime = Float.MIN_VALUE; + float maxTime = -Float.MAX_VALUE; for (Track track : animation.getTracks()) { if (track instanceof BoneTrack) { maxFrame = Math.max(maxFrame, ((BoneTrack) track).getTranslations().length); diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SkeletonConstraint.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SkeletonConstraint.java index 98d5562b1..5560bbd43 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SkeletonConstraint.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SkeletonConstraint.java @@ -32,4 +32,10 @@ import com.jme3.scene.plugins.blender.file.Structure; public void apply(int frame) { LOGGER.warning("Applying constraints to skeleton is not supported."); } + + @Override + public Long getTargetOMA() { + LOGGER.warning("Constraints for skeleton are not supported."); + return null; + } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SpatialConstraint.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SpatialConstraint.java index 5284a800e..91eb5c5c7 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SpatialConstraint.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SpatialConstraint.java @@ -22,6 +22,11 @@ import com.jme3.scene.plugins.blender.file.Structure; if (targetOMA != null) { return blenderContext.getLoadedFeature(targetOMA, LoadedDataType.FEATURE) != null; } - return true; + return constraintDefinition == null ? true : constraintDefinition.isTargetRequired(); + } + + @Override + public Long getTargetOMA() { + return targetOMA; } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/VirtualTrack.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/VirtualTrack.java index 944a3fab8..f18222795 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/VirtualTrack.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/VirtualTrack.java @@ -16,6 +16,8 @@ import com.jme3.math.Vector3f; * @author Marcin Roguski (Kaelthas) */ /* package */class VirtualTrack { + /** The name of the track (for debugging purposes). */ + private String name; /** The last frame for the track. */ public int maxFrame; /** The max time for the track. */ @@ -35,7 +37,8 @@ import com.jme3.math.Vector3f; * @param maxTime * the max time for the track */ - public VirtualTrack(int maxFrame, float maxTime) { + public VirtualTrack(String name, int maxFrame, float maxTime) { + this.name = name; this.maxFrame = maxFrame; this.maxTime = maxTime; } @@ -101,7 +104,7 @@ import com.jme3.math.Vector3f; */ private float[] createTimes() { float[] times = new float[maxFrame]; - float dT = maxTime / (float) maxFrame; + float dT = maxTime / maxFrame; float t = 0; for (int i = 0; i < maxFrame; ++i) { times[i] = t; @@ -143,4 +146,20 @@ import com.jme3.math.Vector3f; list.add(element); } } + + @Override + public String toString() { + StringBuilder result = new StringBuilder(2048); + result.append("TRACK: ").append(name).append('\n'); + if (translations != null && translations.size() > 0) { + result.append("TRANSLATIONS: ").append(translations.toString()).append('\n'); + } + if (rotations != null && rotations.size() > 0) { + result.append("ROTATIONS: ").append(rotations.toString()).append('\n'); + } + if (scales != null && scales.size() > 0) { + result.append("SCALES: ").append(scales.toString()).append('\n'); + } + return result.toString(); + } } \ No newline at end of file diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinition.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinition.java index 8b3f9fd15..346554052 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinition.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinition.java @@ -28,6 +28,8 @@ public abstract class ConstraintDefinition { protected Long ownerOMA; /** Stores the OMA addresses of all features whose transform had been altered beside the constraint owner. */ protected Set alteredOmas; + /** The variable that determines if the constraint will alter the track in any way. */ + protected boolean trackToBeChanged = true; /** * Loads a constraint definition based on the constraint definition @@ -52,6 +54,20 @@ public abstract class ConstraintDefinition { this.ownerOMA = ownerOMA; } + /** + * @return determines if the definition of the constraint will change the bone in any way; in most cases + * it is possible to tell that even before the constraint baking simulation is started, so we can discard such bones from constraint + * computing to improve the computation speed and lower the computations complexity + */ + public boolean isTrackToBeChanged() { + return trackToBeChanged; + } + + /** + * @return determines if this constraint definition requires a defined target or not + */ + public abstract boolean isTargetRequired(); + /** * This method is here because we have no guarantee that the owner is loaded * when constraint is being created. So use it to get the owner when it is @@ -132,4 +148,9 @@ public abstract class ConstraintDefinition { * the influence of the constraint (from range <0; 1>) */ public abstract void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence); + + @Override + public String toString() { + return this.getConstraintTypeName(); + } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionDistLimit.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionDistLimit.java index cc4852cca..aaa7e2d97 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionDistLimit.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionDistLimit.java @@ -26,18 +26,17 @@ import com.jme3.scene.plugins.blender.file.Structure; mode = ((Number) constraintData.getFieldValue("mode")).intValue(); dist = ((Number) constraintData.getFieldValue("dist")).floatValue(); } - + @Override public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) { - if (this.getOwner() instanceof Bone && ((Bone) this.getOwner()).getParent() != null && - blenderContext.getBoneContext(ownerOMA).is(BoneContext.CONNECTED_TO_PARENT)) { + if (this.getOwner() instanceof Bone && ((Bone) this.getOwner()).getParent() != null && blenderContext.getBoneContext(ownerOMA).is(BoneContext.CONNECTED_TO_PARENT)) { // distance limit does not work on bones who are connected to their parent return; } - if(influence == 0 || targetTransform == null) { - return ;// no need to do anything + if (influence == 0 || targetTransform == null) { + return;// no need to do anything } - + Transform ownerTransform = this.getOwnerTransform(ownerSpace); Vector3f v = ownerTransform.getTranslation().subtract(targetTransform.getTranslation()); @@ -73,6 +72,11 @@ import com.jme3.scene.plugins.blender.file.Structure; this.applyOwnerTransform(ownerTransform, ownerSpace); } + @Override + public boolean isTargetRequired() { + return true; + } + @Override public String getConstraintTypeName() { return "Limit distance"; diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionIK.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionIK.java index 615291999..dc63ae42b 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionIK.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionIK.java @@ -29,8 +29,6 @@ public class ConstraintDefinitionIK extends ConstraintDefinition { private int bonesAffected; /** The total length of the bone chain. Useful for optimisation of computations speed in some cases. */ private float chainLength; - /** Tells if there is anything to compute at all. */ - private boolean needToCompute = true; /** Indicates if the tail of the bone should be used or not. */ private boolean useTail; /** The amount of iterations of the algorithm. */ @@ -43,23 +41,23 @@ public class ConstraintDefinitionIK extends ConstraintDefinition { useTail = (flag & FLAG_USE_TAIL) != 0; if ((flag & FLAG_POSITION) == 0) { - needToCompute = false; + trackToBeChanged = false; } - if (needToCompute) { + if (trackToBeChanged) { alteredOmas = new HashSet(); } } @Override public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) { - if (influence == 0 || !needToCompute || targetTransform == null) { + if (influence == 0 || !trackToBeChanged || targetTransform == null) { return;// no need to do anything } Quaternion q = new Quaternion(); Vector3f t = targetTransform.getTranslation(); List bones = this.loadBones(); - if(bones.size() == 0) { + if (bones.size() == 0) { return;// no need to do anything } float distanceFromTarget = Float.MAX_VALUE; @@ -186,4 +184,20 @@ public class ConstraintDefinitionIK extends ConstraintDefinition { } return bones; } + + @Override + public boolean isTrackToBeChanged() { + if (trackToBeChanged) { + // need to check the bone structure too (when constructor was called not all of the bones might have been loaded yet) + // that is why it is also checked here + List bones = this.loadBones(); + trackToBeChanged = bones.size() > 0; + } + return trackToBeChanged; + } + + @Override + public boolean isTargetRequired() { + return true; + } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionLocLike.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionLocLike.java index 0e2c4d63d..bf6fb39b1 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionLocLike.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionLocLike.java @@ -34,27 +34,30 @@ import com.jme3.scene.plugins.blender.file.Structure; int invZ = flag & LOCLIKE_Z_INVERT; // clear the other flags to swap them flag &= LOCLIKE_X | LOCLIKE_X_INVERT | LOCLIKE_OFFSET; - + flag |= y << 1; flag |= invY << 1; flag |= z >> 1; flag |= invZ >> 1; + + trackToBeChanged = (flag & LOCLIKE_X) != 0 || (flag & LOCLIKE_Y) != 0 || (flag & LOCLIKE_Z) != 0; } } - + + @Override + public boolean isTrackToBeChanged() { + // location copy does not work on bones who are connected to their parent + return trackToBeChanged && !(this.getOwner() instanceof Bone && ((Bone) this.getOwner()).getParent() != null && blenderContext.getBoneContext(ownerOMA).is(BoneContext.CONNECTED_TO_PARENT)); + } + @Override public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) { - if (this.getOwner() instanceof Bone && ((Bone) this.getOwner()).getParent() != null && - blenderContext.getBoneContext(ownerOMA).is(BoneContext.CONNECTED_TO_PARENT)) { - // location copy does not work on bones who are connected to their parent + if (influence == 0 || targetTransform == null || !this.isTrackToBeChanged()) { return; } - if(influence == 0 || targetTransform == null) { - return ;// no need to do anything - } - + Transform ownerTransform = this.getOwnerTransform(ownerSpace); - + Vector3f ownerLocation = ownerTransform.getTranslation(); Vector3f targetLocation = targetTransform.getTranslation(); @@ -88,7 +91,7 @@ import com.jme3.scene.plugins.blender.file.Structure; startLocation.subtractLocal(ownerLocation).normalizeLocal().mult(influence); ownerLocation.addLocal(startLocation); } - + this.applyOwnerTransform(ownerTransform, ownerSpace); } @@ -96,4 +99,9 @@ import com.jme3.scene.plugins.blender.file.Structure; public String getConstraintTypeName() { return "Copy location"; } + + @Override + public boolean isTargetRequired() { + return true; + } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionLocLimit.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionLocLimit.java index 615fb104b..62e92e73b 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionLocLimit.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionLocLimit.java @@ -52,18 +52,24 @@ import com.jme3.scene.plugins.blender.file.Structure; limits[2][0] = ((Number) constraintData.getFieldValue("zmin")).floatValue(); limits[2][1] = ((Number) constraintData.getFieldValue("zmax")).floatValue(); } + + trackToBeChanged = (flag & (LIMIT_XMIN | LIMIT_XMAX | LIMIT_YMIN | LIMIT_YMAX | LIMIT_ZMIN | LIMIT_ZMAX)) != 0; + } + + @Override + public boolean isTrackToBeChanged() { + // location limit does not work on bones who are connected to their parent + return trackToBeChanged && !(this.getOwner() instanceof Bone && ((Bone) this.getOwner()).getParent() != null && blenderContext.getBoneContext(ownerOMA).is(BoneContext.CONNECTED_TO_PARENT)); } - + @Override public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) { - if (this.getOwner() instanceof Bone && ((Bone) this.getOwner()).getParent() != null && - blenderContext.getBoneContext(ownerOMA).is(BoneContext.CONNECTED_TO_PARENT)) { - // location limit does not work on bones who are connected to their parent - return; + if (influence == 0 || !this.isTrackToBeChanged()) { + return;// no need to do anything } - + Transform ownerTransform = this.getOwnerTransform(ownerSpace); - + Vector3f translation = ownerTransform.getTranslation(); if ((flag & LIMIT_XMIN) != 0 && translation.x < limits[0][0]) { @@ -84,7 +90,7 @@ import com.jme3.scene.plugins.blender.file.Structure; if ((flag & LIMIT_ZMAX) != 0 && translation.z > limits[2][1]) { translation.z -= (translation.z - limits[2][1]) * influence; } - + this.applyOwnerTransform(ownerTransform, ownerSpace); } @@ -92,4 +98,9 @@ import com.jme3.scene.plugins.blender.file.Structure; public String getConstraintTypeName() { return "Limit location"; } + + @Override + public boolean isTargetRequired() { + return false; + } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionMaintainVolume.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionMaintainVolume.java index fce99d40f..c8756129e 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionMaintainVolume.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionMaintainVolume.java @@ -6,6 +6,11 @@ import com.jme3.scene.plugins.blender.BlenderContext; import com.jme3.scene.plugins.blender.constraints.ConstraintHelper.Space; import com.jme3.scene.plugins.blender.file.Structure; +/** + * This class represents 'Maintain volume' constraint type in blender. + * + * @author Marcin Roguski (Kaelthas) + */ public class ConstraintDefinitionMaintainVolume extends ConstraintDefinition { private static final int FLAG_MASK_X = 0; private static final int FLAG_MASK_Y = 1; @@ -16,11 +21,12 @@ public class ConstraintDefinitionMaintainVolume extends ConstraintDefinition { public ConstraintDefinitionMaintainVolume(Structure constraintData, Long ownerOMA, BlenderContext blenderContext) { super(constraintData, ownerOMA, blenderContext); volume = (float) Math.sqrt(((Number) constraintData.getFieldValue("volume")).floatValue()); + trackToBeChanged = volume != 1 && (flag & (FLAG_MASK_X | FLAG_MASK_Y | FLAG_MASK_Z)) != 0; } @Override public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) { - if (volume != 1 && influence > 0) { + if (trackToBeChanged && influence > 0) { // the maintain volume constraint is applied directly to object's scale, so no need to do it again // but in case of bones we need to make computations if (this.getOwner() instanceof Bone) { @@ -47,4 +53,9 @@ public class ConstraintDefinitionMaintainVolume extends ConstraintDefinition { public String getConstraintTypeName() { return "Maintain volume"; } + + @Override + public boolean isTargetRequired() { + return false; + } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionNull.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionNull.java index 6744a7884..032909c65 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionNull.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionNull.java @@ -14,6 +14,7 @@ import com.jme3.scene.plugins.blender.file.Structure; public ConstraintDefinitionNull(Structure constraintData, Long ownerOMA, BlenderContext blenderContext) { super(constraintData, ownerOMA, blenderContext); + trackToBeChanged = false; } @Override @@ -25,4 +26,9 @@ import com.jme3.scene.plugins.blender.file.Structure; public String getConstraintTypeName() { return "Null"; } + + @Override + public boolean isTargetRequired() { + return false; + } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionRotLike.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionRotLike.java index 3a363cb4d..280e4e77e 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionRotLike.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionRotLike.java @@ -25,15 +25,16 @@ import com.jme3.scene.plugins.blender.file.Structure; public ConstraintDefinitionRotLike(Structure constraintData, Long ownerOMA, BlenderContext blenderContext) { super(constraintData, ownerOMA, blenderContext); + trackToBeChanged = (flag & (ROTLIKE_X | ROTLIKE_Y | ROTLIKE_Z)) != 0; } @Override public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) { - if(influence == 0 || targetTransform == null) { - return ;// no need to do anything + if (influence == 0 || targetTransform == null || !trackToBeChanged) { + return;// no need to do anything } Transform ownerTransform = this.getOwnerTransform(ownerSpace); - + Quaternion ownerRotation = ownerTransform.getRotation(); ownerAngles = ownerRotation.toAngles(ownerAngles); targetAngles = targetTransform.getRotation().toAngles(targetAngles); @@ -70,7 +71,7 @@ import com.jme3.scene.plugins.blender.file.Structure; // ownerLocation.addLocal(startLocation); // TODO } - + this.applyOwnerTransform(ownerTransform, ownerSpace); } @@ -78,4 +79,9 @@ import com.jme3.scene.plugins.blender.file.Structure; public String getConstraintTypeName() { return "Copy rotation"; } + + @Override + public boolean isTargetRequired() { + return true; + } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionRotLimit.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionRotLimit.java index 55a8f8147..3d569447f 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionRotLimit.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionRotLimit.java @@ -65,12 +65,17 @@ import com.jme3.scene.plugins.blender.file.Structure; * if(limits[i][0] > limits[i][1]) { float temp = limits[i][0]; * limits[i][0] = limits[i][1]; limits[i][1] = temp; } } */ + + trackToBeChanged = (flag & (LIMIT_XROT | LIMIT_YROT | LIMIT_ZROT)) != 0; } - + @Override public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) { + if (influence == 0 || !trackToBeChanged) { + return; + } Transform ownerTransform = this.getOwnerTransform(ownerSpace); - + ownerTransform.getRotation().toAngles(angles); // make sure that the rotations are always in range [0, 2PI) // TODO: same comment as in constructor @@ -108,7 +113,7 @@ import com.jme3.scene.plugins.blender.file.Structure; angles[2] -= difference; } ownerTransform.getRotation().fromAngles(angles); - + this.applyOwnerTransform(ownerTransform, ownerSpace); } @@ -116,4 +121,9 @@ import com.jme3.scene.plugins.blender.file.Structure; public String getConstraintTypeName() { return "Limit rotation"; } + + @Override + public boolean isTargetRequired() { + return false; + } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionSizeLike.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionSizeLike.java index 046801526..b05048af6 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionSizeLike.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionSizeLike.java @@ -27,16 +27,18 @@ import com.jme3.scene.plugins.blender.file.Structure; // them flag |= y << 1; flag |= z >> 1; + + trackToBeChanged = (flag & (SIZELIKE_X | SIZELIKE_Y | SIZELIKE_Z)) != 0; } } - + @Override public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) { - if(influence == 0 || targetTransform == null) { + if (influence == 0 || targetTransform == null || !trackToBeChanged) { return;// no need to do anything } Transform ownerTransform = this.getOwnerTransform(ownerSpace); - + Vector3f ownerScale = ownerTransform.getScale(); Vector3f targetScale = targetTransform.getScale(); @@ -56,7 +58,7 @@ import com.jme3.scene.plugins.blender.file.Structure; ownerScale.z = targetScale.z * influence + (1.0f - influence) * ownerScale.z; } ownerScale.addLocal(offset); - + this.applyOwnerTransform(ownerTransform, ownerSpace); } @@ -64,4 +66,9 @@ import com.jme3.scene.plugins.blender.file.Structure; public String getConstraintTypeName() { return "Copy scale"; } + + @Override + public boolean isTargetRequired() { + return true; + } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionSizeLimit.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionSizeLimit.java index 564f77e70..6c133bf18 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionSizeLimit.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionSizeLimit.java @@ -50,12 +50,17 @@ import com.jme3.scene.plugins.blender.file.Structure; limits[2][0] = ((Number) constraintData.getFieldValue("zmin")).floatValue(); limits[2][1] = ((Number) constraintData.getFieldValue("zmax")).floatValue(); } + + trackToBeChanged = (flag & (LIMIT_XMIN | LIMIT_XMAX | LIMIT_YMIN | LIMIT_YMAX | LIMIT_ZMIN | LIMIT_ZMAX)) != 0; } - + @Override public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) { + if (influence == 0 || !trackToBeChanged) { + return; + } Transform ownerTransform = this.getOwnerTransform(ownerSpace); - + Vector3f scale = ownerTransform.getScale(); if ((flag & LIMIT_XMIN) != 0 && scale.x < limits[0][0]) { scale.x -= (scale.x - limits[0][0]) * influence; @@ -75,7 +80,7 @@ import com.jme3.scene.plugins.blender.file.Structure; if ((flag & LIMIT_ZMAX) != 0 && scale.z > limits[2][1]) { scale.z -= (scale.z - limits[2][1]) * influence; } - + this.applyOwnerTransform(ownerTransform, ownerSpace); } @@ -83,4 +88,9 @@ import com.jme3.scene.plugins.blender.file.Structure; public String getConstraintTypeName() { return "Limit scale"; } + + @Override + public boolean isTargetRequired() { + return false; + } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionTransLike.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionTransLike.java index 5b171b97f..b38857279 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionTransLike.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionTransLike.java @@ -35,8 +35,8 @@ public class ConstraintDefinitionTransLike extends ConstraintDefinition { @Override public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) { - if(influence == 0 || targetTransform == null) { - return ;// no need to do anything + if (influence == 0 || targetTransform == null) { + return;// no need to do anything } Object target = this.getTarget();// Bone or Node Object owner = this.getOwner();// Bone or Node @@ -73,4 +73,9 @@ public class ConstraintDefinitionTransLike extends ConstraintDefinition { public String getConstraintTypeName() { return "Copy transforms"; } + + @Override + public boolean isTargetRequired() { + return true; + } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/UnsupportedConstraintDefinition.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/UnsupportedConstraintDefinition.java index 3002cfb88..e3fa82e9a 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/UnsupportedConstraintDefinition.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/UnsupportedConstraintDefinition.java @@ -16,6 +16,7 @@ import com.jme3.scene.plugins.blender.constraints.ConstraintHelper.Space; public UnsupportedConstraintDefinition(String typeName) { super(null, null, null); this.typeName = typeName; + trackToBeChanged = false; } @Override @@ -31,4 +32,9 @@ import com.jme3.scene.plugins.blender.constraints.ConstraintHelper.Space; public String getConstraintTypeName() { return typeName; } + + @Override + public boolean isTargetRequired() { + return false; + } }