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
This commit is contained in:
		
							parent
							
								
									f182b5d91b
								
							
						
					
					
						commit
						99746c72ec
					
				| @ -267,9 +267,9 @@ public class ArmatureHelper extends AbstractBlenderHelper { | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * This method returns bone transformation data for the bone of a given name. | ||||
|      * @param boneName | ||||
|      *        the name of the bone | ||||
|      * This method returns bone transformation data for the bone of a given index. | ||||
|      * @param index | ||||
|      *        the index of the bone | ||||
|      * @return bone's transformation data | ||||
|      */ | ||||
|     public BoneTransformationData getBoneTransformationDataRoot(int index) { | ||||
| @ -368,4 +368,9 @@ public class ArmatureHelper extends AbstractBlenderHelper { | ||||
|         bonesMap.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.Logger; | ||||
| 
 | ||||
| import com.jme3.asset.BlenderKey.FeaturesToLoad; | ||||
| import com.jme3.renderer.Camera; | ||||
| import com.jme3.scene.plugins.blender.data.Structure; | ||||
| import com.jme3.scene.plugins.blender.exception.BlenderFileException; | ||||
| import com.jme3.scene.plugins.blender.utils.AbstractBlenderHelper; | ||||
| import com.jme3.scene.plugins.blender.utils.DataRepository; | ||||
| 
 | ||||
| /** | ||||
|  * A class that is used in light calculations. | ||||
| @ -55,4 +57,9 @@ public class CameraHelper extends AbstractBlenderHelper { | ||||
|         result.setFrustumPerspective(angle, aspect, clipsta, clipend); | ||||
|         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.util.ArrayList; | ||||
| import java.util.Arrays; | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| @ -13,6 +14,7 @@ import com.jme3.animation.BoneTrack; | ||||
| import com.jme3.animation.Skeleton; | ||||
| import com.jme3.math.FastMath; | ||||
| import com.jme3.math.Quaternion; | ||||
| import com.jme3.math.Transform; | ||||
| import com.jme3.math.Vector3f; | ||||
| import com.jme3.scene.Geometry; | ||||
| 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.exception.BlenderFileException; | ||||
| 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.Space; | ||||
| import com.jme3.scene.plugins.blender.structures.ConstraintType; | ||||
| @ -146,70 +149,89 @@ public class ConstraintHelper extends AbstractBlenderHelper { | ||||
| 
 | ||||
| 				@Override | ||||
| 				public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) { | ||||
| 					Structure constraintStructure = constraint.getData(); | ||||
| 					this.validateConstraintType(constraintStructure); | ||||
| 					/*Long boneOMA = constraint.getBoneOMA(); | ||||
|                     //IK solver is only attached to bones | ||||
|                     Bone ownerBone = (Bone)dataRepository.getLoadedFeature(boneOMA, LoadedFeatureDataType.LOADED_FEATURE); | ||||
| 					try { | ||||
| 						Structure constraintStructure = constraint.getData(); | ||||
| 						this.validateConstraintType(constraintStructure); | ||||
| 						Long boneOMA = constraint.getBoneOMA(); | ||||
| 						// 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); | ||||
|                     Vector3f pt = null;//Point Target | ||||
|                     if(targetObject instanceof Bone) { | ||||
|                     pt = ((Bone)targetObject).getModelSpacePosition(); | ||||
|                     } else if(targetObject instanceof Node) { | ||||
|                     pt = ((Node)targetObject).getWorldTranslation(); | ||||
|                     } else if(targetObject instanceof Skeleton) { | ||||
|                     Structure armatureNodeStructure = (Structure)this.getTarget(constraint, LoadedFeatureDataType.LOADED_STRUCTURE); | ||||
|                     ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class); | ||||
|                     Transform transform = objectHelper.getTransformation(armatureNodeStructure); | ||||
|                     pt = transform.getTranslation(); | ||||
|                     } else { | ||||
|                     throw new IllegalStateException("Unknown target object type! Should be Node, Bone or Skeleton and there is: " + targetObject.getClass().getName()); | ||||
|                     } | ||||
|                     //preparing data | ||||
|                     int maxIterations = ((Number)constraintStructure.getFieldValue("iterations")).intValue(); | ||||
|                     CalculationBone[] bones = this.getBonesToCalculate(ownerBone, skeleton, boneAnimation); | ||||
|                     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("==============================="); | ||||
|                     } | ||||
|                     Quaternion rotation = new Quaternion(); | ||||
|                     int maxFrames = bones[0].track.getTimes().length;//all tracks should have the same amount of frames | ||||
| 						// get the target point | ||||
| 						Object targetObject = this.getTarget(constraint, LoadedFeatureDataType.LOADED_FEATURE); | ||||
| 						Vector3f pt = null;// Point Target | ||||
| 						if (targetObject instanceof Bone) { | ||||
| 							pt = ((Bone) targetObject).getModelSpacePosition(); | ||||
| 						} else if (targetObject instanceof Node) { | ||||
| 							pt = ((Node) targetObject).getWorldTranslation(); | ||||
| 						} else if (targetObject instanceof Skeleton) { | ||||
| 							Structure armatureNodeStructure = (Structure) this.getTarget(constraint, LoadedFeatureDataType.LOADED_STRUCTURE); | ||||
| 							ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class); | ||||
| 							Transform transform = objectHelper.getTransformation(armatureNodeStructure, dataRepository); | ||||
| 							pt = transform.getTranslation(); | ||||
| 						} else { | ||||
| 							throw new IllegalStateException( | ||||
| 									"Unknown target object type! Should be Node, Bone or Skeleton and there is: " | ||||
| 									+ targetObject.getClass().getName()); | ||||
| 						} | ||||
| 						 | ||||
| 						//fetching the owner's bone track | ||||
| //						BoneTrack ownerBoneTrack = null; | ||||
| //						int boneIndex = skeleton.getBoneIndex(ownerBone); | ||||
| //						for (int i = 0; i < boneAnimation.getTracks().length; ++i) { | ||||
| //							if (boneAnimation.getTracks()[i].getTargetBoneIndex() == boneIndex) { | ||||
| //								ownerBoneTrack = boneAnimation.getTracks()[i]; | ||||
| //								break; | ||||
| //							} | ||||
| //						} | ||||
| //						int ownerBoneFramesCount = ownerBoneTrack==null ? 0 : ownerBoneTrack.getTimes().length; | ||||
| 						 | ||||
| 						// preparing data | ||||
| 						int maxIterations = ((Number) constraintStructure.getFieldValue("iterations")).intValue(); | ||||
| 						CalculationBone[] bones = this.getBonesToCalculate(ownerBone, skeleton, boneAnimation); | ||||
| //						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("==============================="); | ||||
| //						} | ||||
| 						Quaternion rotation = new Quaternion(); | ||||
| 						//all tracks should have the same amount of frames | ||||
| 						int framesCount = bones[0].getBoneFramesCount(); | ||||
| 						assert framesCount >=1; | ||||
| 						for (int frame = 0; frame < framesCount; ++frame) { | ||||
| 							float error = IK_SOLVER_ERROR; | ||||
| 							int iteration = 0; | ||||
| 							while (error >= IK_SOLVER_ERROR && iteration <= maxIterations) { | ||||
| 								// rotating the bones | ||||
| 								for (int i = 0; i < bones.length - 1; ++i) { | ||||
| 									Vector3f pe = bones[i].getEndPoint(); | ||||
| 									Vector3f pc = bones[i + 1].getWorldTranslation().clone(); | ||||
| 
 | ||||
|                     for(int frame = 0; frame < maxFrames; ++frame) { | ||||
|                     float error = IK_SOLVER_ERROR; | ||||
|                     int iteration = 0; | ||||
|                     while(error >= IK_SOLVER_ERROR && iteration <= maxIterations) { | ||||
|                     //rotating the bones | ||||
|                     for(int i = 0; i < bones.length - 1; ++i) { | ||||
|                     Vector3f pe = bones[i].getEndPoint(); | ||||
|                     Vector3f pc = bones[i + 1].getWorldTranslation().clone(); | ||||
| 									Vector3f peSUBpc = pe.subtract(pc).normalizeLocal(); | ||||
| 									Vector3f ptSUBpc = pt.subtract(pc).normalizeLocal(); | ||||
| 
 | ||||
|                     Vector3f peSUBpc = pe.subtract(pc).normalizeLocal(); | ||||
|                     Vector3f ptSUBpc = pt.subtract(pc).normalizeLocal(); | ||||
| 									float theta = FastMath.acos(peSUBpc.dot(ptSUBpc)); | ||||
| 									Vector3f direction = peSUBpc.cross(ptSUBpc).normalizeLocal(); | ||||
| 									bones[i].rotate(rotation.fromAngleAxis(theta, direction), frame); | ||||
| 								} | ||||
| 								error = pt.subtract(bones[0].getEndPoint()).length(); | ||||
| 								++iteration; | ||||
| 							} | ||||
| 							System.out.println("error = " + error + "   iterations = " + iteration); | ||||
| 						} | ||||
| 
 | ||||
|                     float theta = FastMath.acos(peSUBpc.dot(ptSUBpc)); | ||||
|                     Vector3f direction = peSUBpc.cross(ptSUBpc).normalizeLocal(); | ||||
|                     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(); | ||||
| 						} | ||||
| 
 | ||||
|                     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("==============================="); | ||||
|                     }*/ | ||||
| //						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>(); | ||||
| 					Bone currentBone = bone; | ||||
| 					do { | ||||
| 						int boneIndex = skeleton.getBoneIndex(currentBone); | ||||
| 						for (int i = 0; i < boneAnimation.getTracks().length; ++i) { | ||||
| 							if (boneAnimation.getTracks()[i].getTargetBoneIndex() == boneIndex) { | ||||
| 								bonesList.add(new CalculationBone(currentBone, boneAnimation.getTracks()[i])); | ||||
| 								break; | ||||
| 							} | ||||
| 						} | ||||
| 						bonesList.add(new CalculationBone(currentBone, 1)); | ||||
| //						int boneIndex = skeleton.getBoneIndex(currentBone); | ||||
| //						for (int i = 0; i < boneAnimation.getTracks().length; ++i) { | ||||
| //							if (boneAnimation.getTracks()[i].getTargetBoneIndex() == boneIndex) { | ||||
| //								bonesList.add(new CalculationBone(currentBone, boneAnimation.getTracks()[i])); | ||||
| //								break; | ||||
| //							} | ||||
| //						} | ||||
| 						currentBone = currentBone.getParent(); | ||||
| 					} while (currentBone != null); | ||||
| 					//attaching children | ||||
| @ -725,101 +748,9 @@ public class ConstraintHelper extends AbstractBlenderHelper { | ||||
| 	public void clearState() { | ||||
| 		constraints.clear(); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * The purpose of this class is to imitate bone's movement when calculating inverse kinematics. | ||||
| 	 * @author Marcin Roguski | ||||
| 	 */ | ||||
| 	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(); | ||||
| 		} | ||||
| 	 | ||||
| 	@Override | ||||
| 	public boolean shouldBeLoaded(Structure structure, DataRepository dataRepository) { | ||||
| 		return true; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -599,4 +599,9 @@ public class CurvesHelper extends AbstractBlenderHelper { | ||||
|             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); | ||||
|     } | ||||
| 
 | ||||
|     @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 | ||||
|      * 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.Logger; | ||||
| 
 | ||||
| import com.jme3.asset.BlenderKey.FeaturesToLoad; | ||||
| import com.jme3.light.DirectionalLight; | ||||
| import com.jme3.light.Light; | ||||
| import com.jme3.light.PointLight; | ||||
| @ -97,4 +98,9 @@ public class LightHelper extends AbstractBlenderHelper { | ||||
|         } | ||||
|         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. | ||||
| 	 * @author Marcin Roguski (Kaelthas) | ||||
|  | ||||
| @ -605,4 +605,9 @@ public class MeshHelper extends AbstractBlenderHelper { | ||||
| 		// mesh.setMaxNumWeights(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 | ||||
|             ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class); | ||||
|             Transform t = objectHelper.getTransformation(objectStructure); | ||||
|             Transform t = objectHelper.getTransformation(objectStructure, dataRepository); | ||||
|             Bone bone = new Bone(null); | ||||
|             bone.setBindTransforms(t.getTranslation(), t.getRotation(), t.getScale()); | ||||
| 
 | ||||
| @ -545,7 +545,7 @@ public class ModifierHelper extends AbstractBlenderHelper { | ||||
|             ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class); | ||||
|             try {// we take the structure in case the object was not yet loaded | ||||
|                 Structure offsetStructure = offsetObjectBlock.getStructure(dataRepository); | ||||
|                 Vector3f translation = objectHelper.getTransformation(offsetStructure).getTranslation(); | ||||
|                 Vector3f translation = objectHelper.getTransformation(offsetStructure, dataRepository).getTranslation(); | ||||
|                 objectOffset[0] = translation.x; | ||||
|                 objectOffset[1] = translation.y; | ||||
|                 objectOffset[2] = translation.z; | ||||
| @ -754,4 +754,9 @@ public class ModifierHelper extends AbstractBlenderHelper { | ||||
|         } | ||||
|         return new Skeleton(bones.toArray(new Bone[bones.size()])); | ||||
|     } | ||||
|      | ||||
|     @Override | ||||
|     public boolean shouldBeLoaded(Structure structure, DataRepository dataRepository) { | ||||
|     	return true; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1529,6 +1529,11 @@ public class NoiseHelper extends AbstractBlenderHelper { | ||||
|             return rx * q[0] + ry * q[1] + rz * q[2]; | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     @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 | ||||
|  | ||||
| @ -31,10 +31,13 @@ | ||||
|  */ | ||||
| package com.jme3.scene.plugins.blender.helpers.v249; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collection; | ||||
| import java.util.List; | ||||
| import java.util.logging.Level; | ||||
| import java.util.logging.Logger; | ||||
| 
 | ||||
| import com.jme3.asset.BlenderKey.FeaturesToLoad; | ||||
| import com.jme3.light.DirectionalLight; | ||||
| import com.jme3.light.Light; | ||||
| 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_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. */ | ||||
| 	protected boolean						fixUpAxis; | ||||
| 	/** Quaternion used to rotate data when Y is up axis. */ | ||||
| @ -149,7 +162,7 @@ public class ObjectHelper extends AbstractBlenderHelper { | ||||
| 			parent = this.toObject(parentStructure, dataRepository); | ||||
| 		} | ||||
| 
 | ||||
| 		Transform t = objectHelper.getTransformation(objectStructure); | ||||
| 		Transform t = objectHelper.getTransformation(objectStructure, dataRepository); | ||||
| 		 | ||||
| 		try { | ||||
| 			switch(type) { | ||||
| @ -268,15 +281,23 @@ public class ObjectHelper extends AbstractBlenderHelper { | ||||
| 	 * @return objects transformation relative to its parent | ||||
| 	 */ | ||||
| 	@SuppressWarnings("unchecked") | ||||
| 	public Transform getTransformation(Structure objectStructure) { | ||||
| 	public Transform getTransformation(Structure objectStructure, DataRepository dataRepository) { | ||||
| 		//these are transformations in global space | ||||
| 		DynamicArray<Number> loc = (DynamicArray<Number>)objectStructure.getFieldValue("loc"); | ||||
| 		DynamicArray<Number> size = (DynamicArray<Number>)objectStructure.getFieldValue("size"); | ||||
| 		DynamicArray<Number> rot = (DynamicArray<Number>)objectStructure.getFieldValue("rot"); | ||||
| 
 | ||||
| 		//load parent inverse matrix | ||||
| 		Pointer parent = (Pointer) objectStructure.getFieldValue("parent"); | ||||
| 		Matrix4f parentInv = parent.isNull() ? Matrix4f.IDENTITY : this.getMatrix(objectStructure, "parentinv"); | ||||
| 		Pointer pParent = (Pointer) objectStructure.getFieldValue("parent"); | ||||
| 		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) | ||||
| 		Matrix4f globalMatrix = new Matrix4f(); | ||||
| @ -296,7 +317,7 @@ public class ObjectHelper extends AbstractBlenderHelper { | ||||
| 									  size.get(2).floatValue() * scaleZ); | ||||
| 		 | ||||
| 		//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; | ||||
| 			translation.y = translation.z; | ||||
| 			translation.z = -y; | ||||
| @ -343,4 +364,11 @@ public class ObjectHelper extends AbstractBlenderHelper { | ||||
| 	public void clearState() { | ||||
| 		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; | ||||
| 	} | ||||
| 	 | ||||
| 	@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.TextureKey; | ||||
| import com.jme3.asset.BlenderKey.FeaturesToLoad; | ||||
| import com.jme3.math.FastMath; | ||||
| import com.jme3.scene.plugins.blender.data.FileBlockHeader; | ||||
| import com.jme3.scene.plugins.blender.data.Structure; | ||||
| @ -1779,6 +1780,11 @@ public class TextureHelper extends AbstractBlenderHelper { | ||||
| 			return result; | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	@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 | ||||
|  | ||||
| @ -139,20 +139,21 @@ public abstract class AbstractInfluenceFunction { | ||||
|      * @throws BlenderFileException this exception is thrown if the blend file is somehow corrupted | ||||
|      */ | ||||
|     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 | ||||
|     	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"); | ||||
|     	String subtargetName = subtarget==null ? null : subtarget.toString(); | ||||
|         if (subtargetName!=null && subtargetName.length() > 0) { | ||||
|         	//TODO: what if it is not yet loaded ??? | ||||
|             return dataRepository.getLoadedFeature(subtargetName, loadedFeatureDataType); | ||||
|             result = dataRepository.getLoadedFeature(subtargetName, loadedFeatureDataType); | ||||
|         } | ||||
|         //and now use the target | ||||
|         Long targetOMA = ((Pointer) constraint.getData().getFieldValue("target")).getOldMemoryAddress(); | ||||
|         Structure objectStructure = dataRepository.getFileBlock(targetOMA).getStructure(dataRepository); | ||||
|         return objectHelper.toObject(objectStructure, dataRepository); | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
| @ -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; | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * 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; | ||||
| 
 | ||||
| import java.util.List; | ||||
| import java.util.logging.Logger; | ||||
| 
 | ||||
| import com.jme3.asset.BlenderKey.FeaturesToLoad; | ||||
| 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> { | ||||
| 
 | ||||
|     private static final Logger LOGGER = Logger.getLogger(JmeConverter.class.getName()); | ||||
|     private final DataRepository dataRepository; | ||||
| 
 | ||||
|     /** | ||||
| @ -104,46 +102,47 @@ public class JmeConverter implements BlenderConverter<Node, Camera, Light, Objec | ||||
| 
 | ||||
|     @Override | ||||
|     public Camera toCamera(Structure structure) throws BlenderFileException { | ||||
|         if ((dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.CAMERAS) == 0) { | ||||
|             return null; | ||||
|     	CameraHelper cameraHelper = dataRepository.getHelper(CameraHelper.class); | ||||
|         if (cameraHelper.shouldBeLoaded(structure, dataRepository)) { | ||||
|         	return cameraHelper.toCamera(structure); | ||||
|         } | ||||
|         CameraHelper cameraHelper = dataRepository.getHelper(CameraHelper.class); | ||||
|         return cameraHelper.toCamera(structure); | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public Light toLight(Structure structure) throws BlenderFileException { | ||||
|         if ((dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.LIGHTS) == 0) { | ||||
|             return null; | ||||
|     	LightHelper lightHelper = dataRepository.getHelper(LightHelper.class); | ||||
|         if (lightHelper.shouldBeLoaded(structure, dataRepository)) { | ||||
|             return lightHelper.toLight(structure, dataRepository); | ||||
|         } | ||||
|         LightHelper lightHelper = dataRepository.getHelper(LightHelper.class); | ||||
|         return lightHelper.toLight(structure, dataRepository); | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     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); | ||||
|         return objectHelper.toObject(structure, dataRepository); | ||||
|         if(objectHelper.shouldBeLoaded(structure, dataRepository)) { | ||||
|         	return objectHelper.toObject(structure, dataRepository); | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public List<Geometry> toMesh(Structure structure) throws BlenderFileException { | ||||
|         MeshHelper meshHelper = dataRepository.getHelper(MeshHelper.class); | ||||
|         return meshHelper.toMesh(structure, dataRepository); | ||||
|         if(meshHelper.shouldBeLoaded(structure, dataRepository)) { | ||||
|         	return meshHelper.toMesh(structure, dataRepository); | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public Material toMaterial(Structure structure) throws BlenderFileException { | ||||
|         if ((dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.MATERIALS) == 0) { | ||||
|             return null; | ||||
|     	MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class); | ||||
|         if (materialHelper.shouldBeLoaded(structure, dataRepository)) { | ||||
|             return materialHelper.toMaterial(structure, dataRepository); | ||||
|         } | ||||
|         MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class); | ||||
|         return materialHelper.toMaterial(structure, dataRepository); | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user