Several changes to constraints (but may not working well yet).

Fix to Y-up axis issue when parent was present bu not loaded (in different layer for example).

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7913 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
Kae..pl 14 years ago
parent f182b5d91b
commit 99746c72ec
  1. 11
      engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/ArmatureHelper.java
  2. 7
      engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/CameraHelper.java
  3. 263
      engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/ConstraintHelper.java
  4. 5
      engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/CurvesHelper.java
  5. 5
      engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/IpoHelper.java
  6. 6
      engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/LightHelper.java
  7. 5
      engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/MaterialHelper.java
  8. 5
      engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/MeshHelper.java
  9. 9
      engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/ModifierHelper.java
  10. 5
      engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/NoiseHelper.java
  11. 38
      engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/ObjectHelper.java
  12. 5
      engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/ParticlesHelper.java
  13. 6
      engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/TextureHelper.java
  14. 17
      engine/src/blender/com/jme3/scene/plugins/blender/structures/AbstractInfluenceFunction.java
  15. 129
      engine/src/blender/com/jme3/scene/plugins/blender/structures/CalculationBone.java
  16. 11
      engine/src/blender/com/jme3/scene/plugins/blender/utils/AbstractBlenderHelper.java
  17. 41
      engine/src/blender/com/jme3/scene/plugins/blender/utils/JmeConverter.java

@ -267,9 +267,9 @@ public class ArmatureHelper extends AbstractBlenderHelper {
} }
/** /**
* This method returns bone transformation data for the bone of a given name. * This method returns bone transformation data for the bone of a given index.
* @param boneName * @param index
* the name of the bone * the index of the bone
* @return bone's transformation data * @return bone's transformation data
*/ */
public BoneTransformationData getBoneTransformationDataRoot(int index) { public BoneTransformationData getBoneTransformationDataRoot(int index) {
@ -368,4 +368,9 @@ public class ArmatureHelper extends AbstractBlenderHelper {
bonesMap.clear(); bonesMap.clear();
boneDataRoots.clear(); boneDataRoots.clear();
} }
@Override
public boolean shouldBeLoaded(Structure structure, DataRepository dataRepository) {
return true;
}
} }

@ -3,10 +3,12 @@ package com.jme3.scene.plugins.blender.helpers.v249;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import com.jme3.asset.BlenderKey.FeaturesToLoad;
import com.jme3.renderer.Camera; import com.jme3.renderer.Camera;
import com.jme3.scene.plugins.blender.data.Structure; import com.jme3.scene.plugins.blender.data.Structure;
import com.jme3.scene.plugins.blender.exception.BlenderFileException; import com.jme3.scene.plugins.blender.exception.BlenderFileException;
import com.jme3.scene.plugins.blender.utils.AbstractBlenderHelper; import com.jme3.scene.plugins.blender.utils.AbstractBlenderHelper;
import com.jme3.scene.plugins.blender.utils.DataRepository;
/** /**
* A class that is used in light calculations. * A class that is used in light calculations.
@ -55,4 +57,9 @@ public class CameraHelper extends AbstractBlenderHelper {
result.setFrustumPerspective(angle, aspect, clipsta, clipend); result.setFrustumPerspective(angle, aspect, clipsta, clipend);
return result; return result;
} }
@Override
public boolean shouldBeLoaded(Structure structure, DataRepository dataRepository) {
return (dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.CAMERAS) != 0;
}
} }

@ -2,6 +2,7 @@ package com.jme3.scene.plugins.blender.helpers.v249;
import java.nio.FloatBuffer; import java.nio.FloatBuffer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -13,6 +14,7 @@ import com.jme3.animation.BoneTrack;
import com.jme3.animation.Skeleton; import com.jme3.animation.Skeleton;
import com.jme3.math.FastMath; import com.jme3.math.FastMath;
import com.jme3.math.Quaternion; import com.jme3.math.Quaternion;
import com.jme3.math.Transform;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry; import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh; import com.jme3.scene.Mesh;
@ -22,6 +24,7 @@ import com.jme3.scene.VertexBuffer.Type;
import com.jme3.scene.plugins.blender.data.Structure; import com.jme3.scene.plugins.blender.data.Structure;
import com.jme3.scene.plugins.blender.exception.BlenderFileException; import com.jme3.scene.plugins.blender.exception.BlenderFileException;
import com.jme3.scene.plugins.blender.structures.AbstractInfluenceFunction; import com.jme3.scene.plugins.blender.structures.AbstractInfluenceFunction;
import com.jme3.scene.plugins.blender.structures.CalculationBone;
import com.jme3.scene.plugins.blender.structures.Constraint; import com.jme3.scene.plugins.blender.structures.Constraint;
import com.jme3.scene.plugins.blender.structures.Constraint.Space; import com.jme3.scene.plugins.blender.structures.Constraint.Space;
import com.jme3.scene.plugins.blender.structures.ConstraintType; import com.jme3.scene.plugins.blender.structures.ConstraintType;
@ -146,70 +149,89 @@ public class ConstraintHelper extends AbstractBlenderHelper {
@Override @Override
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) { public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {
Structure constraintStructure = constraint.getData(); try {
this.validateConstraintType(constraintStructure); Structure constraintStructure = constraint.getData();
/*Long boneOMA = constraint.getBoneOMA(); this.validateConstraintType(constraintStructure);
//IK solver is only attached to bones Long boneOMA = constraint.getBoneOMA();
Bone ownerBone = (Bone)dataRepository.getLoadedFeature(boneOMA, LoadedFeatureDataType.LOADED_FEATURE); // IK solver is only attached to bones
Bone ownerBone = (Bone) dataRepository.getLoadedFeature(boneOMA, LoadedFeatureDataType.LOADED_FEATURE);
//get the target point
Object targetObject = this.getTarget(constraint, LoadedFeatureDataType.LOADED_FEATURE); // get the target point
Vector3f pt = null;//Point Target Object targetObject = this.getTarget(constraint, LoadedFeatureDataType.LOADED_FEATURE);
if(targetObject instanceof Bone) { Vector3f pt = null;// Point Target
pt = ((Bone)targetObject).getModelSpacePosition(); if (targetObject instanceof Bone) {
} else if(targetObject instanceof Node) { pt = ((Bone) targetObject).getModelSpacePosition();
pt = ((Node)targetObject).getWorldTranslation(); } else if (targetObject instanceof Node) {
} else if(targetObject instanceof Skeleton) { pt = ((Node) targetObject).getWorldTranslation();
Structure armatureNodeStructure = (Structure)this.getTarget(constraint, LoadedFeatureDataType.LOADED_STRUCTURE); } else if (targetObject instanceof Skeleton) {
ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class); Structure armatureNodeStructure = (Structure) this.getTarget(constraint, LoadedFeatureDataType.LOADED_STRUCTURE);
Transform transform = objectHelper.getTransformation(armatureNodeStructure); ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);
pt = transform.getTranslation(); Transform transform = objectHelper.getTransformation(armatureNodeStructure, dataRepository);
} else { pt = transform.getTranslation();
throw new IllegalStateException("Unknown target object type! Should be Node, Bone or Skeleton and there is: " + targetObject.getClass().getName()); } else {
} throw new IllegalStateException(
//preparing data "Unknown target object type! Should be Node, Bone or Skeleton and there is: "
int maxIterations = ((Number)constraintStructure.getFieldValue("iterations")).intValue(); + targetObject.getClass().getName());
CalculationBone[] bones = this.getBonesToCalculate(ownerBone, skeleton, boneAnimation); }
for(int i=0;i<bones.length;++i) {
System.out.println(Arrays.toString(bones[i].track.getTranslations())); //fetching the owner's bone track
System.out.println(Arrays.toString(bones[i].track.getRotations())); // BoneTrack ownerBoneTrack = null;
System.out.println("==============================="); // int boneIndex = skeleton.getBoneIndex(ownerBone);
} // for (int i = 0; i < boneAnimation.getTracks().length; ++i) {
Quaternion rotation = new Quaternion(); // if (boneAnimation.getTracks()[i].getTargetBoneIndex() == boneIndex) {
int maxFrames = bones[0].track.getTimes().length;//all tracks should have the same amount of frames // ownerBoneTrack = boneAnimation.getTracks()[i];
// break;
for(int frame = 0; frame < maxFrames; ++frame) { // }
float error = IK_SOLVER_ERROR; // }
int iteration = 0; // int ownerBoneFramesCount = ownerBoneTrack==null ? 0 : ownerBoneTrack.getTimes().length;
while(error >= IK_SOLVER_ERROR && iteration <= maxIterations) {
//rotating the bones // preparing data
for(int i = 0; i < bones.length - 1; ++i) { int maxIterations = ((Number) constraintStructure.getFieldValue("iterations")).intValue();
Vector3f pe = bones[i].getEndPoint(); CalculationBone[] bones = this.getBonesToCalculate(ownerBone, skeleton, boneAnimation);
Vector3f pc = bones[i + 1].getWorldTranslation().clone(); // for (int i = 0; i < bones.length; ++i) {
// System.out.println(Arrays.toString(bones[i].track.getTranslations()));
Vector3f peSUBpc = pe.subtract(pc).normalizeLocal(); // System.out.println(Arrays.toString(bones[i].track.getRotations()));
Vector3f ptSUBpc = pt.subtract(pc).normalizeLocal(); // System.out.println("===============================");
// }
float theta = FastMath.acos(peSUBpc.dot(ptSUBpc)); Quaternion rotation = new Quaternion();
Vector3f direction = peSUBpc.cross(ptSUBpc).normalizeLocal(); //all tracks should have the same amount of frames
bones[i].rotate(rotation.fromAngleAxis(theta, direction), frame); int framesCount = bones[0].getBoneFramesCount();
} assert framesCount >=1;
error = pt.subtract(bones[0].getEndPoint()).length(); for (int frame = 0; frame < framesCount; ++frame) {
++iteration; float error = IK_SOLVER_ERROR;
} int iteration = 0;
System.out.println("error = " + error + " iterations = " + iteration); while (error >= IK_SOLVER_ERROR && iteration <= maxIterations) {
} // rotating the bones
for (int i = 0; i < bones.length - 1; ++i) {
for(CalculationBone bone : bones) { Vector3f pe = bones[i].getEndPoint();
bone.applyCalculatedTracks(); Vector3f pc = bones[i + 1].getWorldTranslation().clone();
}
Vector3f peSUBpc = pe.subtract(pc).normalizeLocal();
System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&"); Vector3f ptSUBpc = pt.subtract(pc).normalizeLocal();
for(int i=0;i<bones.length;++i) {
System.out.println(Arrays.toString(bones[i].track.getTranslations())); float theta = FastMath.acos(peSUBpc.dot(ptSUBpc));
System.out.println(Arrays.toString(bones[i].track.getRotations())); Vector3f direction = peSUBpc.cross(ptSUBpc).normalizeLocal();
System.out.println("==============================="); bones[i].rotate(rotation.fromAngleAxis(theta, direction), frame);
}*/ }
error = pt.subtract(bones[0].getEndPoint()).length();
++iteration;
}
System.out.println("error = " + error + " iterations = " + iteration);
}
for (CalculationBone bone : bones) {
bone.applyCalculatedTracks();
}
// System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
// for (int i = 0; i < bones.length; ++i) {
// System.out.println(Arrays.toString(bones[i].track.getTranslations()));
// System.out.println(Arrays.toString(bones[i].track.getRotations()));
// System.out.println("===============================");
// }
} catch(BlenderFileException e) {
LOGGER.severe(e.getLocalizedMessage());
}
} }
/** /**
@ -226,13 +248,14 @@ public class ConstraintHelper extends AbstractBlenderHelper {
List<CalculationBone> bonesList = new ArrayList<CalculationBone>(); List<CalculationBone> bonesList = new ArrayList<CalculationBone>();
Bone currentBone = bone; Bone currentBone = bone;
do { do {
int boneIndex = skeleton.getBoneIndex(currentBone); bonesList.add(new CalculationBone(currentBone, 1));
for (int i = 0; i < boneAnimation.getTracks().length; ++i) { // int boneIndex = skeleton.getBoneIndex(currentBone);
if (boneAnimation.getTracks()[i].getTargetBoneIndex() == boneIndex) { // for (int i = 0; i < boneAnimation.getTracks().length; ++i) {
bonesList.add(new CalculationBone(currentBone, boneAnimation.getTracks()[i])); // if (boneAnimation.getTracks()[i].getTargetBoneIndex() == boneIndex) {
break; // bonesList.add(new CalculationBone(currentBone, boneAnimation.getTracks()[i]));
} // break;
} // }
// }
currentBone = currentBone.getParent(); currentBone = currentBone.getParent();
} while (currentBone != null); } while (currentBone != null);
//attaching children //attaching children
@ -726,100 +749,8 @@ public class ConstraintHelper extends AbstractBlenderHelper {
constraints.clear(); constraints.clear();
} }
/** @Override
* The purpose of this class is to imitate bone's movement when calculating inverse kinematics. public boolean shouldBeLoaded(Structure structure, DataRepository dataRepository) {
* @author Marcin Roguski return true;
*/
private static class CalculationBone extends Node {
/** The name of the bone. Only to be used in toString method. */
private String boneName;
/** The bone's tracks. Will be altered at the end of calculation process. */
private BoneTrack track;
/** The starting position of the bone. */
private Vector3f startTranslation;
/** The starting rotation of the bone. */
private Quaternion startRotation;
/** The starting scale of the bone. */
private Vector3f startScale;
private Vector3f[] translations;
private Quaternion[] rotations;
private Vector3f[] scales;
/**
* Constructor. Stores the track, starting transformation and sets the transformation to the starting positions.
* @param bone
* the bone this class will imitate
* @param track
* the bone's tracks
*/
public CalculationBone(Bone bone, BoneTrack track) {
this.boneName = bone.getName();
this.track = track;
this.startRotation = bone.getModelSpaceRotation().clone();
this.startTranslation = bone.getModelSpacePosition().clone();
this.startScale = bone.getModelSpaceScale().clone();
this.translations = track.getTranslations();
this.rotations = track.getRotations();
this.scales = track.getScales();
this.reset();
}
/**
* This method returns the end point of the bone. If the bone has parent it is calculated from the start point
* of parent to the start point of this bone. If the bone doesn't have a parent the end location is considered
* to be 1 point up along Y axis (scale is applied if set to != 1.0);
* @return the end point of this bone
*/
//TODO: set to Z axis if user defined it this way
public Vector3f getEndPoint() {
if (this.getParent() == null) {
return new Vector3f(0, this.getLocalScale().y, 0);
} else {
Node parent = this.getParent();
return parent.getWorldTranslation().subtract(this.getWorldTranslation()).multLocal(this.getWorldScale());
}
}
/**
* This method resets the calculation bone to the starting position.
*/
public void reset() {
this.setLocalTranslation(startTranslation);
this.setLocalRotation(startRotation);
this.setLocalScale(startScale);
}
@Override
public int attachChild(Spatial child) {
if (this.getChildren() != null && this.getChildren().size() > 1) {
throw new IllegalStateException(this.getClass().getName() + " class instance can only have one child!");
}
return super.attachChild(child);
}
public Spatial rotate(Quaternion rot, int frame) {
Spatial spatial = super.rotate(rot);
this.updateWorldTransforms();
if (this.getChildren() != null && this.getChildren().size() > 0) {
CalculationBone child = (CalculationBone) this.getChild(0);
child.updateWorldTransforms();
}
rotations[frame].set(this.getLocalRotation());
translations[frame].set(this.getLocalTranslation());
if (scales != null) {
scales[frame].set(this.getLocalScale());
}
return spatial;
}
public void applyCalculatedTracks() {
track.setKeyframes(track.getTimes(), translations, rotations);//TODO:scales
}
@Override
public String toString() {
return boneName + ": " + this.getLocalRotation() + " " + this.getLocalTranslation();
}
} }
} }

@ -599,4 +599,9 @@ public class CurvesHelper extends AbstractBlenderHelper {
return new Vector3f(locArray.get(0).floatValue(), locArray.get(2).floatValue(), locArray.get(1).floatValue()); return new Vector3f(locArray.get(0).floatValue(), locArray.get(2).floatValue(), locArray.get(1).floatValue());
} }
} }
@Override
public boolean shouldBeLoaded(Structure structure, DataRepository dataRepository) {
return true;
}
} }

@ -71,6 +71,11 @@ public class IpoHelper extends AbstractBlenderHelper {
return new ConstIpo(constValue); return new ConstIpo(constValue);
} }
@Override
public boolean shouldBeLoaded(Structure structure, DataRepository dataRepository) {
return true;
}
/** /**
* Ipo constant curve. This is a curve with only one value and no specified type. This type of ipo cannot be used to * Ipo constant curve. This is a curve with only one value and no specified type. This type of ipo cannot be used to
* calculate tracks. It should only be used to calculate single value for a given frame. * calculate tracks. It should only be used to calculate single value for a given frame.

@ -34,6 +34,7 @@ package com.jme3.scene.plugins.blender.helpers.v249;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import com.jme3.asset.BlenderKey.FeaturesToLoad;
import com.jme3.light.DirectionalLight; import com.jme3.light.DirectionalLight;
import com.jme3.light.Light; import com.jme3.light.Light;
import com.jme3.light.PointLight; import com.jme3.light.PointLight;
@ -97,4 +98,9 @@ public class LightHelper extends AbstractBlenderHelper {
} }
return result; return result;
} }
@Override
public boolean shouldBeLoaded(Structure structure, DataRepository dataRepository) {
return (dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.LIGHTS) != 0;
}
} }

@ -685,6 +685,11 @@ public class MaterialHelper extends AbstractBlenderHelper {
} }
} }
@Override
public boolean shouldBeLoaded(Structure structure, DataRepository dataRepository) {
return (dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.MATERIALS) != 0;
}
/** /**
* An interface used in calculating alpha mask during particles' texture calculations. * An interface used in calculating alpha mask during particles' texture calculations.
* @author Marcin Roguski (Kaelthas) * @author Marcin Roguski (Kaelthas)

@ -605,4 +605,9 @@ public class MeshHelper extends AbstractBlenderHelper {
// mesh.setMaxNumWeights(maxWeightsPerVert); // mesh.setMaxNumWeights(maxWeightsPerVert);
return maxWeightsPerVert; return maxWeightsPerVert;
} }
@Override
public boolean shouldBeLoaded(Structure structure, DataRepository dataRepository) {
return true;
}
} }

@ -352,7 +352,7 @@ public class ModifierHelper extends AbstractBlenderHelper {
//preparing the object's bone //preparing the object's bone
ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class); ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);
Transform t = objectHelper.getTransformation(objectStructure); Transform t = objectHelper.getTransformation(objectStructure, dataRepository);
Bone bone = new Bone(null); Bone bone = new Bone(null);
bone.setBindTransforms(t.getTranslation(), t.getRotation(), t.getScale()); bone.setBindTransforms(t.getTranslation(), t.getRotation(), t.getScale());
@ -545,7 +545,7 @@ public class ModifierHelper extends AbstractBlenderHelper {
ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class); ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);
try {// we take the structure in case the object was not yet loaded try {// we take the structure in case the object was not yet loaded
Structure offsetStructure = offsetObjectBlock.getStructure(dataRepository); Structure offsetStructure = offsetObjectBlock.getStructure(dataRepository);
Vector3f translation = objectHelper.getTransformation(offsetStructure).getTranslation(); Vector3f translation = objectHelper.getTransformation(offsetStructure, dataRepository).getTranslation();
objectOffset[0] = translation.x; objectOffset[0] = translation.x;
objectOffset[1] = translation.y; objectOffset[1] = translation.y;
objectOffset[2] = translation.z; objectOffset[2] = translation.z;
@ -754,4 +754,9 @@ public class ModifierHelper extends AbstractBlenderHelper {
} }
return new Skeleton(bones.toArray(new Bone[bones.size()])); return new Skeleton(bones.toArray(new Bone[bones.size()]));
} }
@Override
public boolean shouldBeLoaded(Structure structure, DataRepository dataRepository) {
return true;
}
} }

@ -1530,6 +1530,11 @@ public class NoiseHelper extends AbstractBlenderHelper {
} }
} }
@Override
public boolean shouldBeLoaded(Structure structure, DataRepository dataRepository) {
return true;
}
/** /**
* This interface is used for distance calculation classes. Distance metrics for voronoi. e parameter only used in * This interface is used for distance calculation classes. Distance metrics for voronoi. e parameter only used in
* Minkovsky. * Minkovsky.

@ -31,10 +31,13 @@
*/ */
package com.jme3.scene.plugins.blender.helpers.v249; package com.jme3.scene.plugins.blender.helpers.v249;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import com.jme3.asset.BlenderKey.FeaturesToLoad;
import com.jme3.light.DirectionalLight; import com.jme3.light.DirectionalLight;
import com.jme3.light.Light; import com.jme3.light.Light;
import com.jme3.light.PointLight; import com.jme3.light.PointLight;
@ -77,6 +80,16 @@ public class ObjectHelper extends AbstractBlenderHelper {
protected static final int OBJECT_TYPE_LATTICE = 22; protected static final int OBJECT_TYPE_LATTICE = 22;
protected static final int OBJECT_TYPE_ARMATURE = 25; protected static final int OBJECT_TYPE_ARMATURE = 25;
/**
* This collection contains types of features that are not visible to the user.
* These will be loaded regardless the layer they reside in.
*/
protected static final Collection<Integer> invisibleTypes = new ArrayList<Integer>();
static {
invisibleTypes.add(OBJECT_TYPE_EMPTY);
invisibleTypes.add(OBJECT_TYPE_ARMATURE);
}
/** This variable indicates if the Y asxis is the UP axis or not. */ /** This variable indicates if the Y asxis is the UP axis or not. */
protected boolean fixUpAxis; protected boolean fixUpAxis;
/** Quaternion used to rotate data when Y is up axis. */ /** Quaternion used to rotate data when Y is up axis. */
@ -149,7 +162,7 @@ public class ObjectHelper extends AbstractBlenderHelper {
parent = this.toObject(parentStructure, dataRepository); parent = this.toObject(parentStructure, dataRepository);
} }
Transform t = objectHelper.getTransformation(objectStructure); Transform t = objectHelper.getTransformation(objectStructure, dataRepository);
try { try {
switch(type) { switch(type) {
@ -268,15 +281,23 @@ public class ObjectHelper extends AbstractBlenderHelper {
* @return objects transformation relative to its parent * @return objects transformation relative to its parent
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public Transform getTransformation(Structure objectStructure) { public Transform getTransformation(Structure objectStructure, DataRepository dataRepository) {
//these are transformations in global space //these are transformations in global space
DynamicArray<Number> loc = (DynamicArray<Number>)objectStructure.getFieldValue("loc"); DynamicArray<Number> loc = (DynamicArray<Number>)objectStructure.getFieldValue("loc");
DynamicArray<Number> size = (DynamicArray<Number>)objectStructure.getFieldValue("size"); DynamicArray<Number> size = (DynamicArray<Number>)objectStructure.getFieldValue("size");
DynamicArray<Number> rot = (DynamicArray<Number>)objectStructure.getFieldValue("rot"); DynamicArray<Number> rot = (DynamicArray<Number>)objectStructure.getFieldValue("rot");
//load parent inverse matrix //load parent inverse matrix
Pointer parent = (Pointer) objectStructure.getFieldValue("parent"); Pointer pParent = (Pointer) objectStructure.getFieldValue("parent");
Matrix4f parentInv = parent.isNull() ? Matrix4f.IDENTITY : this.getMatrix(objectStructure, "parentinv"); Structure parent = null;
if(pParent.isNotNull()) {
try {
parent = pParent.fetchData(dataRepository.getInputStream()).get(0);
} catch (BlenderFileException e) {
LOGGER.log(Level.WARNING, "Cannot fetch parent for object! Reason: {0}", e.getLocalizedMessage());
}
}
Matrix4f parentInv = pParent.isNull() ? Matrix4f.IDENTITY : this.getMatrix(objectStructure, "parentinv");
//create the global matrix (without the scale) //create the global matrix (without the scale)
Matrix4f globalMatrix = new Matrix4f(); Matrix4f globalMatrix = new Matrix4f();
@ -296,7 +317,7 @@ public class ObjectHelper extends AbstractBlenderHelper {
size.get(2).floatValue() * scaleZ); size.get(2).floatValue() * scaleZ);
//the root object is transformed if the Y axis is UP //the root object is transformed if the Y axis is UP
if(parent.isNull() && fixUpAxis) { if(fixUpAxis && (pParent.isNull() || (parent!=null && !this.shouldBeLoaded(parent, dataRepository)))) {
float y = translation.y; float y = translation.y;
translation.y = translation.z; translation.y = translation.z;
translation.z = -y; translation.z = -y;
@ -343,4 +364,11 @@ public class ObjectHelper extends AbstractBlenderHelper {
public void clearState() { public void clearState() {
fixUpAxis = false; fixUpAxis = false;
} }
@Override
public boolean shouldBeLoaded(Structure structure, DataRepository dataRepository) {
int lay = ((Number) structure.getFieldValue("lay")).intValue();
return ((lay & dataRepository.getBlenderKey().getLayersToLoad()) != 0
&& (dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.OBJECTS) != 0);
}
} }

@ -187,4 +187,9 @@ public class ParticlesHelper extends AbstractBlenderHelper {
} }
return result; return result;
} }
@Override
public boolean shouldBeLoaded(Structure structure, DataRepository dataRepository) {
return true;
}
} }

@ -42,6 +42,7 @@ import java.util.logging.Logger;
import com.jme3.asset.AssetNotFoundException; import com.jme3.asset.AssetNotFoundException;
import com.jme3.asset.TextureKey; import com.jme3.asset.TextureKey;
import com.jme3.asset.BlenderKey.FeaturesToLoad;
import com.jme3.math.FastMath; import com.jme3.math.FastMath;
import com.jme3.scene.plugins.blender.data.FileBlockHeader; import com.jme3.scene.plugins.blender.data.FileBlockHeader;
import com.jme3.scene.plugins.blender.data.Structure; import com.jme3.scene.plugins.blender.data.Structure;
@ -1780,6 +1781,11 @@ public class TextureHelper extends AbstractBlenderHelper {
} }
} }
@Override
public boolean shouldBeLoaded(Structure structure, DataRepository dataRepository) {
return (dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.TEXTURES) != 0;
}
/** /**
* Image types that can be loaded. AWT: png, jpg, jped or bmp TGA: tga DDS: DirectX image files * Image types that can be loaded. AWT: png, jpg, jped or bmp TGA: tga DDS: DirectX image files
* *

@ -139,20 +139,21 @@ public abstract class AbstractInfluenceFunction {
* @throws BlenderFileException this exception is thrown if the blend file is somehow corrupted * @throws BlenderFileException this exception is thrown if the blend file is somehow corrupted
*/ */
protected Object getTarget(Constraint constraint, LoadedFeatureDataType loadedFeatureDataType) throws BlenderFileException { protected Object getTarget(Constraint constraint, LoadedFeatureDataType loadedFeatureDataType) throws BlenderFileException {
//TODO: load the feature through objectHelper, this way we are certain the object loads and has //load the feature through objectHelper, this way we are certain the object loads and has
//his own constraints applied to traces //his own constraints applied to traces
ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class); ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);
//subtarget goes first //always load the target first
Long targetOMA = ((Pointer) constraint.getData().getFieldValue("tar")).getOldMemoryAddress();
Structure objectStructure = dataRepository.getFileBlock(targetOMA).getStructure(dataRepository);
Object result = objectHelper.toObject(objectStructure, dataRepository);
//subtarget should be loaded alogn with target
Object subtarget = constraint.getData().getFieldValue("subtarget"); Object subtarget = constraint.getData().getFieldValue("subtarget");
String subtargetName = subtarget==null ? null : subtarget.toString(); String subtargetName = subtarget==null ? null : subtarget.toString();
if (subtargetName!=null && subtargetName.length() > 0) { if (subtargetName!=null && subtargetName.length() > 0) {
//TODO: what if it is not yet loaded ??? result = dataRepository.getLoadedFeature(subtargetName, loadedFeatureDataType);
return dataRepository.getLoadedFeature(subtargetName, loadedFeatureDataType);
} }
//and now use the target return result;
Long targetOMA = ((Pointer) constraint.getData().getFieldValue("target")).getOldMemoryAddress();
Structure objectStructure = dataRepository.getFileBlock(targetOMA).getStructure(dataRepository);
return objectHelper.toObject(objectStructure, dataRepository);
} }
/** /**

@ -0,0 +1,129 @@
package com.jme3.scene.plugins.blender.structures;
import java.util.Arrays;
import com.jme3.animation.Bone;
import com.jme3.animation.BoneTrack;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
/**
* The purpose of this class is to imitate bone's movement when calculating inverse kinematics.
* @author Marcin Roguski
*/
public class CalculationBone extends Node {
private Bone bone;
/** The bone's tracks. Will be altered at the end of calculation process. */
private BoneTrack track;
/** The starting position of the bone. */
private Vector3f startTranslation;
/** The starting rotation of the bone. */
private Quaternion startRotation;
/** The starting scale of the bone. */
private Vector3f startScale;
private Vector3f[] translations;
private Quaternion[] rotations;
private Vector3f[] scales;
public CalculationBone(Bone bone, int boneFramesCount) {
this.bone = bone;
this.startRotation = bone.getModelSpaceRotation().clone();
this.startTranslation = bone.getModelSpacePosition().clone();
this.startScale = bone.getModelSpaceScale().clone();
this.reset();
if(boneFramesCount > 0) {
this.translations = new Vector3f[boneFramesCount];
this.rotations = new Quaternion[boneFramesCount];
this.scales = new Vector3f[boneFramesCount];
Arrays.fill(this.translations, 0, boneFramesCount, this.startTranslation);
Arrays.fill(this.rotations, 0, boneFramesCount, this.startRotation);
Arrays.fill(this.scales, 0, boneFramesCount, this.startScale);
}
}
/**
* Constructor. Stores the track, starting transformation and sets the transformation to the starting positions.
* @param bone
* the bone this class will imitate
* @param track
* the bone's tracks
*/
public CalculationBone(Bone bone, BoneTrack track) {
this(bone, 0);
this.track = track;
this.translations = track.getTranslations();
this.rotations = track.getRotations();
this.scales = track.getScales();
}
public int getBoneFramesCount() {
return this.translations==null ? 0 : this.translations.length;
}
/**
* This method returns the end point of the bone. If the bone has parent it is calculated from the start point
* of parent to the start point of this bone. If the bone doesn't have a parent the end location is considered
* to be 1 point up along Y axis (scale is applied if set to != 1.0);
* @return the end point of this bone
*/
//TODO: set to Z axis if user defined it this way
public Vector3f getEndPoint() {
if (this.getParent() == null) {
return new Vector3f(0, this.getLocalScale().y, 0);
} else {
Node parent = this.getParent();
return parent.getWorldTranslation().subtract(this.getWorldTranslation()).multLocal(this.getWorldScale());
}
}
/**
* This method resets the calculation bone to the starting position.
*/
public void reset() {
this.setLocalTranslation(startTranslation);
this.setLocalRotation(startRotation);
this.setLocalScale(startScale);
}
@Override
public int attachChild(Spatial child) {
if (this.getChildren() != null && this.getChildren().size() > 1) {
throw new IllegalStateException(this.getClass().getName() + " class instance can only have one child!");
}
return super.attachChild(child);
}
public Spatial rotate(Quaternion rot, int frame) {
Spatial spatial = super.rotate(rot);
this.updateWorldTransforms();
if (this.getChildren() != null && this.getChildren().size() > 0) {
CalculationBone child = (CalculationBone) this.getChild(0);
child.updateWorldTransforms();
}
rotations[frame].set(this.getLocalRotation());
translations[frame].set(this.getLocalTranslation());
if (scales != null) {
scales[frame].set(this.getLocalScale());
}
return spatial;
}
public void applyCalculatedTracks() {
if(track != null) {
track.setKeyframes(track.getTimes(), translations, rotations);//TODO:scales
} else {
bone.setUserControl(true);
bone.setUserTransforms(translations[0], rotations[0], scales[0]);
bone.setUserControl(false);
bone.updateWorldVectors();
}
}
@Override
public String toString() {
return bone.getName() + ": " + this.getLocalRotation() + " " + this.getLocalTranslation();
}
}

@ -127,4 +127,15 @@ public abstract class AbstractBlenderHelper {
} }
return properties; return properties;
} }
/**
* This method analyzes the given structure and the data contained within
* data repository and decides if the feature should be loaded.
* @param structure
* structure to be analyzed
* @param dataRepository
* the data repository
* @return <b>true</b> if the feature should be loaded and false otherwise
*/
public abstract boolean shouldBeLoaded(Structure structure, DataRepository dataRepository);
} }

@ -32,7 +32,6 @@
package com.jme3.scene.plugins.blender.utils; package com.jme3.scene.plugins.blender.utils;
import java.util.List; import java.util.List;
import java.util.logging.Logger;
import com.jme3.asset.BlenderKey.FeaturesToLoad; import com.jme3.asset.BlenderKey.FeaturesToLoad;
import com.jme3.asset.BlenderKey.WorldData; import com.jme3.asset.BlenderKey.WorldData;
@ -57,7 +56,6 @@ import com.jme3.scene.plugins.blender.helpers.ObjectHelper;
*/ */
public class JmeConverter implements BlenderConverter<Node, Camera, Light, Object, List<Geometry>, Material> { public class JmeConverter implements BlenderConverter<Node, Camera, Light, Object, List<Geometry>, Material> {
private static final Logger LOGGER = Logger.getLogger(JmeConverter.class.getName());
private final DataRepository dataRepository; private final DataRepository dataRepository;
/** /**
@ -104,46 +102,47 @@ public class JmeConverter implements BlenderConverter<Node, Camera, Light, Objec
@Override @Override
public Camera toCamera(Structure structure) throws BlenderFileException { public Camera toCamera(Structure structure) throws BlenderFileException {
if ((dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.CAMERAS) == 0) { CameraHelper cameraHelper = dataRepository.getHelper(CameraHelper.class);
return null; if (cameraHelper.shouldBeLoaded(structure, dataRepository)) {
return cameraHelper.toCamera(structure);
} }
CameraHelper cameraHelper = dataRepository.getHelper(CameraHelper.class); return null;
return cameraHelper.toCamera(structure);
} }
@Override @Override
public Light toLight(Structure structure) throws BlenderFileException { public Light toLight(Structure structure) throws BlenderFileException {
if ((dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.LIGHTS) == 0) { LightHelper lightHelper = dataRepository.getHelper(LightHelper.class);
return null; if (lightHelper.shouldBeLoaded(structure, dataRepository)) {
return lightHelper.toLight(structure, dataRepository);
} }
LightHelper lightHelper = dataRepository.getHelper(LightHelper.class); return null;
return lightHelper.toLight(structure, dataRepository);
} }
@Override @Override
public Object toObject(Structure structure) throws BlenderFileException { public Object toObject(Structure structure) throws BlenderFileException {
int lay = ((Number) structure.getFieldValue("lay")).intValue();
if ((lay & dataRepository.getBlenderKey().getLayersToLoad()) == 0
|| (dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.OBJECTS) == 0) {
return null;
}
ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class); ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);
return objectHelper.toObject(structure, dataRepository); if(objectHelper.shouldBeLoaded(structure, dataRepository)) {
return objectHelper.toObject(structure, dataRepository);
}
return null;
} }
@Override @Override
public List<Geometry> toMesh(Structure structure) throws BlenderFileException { public List<Geometry> toMesh(Structure structure) throws BlenderFileException {
MeshHelper meshHelper = dataRepository.getHelper(MeshHelper.class); MeshHelper meshHelper = dataRepository.getHelper(MeshHelper.class);
return meshHelper.toMesh(structure, dataRepository); if(meshHelper.shouldBeLoaded(structure, dataRepository)) {
return meshHelper.toMesh(structure, dataRepository);
}
return null;
} }
@Override @Override
public Material toMaterial(Structure structure) throws BlenderFileException { public Material toMaterial(Structure structure) throws BlenderFileException {
if ((dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.MATERIALS) == 0) { MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);
return null; if (materialHelper.shouldBeLoaded(structure, dataRepository)) {
return materialHelper.toMaterial(structure, dataRepository);
} }
MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class); return null;
return materialHelper.toMaterial(structure, dataRepository);
} }
/** /**

Loading…
Cancel
Save