Bugfix: sorting constraint computation in the proper order which should
decrease the amount of unwanted artifacts appearing in some models during animations.
This commit is contained in:
parent
858fd433ca
commit
65c3ff668c
jme3-blender/src/main/java/com/jme3/scene/plugins/blender
animations
constraints
BoneConstraint.javaConstraint.javaSimulationNode.javaSkeletonConstraint.javaSpatialConstraint.javaVirtualTrack.java
definitions
ConstraintDefinition.javaConstraintDefinitionDistLimit.javaConstraintDefinitionIK.javaConstraintDefinitionLocLike.javaConstraintDefinitionLocLimit.javaConstraintDefinitionMaintainVolume.javaConstraintDefinitionNull.javaConstraintDefinitionRotLike.javaConstraintDefinitionRotLimit.javaConstraintDefinitionSizeLike.javaConstraintDefinitionSizeLimit.javaConstraintDefinitionTransLike.javaUnsupportedConstraintDefinition.java
@ -67,9 +67,9 @@ public class BoneContext {
|
|||||||
private float length;
|
private float length;
|
||||||
/** The bone's deform envelope. */
|
/** The bone's deform envelope. */
|
||||||
private BoneEnvelope boneEnvelope;
|
private BoneEnvelope boneEnvelope;
|
||||||
|
|
||||||
// The below data is used only for IK constraint computations.
|
// The below data is used only for IK constraint computations.
|
||||||
|
|
||||||
/** The bone's stretch value. */
|
/** The bone's stretch value. */
|
||||||
private float ikStretch;
|
private float ikStretch;
|
||||||
/** Bone's rotation minimum values. */
|
/** Bone's rotation minimum values. */
|
||||||
@ -366,6 +366,30 @@ public class BoneContext {
|
|||||||
return (flag & flagMask) != 0;
|
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
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "BoneContext: " + boneName;
|
return "BoneContext: " + boneName;
|
||||||
|
@ -62,7 +62,7 @@ import com.jme3.scene.plugins.blender.objects.ObjectHelper;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return constraintDefinition == null ? true : constraintDefinition.isTargetRequired();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -70,4 +70,19 @@ import com.jme3.scene.plugins.blender.objects.ObjectHelper;
|
|||||||
super.apply(frame);
|
super.apply(frame);
|
||||||
blenderContext.getBoneContext(ownerOMA).getBone().updateModelTransforms();
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,14 +116,31 @@ public abstract class Constraint {
|
|||||||
*/
|
*/
|
||||||
public abstract boolean validate();
|
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).
|
* Applies the constraint to owner (and in some cases can alter other bones of the skeleton).
|
||||||
* @param frame
|
* @param frame
|
||||||
* the frame of the animation
|
* the frame of the animation
|
||||||
*/
|
*/
|
||||||
public void apply(int frame) {
|
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;
|
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
|
@Override
|
||||||
@ -163,4 +180,9 @@ public abstract class Constraint {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Constraint(name = " + name + ", def = " + constraintDefinition + ")";
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,6 +1,8 @@
|
|||||||
package com.jme3.scene.plugins.blender.constraints;
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -132,7 +134,7 @@ public class SimulationNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Node node = blenderContext.getControlledNode(skeleton);
|
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);
|
animations = blenderContext.getAnimations(animatedNodeOMA);
|
||||||
} else {
|
} else {
|
||||||
animations = blenderContext.getAnimations(featureOMA);
|
animations = blenderContext.getAnimations(featureOMA);
|
||||||
@ -206,7 +208,7 @@ public class SimulationNode {
|
|||||||
int maxFrame = (int) animationTimeBoundaries[0];
|
int maxFrame = (int) animationTimeBoundaries[0];
|
||||||
float maxTime = animationTimeBoundaries[1];
|
float maxTime = animationTimeBoundaries[1];
|
||||||
|
|
||||||
VirtualTrack vTrack = new VirtualTrack(maxFrame, maxTime);
|
VirtualTrack vTrack = new VirtualTrack(spatial.getName(), maxFrame, maxTime);
|
||||||
for (Track track : animation.getTracks()) {
|
for (Track track : animation.getTracks()) {
|
||||||
for (int frame = 0; frame < maxFrame; ++frame) {
|
for (int frame = 0; frame < maxFrame; ++frame) {
|
||||||
spatial.setLocalTranslation(((SpatialTrack) track).getTranslations()[frame]);
|
spatial.setLocalTranslation(((SpatialTrack) track).getTranslations()[frame]);
|
||||||
@ -252,6 +254,8 @@ public class SimulationNode {
|
|||||||
if (animations != null) {
|
if (animations != null) {
|
||||||
TempVars vars = TempVars.get();
|
TempVars vars = TempVars.get();
|
||||||
AnimChannel animChannel = animControl.createChannel();
|
AnimChannel animChannel = animControl.createChannel();
|
||||||
|
|
||||||
|
List<Bone> bonesWithConstraints = this.collectBonesWithConstraints(skeleton);
|
||||||
for (Animation animation : animations) {
|
for (Animation animation : animations) {
|
||||||
float[] animationTimeBoundaries = this.computeAnimationTimeBoundaries(animation);
|
float[] animationTimeBoundaries = this.computeAnimationTimeBoundaries(animation);
|
||||||
int maxFrame = (int) animationTimeBoundaries[0];
|
int maxFrame = (int) animationTimeBoundaries[0];
|
||||||
@ -271,11 +275,8 @@ public class SimulationNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ... and then apply constraints from the root bone to the last child ...
|
// ... and then apply constraints from the root bone to the last child ...
|
||||||
for (Bone rootBone : skeleton.getRoots()) {
|
for (Bone rootBone : bonesWithConstraints) {
|
||||||
if (skeleton.getBoneIndex(rootBone) > 0) {
|
this.applyConstraints(rootBone, alteredOmas, frame);
|
||||||
// ommit the 0 - indexed root bone as it is the bone added by importer
|
|
||||||
this.applyConstraints(rootBone, alteredOmas, frame);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ... add virtual tracks if neccessary, for bones that were altered but had no tracks before ...
|
// ... 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);
|
BoneContext boneContext = blenderContext.getBoneContext(boneOMA);
|
||||||
int boneIndex = skeleton.getBoneIndex(boneContext.getBone());
|
int boneIndex = skeleton.getBoneIndex(boneContext.getBone());
|
||||||
if (!tracks.containsKey(boneIndex)) {
|
if (!tracks.containsKey(boneIndex)) {
|
||||||
tracks.put(boneIndex, new VirtualTrack(maxFrame, maxTime));
|
tracks.put(boneIndex, new VirtualTrack(boneContext.getBone().getName(), maxFrame, maxTime));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
alteredOmas.clear();
|
alteredOmas.clear();
|
||||||
@ -292,12 +293,12 @@ public class SimulationNode {
|
|||||||
for (Entry<Integer, VirtualTrack> trackEntry : tracks.entrySet()) {
|
for (Entry<Integer, VirtualTrack> trackEntry : tracks.entrySet()) {
|
||||||
Bone bone = skeleton.getBone(trackEntry.getKey());
|
Bone bone = skeleton.getBone(trackEntry.getKey());
|
||||||
Transform startTransform = boneStartTransforms.get(bone);
|
Transform startTransform = boneStartTransforms.get(bone);
|
||||||
|
|
||||||
// track contains differences between the frame position and bind positions of bones/spatials
|
// track contains differences between the frame position and bind positions of bones/spatials
|
||||||
Vector3f bonePositionDifference = bone.getLocalPosition().subtract(startTransform.getTranslation());
|
Vector3f bonePositionDifference = bone.getLocalPosition().subtract(startTransform.getTranslation());
|
||||||
Quaternion boneRotationDifference = startTransform.getRotation().inverse().mult(bone.getLocalRotation()).normalizeLocal();
|
Quaternion boneRotationDifference = startTransform.getRotation().inverse().mult(bone.getLocalRotation()).normalizeLocal();
|
||||||
Vector3f boneScaleDifference = bone.getLocalScale().divide(startTransform.getScale());
|
Vector3f boneScaleDifference = bone.getLocalScale().divide(startTransform.getScale());
|
||||||
|
|
||||||
trackEntry.getValue().setTransform(frame, new Transform(bonePositionDifference, boneRotationDifference, boneScaleDifference));
|
trackEntry.getValue().setTransform(frame, new Transform(bonePositionDifference, boneRotationDifference, boneScaleDifference));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -349,9 +350,6 @@ public class SimulationNode {
|
|||||||
alteredOmas.add(boneContext.getBoneOma());
|
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<Bone> collectBonesWithConstraints(Skeleton skeleton) {
|
||||||
|
Map<BoneContext, List<Constraint>> bonesWithConstraints = new HashMap<BoneContext, List<Constraint>>();
|
||||||
|
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<Constraint> 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<BoneContext> bonesToRemove = new ArrayList<BoneContext>(bonesWithConstraints.size());
|
||||||
|
for (Entry<BoneContext, List<Constraint>> entry : bonesWithConstraints.entrySet()) {
|
||||||
|
List<Constraint> validConstraints = new ArrayList<Constraint>(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<BoneContext> bonesConstrainedWithoutTarget = new ArrayList<BoneContext>();
|
||||||
|
Set<Long> remainedOMAS = new HashSet<Long>();
|
||||||
|
// later move all bones with not dependant constraints to the front
|
||||||
|
bonesToRemove.clear();
|
||||||
|
for (Entry<BoneContext, List<Constraint>> 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<BoneContext> bonesConstrainedWithTarget = new ArrayList<BoneContext>();
|
||||||
|
do {
|
||||||
|
bonesToRemove.clear();
|
||||||
|
for (Entry<BoneContext, List<Constraint>> 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<Bone> result = new ArrayList<Bone>();
|
||||||
|
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<BoneContext> bones) {
|
||||||
|
Map<BoneContext, List<BoneContext>> branches = new HashMap<BoneContext, List<BoneContext>>();
|
||||||
|
|
||||||
|
for (BoneContext bone : bones) {
|
||||||
|
BoneContext root = bone.getRoot();
|
||||||
|
List<BoneContext> list = branches.get(root);
|
||||||
|
if (list == null) {
|
||||||
|
list = new ArrayList<BoneContext>();
|
||||||
|
branches.put(root, list);
|
||||||
|
}
|
||||||
|
list.add(bone);
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort the bones in each branch from root to leaf
|
||||||
|
bones.clear();
|
||||||
|
for (Entry<BoneContext, List<BoneContext>> entry : branches.entrySet()) {
|
||||||
|
Collections.sort(entry.getValue(), new Comparator<BoneContext>() {
|
||||||
|
@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
|
* Computes the maximum frame and time for the animation. Different tracks
|
||||||
* can have different lengths so here the maximum one is being found.
|
* can have different lengths so here the maximum one is being found.
|
||||||
@ -376,7 +518,7 @@ public class SimulationNode {
|
|||||||
*/
|
*/
|
||||||
private float[] computeAnimationTimeBoundaries(Animation animation) {
|
private float[] computeAnimationTimeBoundaries(Animation animation) {
|
||||||
int maxFrame = Integer.MIN_VALUE;
|
int maxFrame = Integer.MIN_VALUE;
|
||||||
float maxTime = Float.MIN_VALUE;
|
float maxTime = -Float.MAX_VALUE;
|
||||||
for (Track track : animation.getTracks()) {
|
for (Track track : animation.getTracks()) {
|
||||||
if (track instanceof BoneTrack) {
|
if (track instanceof BoneTrack) {
|
||||||
maxFrame = Math.max(maxFrame, ((BoneTrack) track).getTranslations().length);
|
maxFrame = Math.max(maxFrame, ((BoneTrack) track).getTranslations().length);
|
||||||
|
@ -32,4 +32,10 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
public void apply(int frame) {
|
public void apply(int frame) {
|
||||||
LOGGER.warning("Applying constraints to skeleton is not supported.");
|
LOGGER.warning("Applying constraints to skeleton is not supported.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getTargetOMA() {
|
||||||
|
LOGGER.warning("Constraints for skeleton are not supported.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,11 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
if (targetOMA != null) {
|
if (targetOMA != null) {
|
||||||
return blenderContext.getLoadedFeature(targetOMA, LoadedDataType.FEATURE) != null;
|
return blenderContext.getLoadedFeature(targetOMA, LoadedDataType.FEATURE) != null;
|
||||||
}
|
}
|
||||||
return true;
|
return constraintDefinition == null ? true : constraintDefinition.isTargetRequired();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getTargetOMA() {
|
||||||
|
return targetOMA;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,8 @@ import com.jme3.math.Vector3f;
|
|||||||
* @author Marcin Roguski (Kaelthas)
|
* @author Marcin Roguski (Kaelthas)
|
||||||
*/
|
*/
|
||||||
/* package */class VirtualTrack {
|
/* package */class VirtualTrack {
|
||||||
|
/** The name of the track (for debugging purposes). */
|
||||||
|
private String name;
|
||||||
/** The last frame for the track. */
|
/** The last frame for the track. */
|
||||||
public int maxFrame;
|
public int maxFrame;
|
||||||
/** The max time for the track. */
|
/** The max time for the track. */
|
||||||
@ -35,7 +37,8 @@ import com.jme3.math.Vector3f;
|
|||||||
* @param maxTime
|
* @param maxTime
|
||||||
* the max time for the track
|
* 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.maxFrame = maxFrame;
|
||||||
this.maxTime = maxTime;
|
this.maxTime = maxTime;
|
||||||
}
|
}
|
||||||
@ -101,7 +104,7 @@ import com.jme3.math.Vector3f;
|
|||||||
*/
|
*/
|
||||||
private float[] createTimes() {
|
private float[] createTimes() {
|
||||||
float[] times = new float[maxFrame];
|
float[] times = new float[maxFrame];
|
||||||
float dT = maxTime / (float) maxFrame;
|
float dT = maxTime / maxFrame;
|
||||||
float t = 0;
|
float t = 0;
|
||||||
for (int i = 0; i < maxFrame; ++i) {
|
for (int i = 0; i < maxFrame; ++i) {
|
||||||
times[i] = t;
|
times[i] = t;
|
||||||
@ -143,4 +146,20 @@ import com.jme3.math.Vector3f;
|
|||||||
list.add(element);
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
@ -28,6 +28,8 @@ public abstract class ConstraintDefinition {
|
|||||||
protected Long ownerOMA;
|
protected Long ownerOMA;
|
||||||
/** Stores the OMA addresses of all features whose transform had been altered beside the constraint owner. */
|
/** Stores the OMA addresses of all features whose transform had been altered beside the constraint owner. */
|
||||||
protected Set<Long> alteredOmas;
|
protected Set<Long> 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
|
* Loads a constraint definition based on the constraint definition
|
||||||
@ -52,6 +54,20 @@ public abstract class ConstraintDefinition {
|
|||||||
this.ownerOMA = ownerOMA;
|
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
|
* 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
|
* 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>)
|
* the influence of the constraint (from range <0; 1>)
|
||||||
*/
|
*/
|
||||||
public abstract void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence);
|
public abstract void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return this.getConstraintTypeName();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,18 +26,17 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
mode = ((Number) constraintData.getFieldValue("mode")).intValue();
|
mode = ((Number) constraintData.getFieldValue("mode")).intValue();
|
||||||
dist = ((Number) constraintData.getFieldValue("dist")).floatValue();
|
dist = ((Number) constraintData.getFieldValue("dist")).floatValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) {
|
public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) {
|
||||||
if (this.getOwner() instanceof Bone && ((Bone) this.getOwner()).getParent() != null &&
|
if (this.getOwner() instanceof Bone && ((Bone) this.getOwner()).getParent() != null && blenderContext.getBoneContext(ownerOMA).is(BoneContext.CONNECTED_TO_PARENT)) {
|
||||||
blenderContext.getBoneContext(ownerOMA).is(BoneContext.CONNECTED_TO_PARENT)) {
|
|
||||||
// distance limit does not work on bones who are connected to their parent
|
// distance limit does not work on bones who are connected to their parent
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(influence == 0 || targetTransform == null) {
|
if (influence == 0 || targetTransform == null) {
|
||||||
return ;// no need to do anything
|
return;// no need to do anything
|
||||||
}
|
}
|
||||||
|
|
||||||
Transform ownerTransform = this.getOwnerTransform(ownerSpace);
|
Transform ownerTransform = this.getOwnerTransform(ownerSpace);
|
||||||
|
|
||||||
Vector3f v = ownerTransform.getTranslation().subtract(targetTransform.getTranslation());
|
Vector3f v = ownerTransform.getTranslation().subtract(targetTransform.getTranslation());
|
||||||
@ -73,6 +72,11 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
this.applyOwnerTransform(ownerTransform, ownerSpace);
|
this.applyOwnerTransform(ownerTransform, ownerSpace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTargetRequired() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getConstraintTypeName() {
|
public String getConstraintTypeName() {
|
||||||
return "Limit distance";
|
return "Limit distance";
|
||||||
|
@ -29,8 +29,6 @@ public class ConstraintDefinitionIK extends ConstraintDefinition {
|
|||||||
private int bonesAffected;
|
private int bonesAffected;
|
||||||
/** The total length of the bone chain. Useful for optimisation of computations speed in some cases. */
|
/** The total length of the bone chain. Useful for optimisation of computations speed in some cases. */
|
||||||
private float chainLength;
|
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. */
|
/** Indicates if the tail of the bone should be used or not. */
|
||||||
private boolean useTail;
|
private boolean useTail;
|
||||||
/** The amount of iterations of the algorithm. */
|
/** The amount of iterations of the algorithm. */
|
||||||
@ -43,23 +41,23 @@ public class ConstraintDefinitionIK extends ConstraintDefinition {
|
|||||||
useTail = (flag & FLAG_USE_TAIL) != 0;
|
useTail = (flag & FLAG_USE_TAIL) != 0;
|
||||||
|
|
||||||
if ((flag & FLAG_POSITION) == 0) {
|
if ((flag & FLAG_POSITION) == 0) {
|
||||||
needToCompute = false;
|
trackToBeChanged = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needToCompute) {
|
if (trackToBeChanged) {
|
||||||
alteredOmas = new HashSet<Long>();
|
alteredOmas = new HashSet<Long>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) {
|
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
|
return;// no need to do anything
|
||||||
}
|
}
|
||||||
Quaternion q = new Quaternion();
|
Quaternion q = new Quaternion();
|
||||||
Vector3f t = targetTransform.getTranslation();
|
Vector3f t = targetTransform.getTranslation();
|
||||||
List<BoneContext> bones = this.loadBones();
|
List<BoneContext> bones = this.loadBones();
|
||||||
if(bones.size() == 0) {
|
if (bones.size() == 0) {
|
||||||
return;// no need to do anything
|
return;// no need to do anything
|
||||||
}
|
}
|
||||||
float distanceFromTarget = Float.MAX_VALUE;
|
float distanceFromTarget = Float.MAX_VALUE;
|
||||||
@ -186,4 +184,20 @@ public class ConstraintDefinitionIK extends ConstraintDefinition {
|
|||||||
}
|
}
|
||||||
return bones;
|
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<BoneContext> bones = this.loadBones();
|
||||||
|
trackToBeChanged = bones.size() > 0;
|
||||||
|
}
|
||||||
|
return trackToBeChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTargetRequired() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,27 +34,30 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
int invZ = flag & LOCLIKE_Z_INVERT;
|
int invZ = flag & LOCLIKE_Z_INVERT;
|
||||||
// clear the other flags to swap them
|
// clear the other flags to swap them
|
||||||
flag &= LOCLIKE_X | LOCLIKE_X_INVERT | LOCLIKE_OFFSET;
|
flag &= LOCLIKE_X | LOCLIKE_X_INVERT | LOCLIKE_OFFSET;
|
||||||
|
|
||||||
flag |= y << 1;
|
flag |= y << 1;
|
||||||
flag |= invY << 1;
|
flag |= invY << 1;
|
||||||
flag |= z >> 1;
|
flag |= z >> 1;
|
||||||
flag |= invZ >> 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
|
@Override
|
||||||
public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) {
|
public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) {
|
||||||
if (this.getOwner() instanceof Bone && ((Bone) this.getOwner()).getParent() != null &&
|
if (influence == 0 || targetTransform == null || !this.isTrackToBeChanged()) {
|
||||||
blenderContext.getBoneContext(ownerOMA).is(BoneContext.CONNECTED_TO_PARENT)) {
|
|
||||||
// location copy does not work on bones who are connected to their parent
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(influence == 0 || targetTransform == null) {
|
|
||||||
return ;// no need to do anything
|
|
||||||
}
|
|
||||||
|
|
||||||
Transform ownerTransform = this.getOwnerTransform(ownerSpace);
|
Transform ownerTransform = this.getOwnerTransform(ownerSpace);
|
||||||
|
|
||||||
Vector3f ownerLocation = ownerTransform.getTranslation();
|
Vector3f ownerLocation = ownerTransform.getTranslation();
|
||||||
Vector3f targetLocation = targetTransform.getTranslation();
|
Vector3f targetLocation = targetTransform.getTranslation();
|
||||||
|
|
||||||
@ -88,7 +91,7 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
startLocation.subtractLocal(ownerLocation).normalizeLocal().mult(influence);
|
startLocation.subtractLocal(ownerLocation).normalizeLocal().mult(influence);
|
||||||
ownerLocation.addLocal(startLocation);
|
ownerLocation.addLocal(startLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.applyOwnerTransform(ownerTransform, ownerSpace);
|
this.applyOwnerTransform(ownerTransform, ownerSpace);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,4 +99,9 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
public String getConstraintTypeName() {
|
public String getConstraintTypeName() {
|
||||||
return "Copy location";
|
return "Copy location";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTargetRequired() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,18 +52,24 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
limits[2][0] = ((Number) constraintData.getFieldValue("zmin")).floatValue();
|
limits[2][0] = ((Number) constraintData.getFieldValue("zmin")).floatValue();
|
||||||
limits[2][1] = ((Number) constraintData.getFieldValue("zmax")).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
|
@Override
|
||||||
public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) {
|
public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) {
|
||||||
if (this.getOwner() instanceof Bone && ((Bone) this.getOwner()).getParent() != null &&
|
if (influence == 0 || !this.isTrackToBeChanged()) {
|
||||||
blenderContext.getBoneContext(ownerOMA).is(BoneContext.CONNECTED_TO_PARENT)) {
|
return;// no need to do anything
|
||||||
// location limit does not work on bones who are connected to their parent
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Transform ownerTransform = this.getOwnerTransform(ownerSpace);
|
Transform ownerTransform = this.getOwnerTransform(ownerSpace);
|
||||||
|
|
||||||
Vector3f translation = ownerTransform.getTranslation();
|
Vector3f translation = ownerTransform.getTranslation();
|
||||||
|
|
||||||
if ((flag & LIMIT_XMIN) != 0 && translation.x < limits[0][0]) {
|
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]) {
|
if ((flag & LIMIT_ZMAX) != 0 && translation.z > limits[2][1]) {
|
||||||
translation.z -= (translation.z - limits[2][1]) * influence;
|
translation.z -= (translation.z - limits[2][1]) * influence;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.applyOwnerTransform(ownerTransform, ownerSpace);
|
this.applyOwnerTransform(ownerTransform, ownerSpace);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,4 +98,9 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
public String getConstraintTypeName() {
|
public String getConstraintTypeName() {
|
||||||
return "Limit location";
|
return "Limit location";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTargetRequired() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.constraints.ConstraintHelper.Space;
|
||||||
import com.jme3.scene.plugins.blender.file.Structure;
|
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 {
|
public class ConstraintDefinitionMaintainVolume extends ConstraintDefinition {
|
||||||
private static final int FLAG_MASK_X = 0;
|
private static final int FLAG_MASK_X = 0;
|
||||||
private static final int FLAG_MASK_Y = 1;
|
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) {
|
public ConstraintDefinitionMaintainVolume(Structure constraintData, Long ownerOMA, BlenderContext blenderContext) {
|
||||||
super(constraintData, ownerOMA, blenderContext);
|
super(constraintData, ownerOMA, blenderContext);
|
||||||
volume = (float) Math.sqrt(((Number) constraintData.getFieldValue("volume")).floatValue());
|
volume = (float) Math.sqrt(((Number) constraintData.getFieldValue("volume")).floatValue());
|
||||||
|
trackToBeChanged = volume != 1 && (flag & (FLAG_MASK_X | FLAG_MASK_Y | FLAG_MASK_Z)) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) {
|
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
|
// 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
|
// but in case of bones we need to make computations
|
||||||
if (this.getOwner() instanceof Bone) {
|
if (this.getOwner() instanceof Bone) {
|
||||||
@ -47,4 +53,9 @@ public class ConstraintDefinitionMaintainVolume extends ConstraintDefinition {
|
|||||||
public String getConstraintTypeName() {
|
public String getConstraintTypeName() {
|
||||||
return "Maintain volume";
|
return "Maintain volume";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTargetRequired() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
|
|
||||||
public ConstraintDefinitionNull(Structure constraintData, Long ownerOMA, BlenderContext blenderContext) {
|
public ConstraintDefinitionNull(Structure constraintData, Long ownerOMA, BlenderContext blenderContext) {
|
||||||
super(constraintData, ownerOMA, blenderContext);
|
super(constraintData, ownerOMA, blenderContext);
|
||||||
|
trackToBeChanged = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -25,4 +26,9 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
public String getConstraintTypeName() {
|
public String getConstraintTypeName() {
|
||||||
return "Null";
|
return "Null";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTargetRequired() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,15 +25,16 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
|
|
||||||
public ConstraintDefinitionRotLike(Structure constraintData, Long ownerOMA, BlenderContext blenderContext) {
|
public ConstraintDefinitionRotLike(Structure constraintData, Long ownerOMA, BlenderContext blenderContext) {
|
||||||
super(constraintData, ownerOMA, blenderContext);
|
super(constraintData, ownerOMA, blenderContext);
|
||||||
|
trackToBeChanged = (flag & (ROTLIKE_X | ROTLIKE_Y | ROTLIKE_Z)) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) {
|
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
|
return;// no need to do anything
|
||||||
}
|
}
|
||||||
Transform ownerTransform = this.getOwnerTransform(ownerSpace);
|
Transform ownerTransform = this.getOwnerTransform(ownerSpace);
|
||||||
|
|
||||||
Quaternion ownerRotation = ownerTransform.getRotation();
|
Quaternion ownerRotation = ownerTransform.getRotation();
|
||||||
ownerAngles = ownerRotation.toAngles(ownerAngles);
|
ownerAngles = ownerRotation.toAngles(ownerAngles);
|
||||||
targetAngles = targetTransform.getRotation().toAngles(targetAngles);
|
targetAngles = targetTransform.getRotation().toAngles(targetAngles);
|
||||||
@ -70,7 +71,7 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
// ownerLocation.addLocal(startLocation);
|
// ownerLocation.addLocal(startLocation);
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
this.applyOwnerTransform(ownerTransform, ownerSpace);
|
this.applyOwnerTransform(ownerTransform, ownerSpace);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,4 +79,9 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
public String getConstraintTypeName() {
|
public String getConstraintTypeName() {
|
||||||
return "Copy rotation";
|
return "Copy rotation";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTargetRequired() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,12 +65,17 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
* if(limits[i][0] > limits[i][1]) { float temp = limits[i][0];
|
* if(limits[i][0] > limits[i][1]) { float temp = limits[i][0];
|
||||||
* limits[i][0] = limits[i][1]; limits[i][1] = temp; } }
|
* limits[i][0] = limits[i][1]; limits[i][1] = temp; } }
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
trackToBeChanged = (flag & (LIMIT_XROT | LIMIT_YROT | LIMIT_ZROT)) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) {
|
public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) {
|
||||||
|
if (influence == 0 || !trackToBeChanged) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
Transform ownerTransform = this.getOwnerTransform(ownerSpace);
|
Transform ownerTransform = this.getOwnerTransform(ownerSpace);
|
||||||
|
|
||||||
ownerTransform.getRotation().toAngles(angles);
|
ownerTransform.getRotation().toAngles(angles);
|
||||||
// make sure that the rotations are always in range [0, 2PI)
|
// make sure that the rotations are always in range [0, 2PI)
|
||||||
// TODO: same comment as in constructor
|
// TODO: same comment as in constructor
|
||||||
@ -108,7 +113,7 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
angles[2] -= difference;
|
angles[2] -= difference;
|
||||||
}
|
}
|
||||||
ownerTransform.getRotation().fromAngles(angles);
|
ownerTransform.getRotation().fromAngles(angles);
|
||||||
|
|
||||||
this.applyOwnerTransform(ownerTransform, ownerSpace);
|
this.applyOwnerTransform(ownerTransform, ownerSpace);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,4 +121,9 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
public String getConstraintTypeName() {
|
public String getConstraintTypeName() {
|
||||||
return "Limit rotation";
|
return "Limit rotation";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTargetRequired() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,16 +27,18 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
// them
|
// them
|
||||||
flag |= y << 1;
|
flag |= y << 1;
|
||||||
flag |= z >> 1;
|
flag |= z >> 1;
|
||||||
|
|
||||||
|
trackToBeChanged = (flag & (SIZELIKE_X | SIZELIKE_Y | SIZELIKE_Z)) != 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) {
|
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
|
return;// no need to do anything
|
||||||
}
|
}
|
||||||
Transform ownerTransform = this.getOwnerTransform(ownerSpace);
|
Transform ownerTransform = this.getOwnerTransform(ownerSpace);
|
||||||
|
|
||||||
Vector3f ownerScale = ownerTransform.getScale();
|
Vector3f ownerScale = ownerTransform.getScale();
|
||||||
Vector3f targetScale = targetTransform.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.z = targetScale.z * influence + (1.0f - influence) * ownerScale.z;
|
||||||
}
|
}
|
||||||
ownerScale.addLocal(offset);
|
ownerScale.addLocal(offset);
|
||||||
|
|
||||||
this.applyOwnerTransform(ownerTransform, ownerSpace);
|
this.applyOwnerTransform(ownerTransform, ownerSpace);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,4 +66,9 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
public String getConstraintTypeName() {
|
public String getConstraintTypeName() {
|
||||||
return "Copy scale";
|
return "Copy scale";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTargetRequired() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,12 +50,17 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
limits[2][0] = ((Number) constraintData.getFieldValue("zmin")).floatValue();
|
limits[2][0] = ((Number) constraintData.getFieldValue("zmin")).floatValue();
|
||||||
limits[2][1] = ((Number) constraintData.getFieldValue("zmax")).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
|
@Override
|
||||||
public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) {
|
public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) {
|
||||||
|
if (influence == 0 || !trackToBeChanged) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
Transform ownerTransform = this.getOwnerTransform(ownerSpace);
|
Transform ownerTransform = this.getOwnerTransform(ownerSpace);
|
||||||
|
|
||||||
Vector3f scale = ownerTransform.getScale();
|
Vector3f scale = ownerTransform.getScale();
|
||||||
if ((flag & LIMIT_XMIN) != 0 && scale.x < limits[0][0]) {
|
if ((flag & LIMIT_XMIN) != 0 && scale.x < limits[0][0]) {
|
||||||
scale.x -= (scale.x - limits[0][0]) * influence;
|
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]) {
|
if ((flag & LIMIT_ZMAX) != 0 && scale.z > limits[2][1]) {
|
||||||
scale.z -= (scale.z - limits[2][1]) * influence;
|
scale.z -= (scale.z - limits[2][1]) * influence;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.applyOwnerTransform(ownerTransform, ownerSpace);
|
this.applyOwnerTransform(ownerTransform, ownerSpace);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,4 +88,9 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
public String getConstraintTypeName() {
|
public String getConstraintTypeName() {
|
||||||
return "Limit scale";
|
return "Limit scale";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTargetRequired() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,8 +35,8 @@ public class ConstraintDefinitionTransLike extends ConstraintDefinition {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) {
|
public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) {
|
||||||
if(influence == 0 || targetTransform == null) {
|
if (influence == 0 || targetTransform == null) {
|
||||||
return ;// no need to do anything
|
return;// no need to do anything
|
||||||
}
|
}
|
||||||
Object target = this.getTarget();// Bone or Node
|
Object target = this.getTarget();// Bone or Node
|
||||||
Object owner = this.getOwner();// Bone or Node
|
Object owner = this.getOwner();// Bone or Node
|
||||||
@ -73,4 +73,9 @@ public class ConstraintDefinitionTransLike extends ConstraintDefinition {
|
|||||||
public String getConstraintTypeName() {
|
public String getConstraintTypeName() {
|
||||||
return "Copy transforms";
|
return "Copy transforms";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTargetRequired() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ import com.jme3.scene.plugins.blender.constraints.ConstraintHelper.Space;
|
|||||||
public UnsupportedConstraintDefinition(String typeName) {
|
public UnsupportedConstraintDefinition(String typeName) {
|
||||||
super(null, null, null);
|
super(null, null, null);
|
||||||
this.typeName = typeName;
|
this.typeName = typeName;
|
||||||
|
trackToBeChanged = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -31,4 +32,9 @@ import com.jme3.scene.plugins.blender.constraints.ConstraintHelper.Space;
|
|||||||
public String getConstraintTypeName() {
|
public String getConstraintTypeName() {
|
||||||
return typeName;
|
return typeName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTargetRequired() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user