Many changes:
- simplified implementation for bones loading - static bones poses discarded - loading of object animation for blender 2.50+ added (didn't work for these versions before) - several small bugfixes git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9115 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
This commit is contained in:
parent
fb68a176b5
commit
3a84693f68
@ -46,6 +46,7 @@ import com.jme3.asset.AssetManager;
|
|||||||
import com.jme3.asset.BlenderKey;
|
import com.jme3.asset.BlenderKey;
|
||||||
import com.jme3.material.Material;
|
import com.jme3.material.Material;
|
||||||
import com.jme3.math.ColorRGBA;
|
import com.jme3.math.ColorRGBA;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.BoneContext;
|
||||||
import com.jme3.scene.plugins.blender.animations.Ipo;
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
import com.jme3.scene.plugins.blender.constraints.Constraint;
|
import com.jme3.scene.plugins.blender.constraints.Constraint;
|
||||||
import com.jme3.scene.plugins.blender.file.BlenderInputStream;
|
import com.jme3.scene.plugins.blender.file.BlenderInputStream;
|
||||||
@ -112,6 +113,8 @@ public class BlenderContext {
|
|||||||
private Map<Long, Skeleton> skeletons = new HashMap<Long, Skeleton>();
|
private Map<Long, Skeleton> skeletons = new HashMap<Long, Skeleton>();
|
||||||
/** A map of mesh contexts. */
|
/** A map of mesh contexts. */
|
||||||
protected Map<Long, MeshContext> meshContexts = new HashMap<Long, MeshContext>();
|
protected Map<Long, MeshContext> meshContexts = new HashMap<Long, MeshContext>();
|
||||||
|
/** A map of bone contexts. */
|
||||||
|
protected Map<Long, BoneContext> boneContexts = new HashMap<Long, BoneContext>();
|
||||||
/** A map of material contexts. */
|
/** A map of material contexts. */
|
||||||
protected Map<Material, MaterialContext> materialContexts = new HashMap<Material, MaterialContext>();
|
protected Map<Material, MaterialContext> materialContexts = new HashMap<Material, MaterialContext>();
|
||||||
/** A map og helpers that perform loading. */
|
/** A map og helpers that perform loading. */
|
||||||
@ -542,6 +545,31 @@ public class BlenderContext {
|
|||||||
return this.meshContexts.get(meshOMA);
|
return this.meshContexts.get(meshOMA);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method sets the bone context for the given bone old memory address.
|
||||||
|
* If the context is already set it will be replaced.
|
||||||
|
*
|
||||||
|
* @param boneOMA
|
||||||
|
* the bone's old memory address
|
||||||
|
* @param boneContext
|
||||||
|
* the bones's context
|
||||||
|
*/
|
||||||
|
public void setBoneContext(Long boneOMA, BoneContext boneContext) {
|
||||||
|
this.boneContexts.put(boneOMA, boneContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the bone context for the given bone old memory
|
||||||
|
* address. If no context exists then <b>null</b> is returned.
|
||||||
|
*
|
||||||
|
* @param boneOMA
|
||||||
|
* the bone's old memory address
|
||||||
|
* @return bone's context
|
||||||
|
*/
|
||||||
|
public BoneContext getBoneContext(Long boneOMA) {
|
||||||
|
return boneContexts.get(boneOMA);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method sets the material context for the given material. If the
|
* This method sets the material context for the given material. If the
|
||||||
* context is already set it will be replaced.
|
* context is already set it will be replaced.
|
||||||
|
@ -42,44 +42,39 @@ import com.jme3.animation.Bone;
|
|||||||
import com.jme3.animation.BoneTrack;
|
import com.jme3.animation.BoneTrack;
|
||||||
import com.jme3.animation.Skeleton;
|
import com.jme3.animation.Skeleton;
|
||||||
import com.jme3.math.Matrix4f;
|
import com.jme3.math.Matrix4f;
|
||||||
import com.jme3.math.Quaternion;
|
|
||||||
import com.jme3.math.Transform;
|
|
||||||
import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
|
import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
|
||||||
import com.jme3.scene.plugins.blender.BlenderContext;
|
import com.jme3.scene.plugins.blender.BlenderContext;
|
||||||
import com.jme3.scene.plugins.blender.curves.BezierCurve;
|
import com.jme3.scene.plugins.blender.curves.BezierCurve;
|
||||||
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
import com.jme3.scene.plugins.blender.file.BlenderInputStream;
|
|
||||||
import com.jme3.scene.plugins.blender.file.DynamicArray;
|
|
||||||
import com.jme3.scene.plugins.blender.file.FileBlockHeader;
|
|
||||||
import com.jme3.scene.plugins.blender.file.Pointer;
|
import com.jme3.scene.plugins.blender.file.Pointer;
|
||||||
import com.jme3.scene.plugins.blender.file.Structure;
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
import com.jme3.scene.plugins.blender.objects.ObjectHelper;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class defines the methods to calculate certain aspects of animation and armature functionalities.
|
* This class defines the methods to calculate certain aspects of animation and
|
||||||
|
* armature functionalities.
|
||||||
|
*
|
||||||
* @author Marcin Roguski (Kaelthas)
|
* @author Marcin Roguski (Kaelthas)
|
||||||
*/
|
*/
|
||||||
public class ArmatureHelper extends AbstractBlenderHelper {
|
public class ArmatureHelper extends AbstractBlenderHelper {
|
||||||
private static final Logger LOGGER = Logger.getLogger(ArmatureHelper.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(ArmatureHelper.class.getName());
|
||||||
|
|
||||||
/** A map of bones and their old memory addresses. */
|
/** A map of bones and their old memory addresses. */
|
||||||
private Map<Bone, Long> bonesOMAs = new HashMap<Bone, Long>();
|
private Map<Bone, Long> bonesOMAs = new HashMap<Bone, Long>();
|
||||||
/** Bone transforms need to be applied after the model is attached to the skeleton. Otherwise it will have no effect. */
|
|
||||||
private Map<Bone, Transform> boneBindTransforms = new HashMap<Bone, Transform>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor parses the given blender version and stores the result. Some functionalities may differ in
|
* This constructor parses the given blender version and stores the result.
|
||||||
* different blender versions.
|
* Some functionalities may differ in different blender versions.
|
||||||
* @param blenderVersion
|
*
|
||||||
* the version read from the blend file
|
* @param blenderVersion
|
||||||
* @param fixUpAxis
|
* the version read from the blend file
|
||||||
* a variable that indicates if the Y asxis is the UP axis or not
|
* @param fixUpAxis
|
||||||
*/
|
* a variable that indicates if the Y asxis is the UP axis or not
|
||||||
public ArmatureHelper(String blenderVersion, boolean fixUpAxis) {
|
*/
|
||||||
super(blenderVersion, fixUpAxis);
|
public ArmatureHelper(String blenderVersion, boolean fixUpAxis) {
|
||||||
}
|
super(blenderVersion, fixUpAxis);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method builds the object's bones structure.
|
* This method builds the object's bones structure.
|
||||||
*
|
*
|
||||||
* @param boneStructure
|
* @param boneStructure
|
||||||
@ -96,118 +91,60 @@ public class ArmatureHelper extends AbstractBlenderHelper {
|
|||||||
* an exception is thrown when there is problem with the blender
|
* an exception is thrown when there is problem with the blender
|
||||||
* file
|
* file
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
public void buildBones(Structure boneStructure, Bone parent, List<Bone> result, Matrix4f arbt, final Map<Long, Structure> bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
public void buildBones(Structure boneStructure, Bone parent, List<Bone> result, Matrix4f arbt,
|
BoneContext bc = new BoneContext(boneStructure, arbt, bonesPoseChannels, blenderContext);
|
||||||
final Map<Long, Structure> bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException {
|
bc.buildBone(result, bonesOMAs, blenderContext);
|
||||||
String boneName = boneStructure.getFieldValue("name").toString();
|
|
||||||
Long boneOMA = boneStructure.getOldMemoryAddress();
|
|
||||||
Bone bone = new Bone(boneName);
|
|
||||||
this.bonesOMAs.put(bone, boneOMA);
|
|
||||||
blenderContext.addLoadedFeatures(boneStructure.getOldMemoryAddress(), boneName, boneStructure, bone);
|
|
||||||
|
|
||||||
ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
|
|
||||||
Matrix4f boneMatrix = arbt.mult(objectHelper.getMatrix(boneStructure, "arm_mat", true));
|
|
||||||
Pointer pParentStructure = (Pointer) boneStructure.getFieldValue("parent");
|
|
||||||
if(pParentStructure.isNotNull()) {
|
|
||||||
Structure parentStructure = pParentStructure.fetchData(blenderContext.getInputStream()).get(0);
|
|
||||||
Matrix4f parentArmMat = objectHelper.getMatrix(parentStructure, "arm_mat", true);
|
|
||||||
parentArmMat = arbt.mult(parentArmMat).invertLocal();
|
|
||||||
boneMatrix = parentArmMat.multLocal(boneMatrix);
|
|
||||||
}
|
|
||||||
|
|
||||||
Transform baseTransform = new Transform(boneMatrix.toTranslationVector(), boneMatrix.toRotationQuat());
|
|
||||||
baseTransform.setScale(objectHelper.getScale(boneMatrix));
|
|
||||||
bone.setBindTransforms(baseTransform.getTranslation(), baseTransform.getRotation(), baseTransform.getScale());
|
|
||||||
|
|
||||||
// loading poses
|
|
||||||
Structure poseChannel = bonesPoseChannels.get(boneStructure.getOldMemoryAddress());
|
|
||||||
DynamicArray<Number> loc = (DynamicArray<Number>) poseChannel.getFieldValue("loc");
|
|
||||||
DynamicArray<Number> size = (DynamicArray<Number>) poseChannel.getFieldValue("size");
|
|
||||||
DynamicArray<Number> quat = (DynamicArray<Number>) poseChannel.getFieldValue("quat");
|
|
||||||
Transform transform = new Transform();
|
|
||||||
if (blenderContext.getBlenderKey().isFixUpAxis()) {
|
|
||||||
transform.setTranslation(loc.get(0).floatValue(), -loc.get(2).floatValue(), loc.get(1).floatValue());
|
|
||||||
transform.setRotation(new Quaternion(quat.get(1).floatValue(), -quat.get(3).floatValue(), quat.get(2).floatValue(), quat.get(0).floatValue()));
|
|
||||||
transform.setScale(size.get(0).floatValue(), size.get(2).floatValue(), size.get(1).floatValue());
|
|
||||||
} else {
|
|
||||||
transform.setTranslation(loc.get(0).floatValue(), loc.get(1).floatValue(), loc.get(2).floatValue());
|
|
||||||
transform.setRotation(new Quaternion(quat.get(0).floatValue(), quat.get(1).floatValue(), quat.get(2).floatValue(), quat.get(3).floatValue()));
|
|
||||||
transform.setScale(size.get(0).floatValue(), size.get(1).floatValue(), size.get(2).floatValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
this.boneBindTransforms.put(bone, transform);
|
|
||||||
if (parent != null) {
|
|
||||||
parent.addChild(bone);
|
|
||||||
}
|
|
||||||
result.add(bone);
|
|
||||||
List<Structure> childbase = ((Structure) boneStructure.getFieldValue("childbase")).evaluateListBase(blenderContext);
|
|
||||||
for (Structure child : childbase) {
|
|
||||||
this.buildBones(child, bone, result, arbt, bonesPoseChannels, blenderContext);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Transform getLocalTransform(Bone bone) {
|
|
||||||
Transform transform = new Transform(bone.getLocalPosition(), bone.getLocalRotation());
|
|
||||||
transform.setScale(bone.getLocalScale());
|
|
||||||
return transform;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns the old memory address of a bone. If the bone does not exist in the blend file - zero is
|
|
||||||
* returned.
|
|
||||||
* @param bone
|
|
||||||
* the bone whose old memory address we seek
|
|
||||||
* @return the old memory address of the given bone
|
|
||||||
*/
|
|
||||||
public Long getBoneOMA(Bone bone) {
|
|
||||||
Long result = bonesOMAs.get(bone);
|
|
||||||
if (result == null) {
|
|
||||||
result = Long.valueOf(0);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns the bind transform for the specified bone.
|
* This method returns the old memory address of a bone. If the bone does
|
||||||
|
* not exist in the blend file - zero is returned.
|
||||||
|
*
|
||||||
* @param bone
|
* @param bone
|
||||||
* the bone
|
* the bone whose old memory address we seek
|
||||||
* @return bone's bind transform
|
* @return the old memory address of the given bone
|
||||||
*/
|
*/
|
||||||
public Transform getBoneBindTransform(Bone bone) {
|
public Long getBoneOMA(Bone bone) {
|
||||||
return boneBindTransforms.get(bone);
|
Long result = bonesOMAs.get(bone);
|
||||||
}
|
if (result == null) {
|
||||||
|
result = Long.valueOf(0);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns a map where the key is the object's group index that is used by a bone and the key is the
|
* This method returns a map where the key is the object's group index that
|
||||||
* bone index in the armature.
|
* is used by a bone and the key is the bone index in the armature.
|
||||||
* @param defBaseStructure
|
*
|
||||||
* a bPose structure of the object
|
* @param defBaseStructure
|
||||||
* @return bone group-to-index map
|
* a bPose structure of the object
|
||||||
* @throws BlenderFileException
|
* @return bone group-to-index map
|
||||||
* this exception is thrown when the blender file is somehow corrupted
|
* @throws BlenderFileException
|
||||||
*/
|
* this exception is thrown when the blender file is somehow
|
||||||
public Map<Integer, Integer> getGroupToBoneIndexMap(Structure defBaseStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException {
|
* corrupted
|
||||||
Map<Integer, Integer> result = null;
|
*/
|
||||||
if (skeleton.getBoneCount() != 0) {
|
public Map<Integer, Integer> getGroupToBoneIndexMap(Structure defBaseStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
result = new HashMap<Integer, Integer>();
|
Map<Integer, Integer> result = null;
|
||||||
List<Structure> deformGroups = defBaseStructure.evaluateListBase(blenderContext);//bDeformGroup
|
if (skeleton.getBoneCount() != 0) {
|
||||||
int groupIndex = 0;
|
result = new HashMap<Integer, Integer>();
|
||||||
for (Structure deformGroup : deformGroups) {
|
List<Structure> deformGroups = defBaseStructure.evaluateListBase(blenderContext);// bDeformGroup
|
||||||
String deformGroupName = deformGroup.getFieldValue("name").toString();
|
int groupIndex = 0;
|
||||||
Integer boneIndex = this.getBoneIndex(skeleton, deformGroupName);
|
for (Structure deformGroup : deformGroups) {
|
||||||
if (boneIndex != null) {
|
String deformGroupName = deformGroup.getFieldValue("name").toString();
|
||||||
result.put(Integer.valueOf(groupIndex), boneIndex);
|
Integer boneIndex = this.getBoneIndex(skeleton, deformGroupName);
|
||||||
}
|
if (boneIndex != null) {
|
||||||
++groupIndex;
|
result.put(Integer.valueOf(groupIndex), boneIndex);
|
||||||
}
|
}
|
||||||
}
|
++groupIndex;
|
||||||
return result;
|
}
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) {
|
public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method retuns the bone tracks for animation.
|
* This method retuns the bone tracks for animation.
|
||||||
@ -221,16 +158,17 @@ public class ArmatureHelper extends AbstractBlenderHelper {
|
|||||||
* an exception is thrown when there are problems with the blend
|
* an exception is thrown when there are problems with the blend
|
||||||
* file
|
* file
|
||||||
*/
|
*/
|
||||||
public BoneTrack[] getTracks(Structure actionStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException {
|
public BoneTrack[] getTracks(Structure actionStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
if (blenderVersion < 250) {
|
if (blenderVersion < 250) {
|
||||||
return this.getTracks249(actionStructure, skeleton, blenderContext);
|
return this.getTracks249(actionStructure, skeleton, blenderContext);
|
||||||
} else {
|
} else {
|
||||||
return this.getTracks250(actionStructure, skeleton, blenderContext);
|
return this.getTracks250(actionStructure, skeleton, blenderContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method retuns the bone tracks for animation for blender version 2.50 and higher.
|
* This method retuns the bone tracks for animation for blender version 2.50
|
||||||
|
* and higher.
|
||||||
*
|
*
|
||||||
* @param actionStructure
|
* @param actionStructure
|
||||||
* the structure containing the tracks
|
* the structure containing the tracks
|
||||||
@ -241,45 +179,37 @@ public class ArmatureHelper extends AbstractBlenderHelper {
|
|||||||
* an exception is thrown when there are problems with the blend
|
* an exception is thrown when there are problems with the blend
|
||||||
* file
|
* file
|
||||||
*/
|
*/
|
||||||
private BoneTrack[] getTracks250(Structure actionStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException {
|
private BoneTrack[] getTracks250(Structure actionStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
LOGGER.log(Level.INFO, "Getting tracks!");
|
LOGGER.log(Level.INFO, "Getting tracks!");
|
||||||
int fps = blenderContext.getBlenderKey().getFps();
|
IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class);
|
||||||
Structure groups = (Structure) actionStructure.getFieldValue("groups");
|
int fps = blenderContext.getBlenderKey().getFps();
|
||||||
List<Structure> actionGroups = groups.evaluateListBase(blenderContext);//bActionGroup
|
Structure groups = (Structure) actionStructure.getFieldValue("groups");
|
||||||
List<BoneTrack> tracks = new ArrayList<BoneTrack>();
|
List<Structure> actionGroups = groups.evaluateListBase(blenderContext);// bActionGroup
|
||||||
for (Structure actionGroup : actionGroups) {
|
List<BoneTrack> tracks = new ArrayList<BoneTrack>();
|
||||||
String name = actionGroup.getFieldValue("name").toString();
|
for (Structure actionGroup : actionGroups) {
|
||||||
Integer boneIndex = this.getBoneIndex(skeleton, name);
|
String name = actionGroup.getFieldValue("name").toString();
|
||||||
if (boneIndex != null) {
|
int boneIndex = this.getBoneIndex(skeleton, name);
|
||||||
List<Structure> channels = ((Structure) actionGroup.getFieldValue("channels")).evaluateListBase(blenderContext);
|
if (boneIndex >= 0) {
|
||||||
BezierCurve[] bezierCurves = new BezierCurve[channels.size()];
|
List<Structure> channels = ((Structure) actionGroup.getFieldValue("channels")).evaluateListBase(blenderContext);
|
||||||
int channelCounter = 0;
|
BezierCurve[] bezierCurves = new BezierCurve[channels.size()];
|
||||||
for (Structure c : channels) {
|
int channelCounter = 0;
|
||||||
//reading rna path first
|
for (Structure c : channels) {
|
||||||
BlenderInputStream bis = blenderContext.getInputStream();
|
int type = ipoHelper.getCurveType(c, blenderContext);
|
||||||
int currentPosition = bis.getPosition();
|
Pointer pBezTriple = (Pointer) c.getFieldValue("bezt");
|
||||||
Pointer pRnaPath = (Pointer) c.getFieldValue("rna_path");
|
List<Structure> bezTriples = pBezTriple.fetchData(blenderContext.getInputStream());
|
||||||
FileBlockHeader dataFileBlock = blenderContext.getFileBlock(pRnaPath.getOldMemoryAddress());
|
bezierCurves[channelCounter++] = new BezierCurve(type, bezTriples, 2);
|
||||||
bis.setPosition(dataFileBlock.getBlockPosition());
|
}
|
||||||
String rnaPath = bis.readString();
|
|
||||||
bis.setPosition(currentPosition);
|
|
||||||
int arrayIndex = ((Number) c.getFieldValue("array_index")).intValue();
|
|
||||||
int type = this.getCurveType(rnaPath, arrayIndex);
|
|
||||||
|
|
||||||
Pointer pBezTriple = (Pointer) c.getFieldValue("bezt");
|
Ipo ipo = new Ipo(bezierCurves, fixUpAxis);
|
||||||
List<Structure> bezTriples = pBezTriple.fetchData(blenderContext.getInputStream());
|
tracks.add((BoneTrack) ipo.calculateTrack(boneIndex, 0, ipo.getLastFrame(), fps, false));
|
||||||
bezierCurves[channelCounter++] = new BezierCurve(type, bezTriples, 2);
|
}
|
||||||
}
|
}
|
||||||
|
return tracks.toArray(new BoneTrack[tracks.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
Ipo ipo = new Ipo(bezierCurves, fixUpAxis);
|
/**
|
||||||
tracks.add((BoneTrack) ipo.calculateTrack(boneIndex.intValue(), 0, ipo.getLastFrame(), fps));
|
* This method retuns the bone tracks for animation for blender version 2.49
|
||||||
}
|
* (and probably several lower versions too).
|
||||||
}
|
|
||||||
return tracks.toArray(new BoneTrack[tracks.size()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method retuns the bone tracks for animation for blender version 2.49 (and probably several lower versions too).
|
|
||||||
*
|
*
|
||||||
* @param actionStructure
|
* @param actionStructure
|
||||||
* the structure containing the tracks
|
* the structure containing the tracks
|
||||||
@ -290,61 +220,44 @@ public class ArmatureHelper extends AbstractBlenderHelper {
|
|||||||
* an exception is thrown when there are problems with the blend
|
* an exception is thrown when there are problems with the blend
|
||||||
* file
|
* file
|
||||||
*/
|
*/
|
||||||
private BoneTrack[] getTracks249(Structure actionStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException {
|
private BoneTrack[] getTracks249(Structure actionStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
LOGGER.log(Level.INFO, "Getting tracks!");
|
LOGGER.log(Level.INFO, "Getting tracks!");
|
||||||
IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class);
|
IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class);
|
||||||
int fps = blenderContext.getBlenderKey().getFps();
|
int fps = blenderContext.getBlenderKey().getFps();
|
||||||
Structure chanbase = (Structure) actionStructure.getFieldValue("chanbase");
|
Structure chanbase = (Structure) actionStructure.getFieldValue("chanbase");
|
||||||
List<Structure> actionChannels = chanbase.evaluateListBase(blenderContext);//bActionChannel
|
List<Structure> actionChannels = chanbase.evaluateListBase(blenderContext);// bActionChannel
|
||||||
List<BoneTrack> tracks = new ArrayList<BoneTrack>();
|
List<BoneTrack> tracks = new ArrayList<BoneTrack>();
|
||||||
for (Structure bActionChannel : actionChannels) {
|
for (Structure bActionChannel : actionChannels) {
|
||||||
String name = bActionChannel.getFieldValue("name").toString();
|
String name = bActionChannel.getFieldValue("name").toString();
|
||||||
Integer boneIndex = this.getBoneIndex(skeleton, name);
|
int boneIndex = this.getBoneIndex(skeleton, name);
|
||||||
if (boneIndex != null && boneIndex.intValue() >= 0) {
|
if (boneIndex >= 0) {
|
||||||
Pointer p = (Pointer) bActionChannel.getFieldValue("ipo");
|
Pointer p = (Pointer) bActionChannel.getFieldValue("ipo");
|
||||||
if (!p.isNull()) {
|
if (!p.isNull()) {
|
||||||
Structure ipoStructure = p.fetchData(blenderContext.getInputStream()).get(0);
|
Structure ipoStructure = p.fetchData(blenderContext.getInputStream()).get(0);
|
||||||
Ipo ipo = ipoHelper.createIpo(ipoStructure, blenderContext);
|
Ipo ipo = ipoHelper.fromIpoStructure(ipoStructure, blenderContext);
|
||||||
tracks.add((BoneTrack) ipo.calculateTrack(boneIndex.intValue(), 0, ipo.getLastFrame(), fps));
|
tracks.add((BoneTrack) ipo.calculateTrack(boneIndex, 0, ipo.getLastFrame(), fps, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tracks.toArray(new BoneTrack[tracks.size()]);
|
return tracks.toArray(new BoneTrack[tracks.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns the index of the bone in the given skeleton.
|
* This method returns the index of the bone in the given skeleton.
|
||||||
* @param skeleton the skeleton
|
*
|
||||||
* @param boneName the name of the bone
|
* @param skeleton
|
||||||
* @return the index of the bone
|
* the skeleton
|
||||||
*/
|
* @param boneName
|
||||||
private int getBoneIndex(Skeleton skeleton, String boneName) {
|
* the name of the bone
|
||||||
int result = -1;
|
* @return the index of the bone
|
||||||
for(int i=0;i<skeleton.getBoneCount() && result==-1;++i) {
|
*/
|
||||||
if(boneName.equals(skeleton.getBone(i).getName())) {
|
private int getBoneIndex(Skeleton skeleton, String boneName) {
|
||||||
result = i;
|
int result = -1;
|
||||||
}
|
for (int i = 0; i < skeleton.getBoneCount() && result == -1; ++i) {
|
||||||
}
|
if (boneName.equals(skeleton.getBone(i).getName())) {
|
||||||
return result;
|
result = i;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
return result;
|
||||||
* This method parses the information stored inside the curve rna path and returns the proper type
|
}
|
||||||
* of the curve.
|
|
||||||
* @param rnaPath the curve's rna path
|
|
||||||
* @param arrayIndex the array index of the stored data
|
|
||||||
* @return the type of the curve
|
|
||||||
*/
|
|
||||||
protected int getCurveType(String rnaPath, int arrayIndex) {
|
|
||||||
if (rnaPath.endsWith(".location")) {
|
|
||||||
return Ipo.AC_LOC_X + arrayIndex;
|
|
||||||
}
|
|
||||||
if (rnaPath.endsWith(".rotation_quaternion")) {
|
|
||||||
return Ipo.AC_QUAT_W + arrayIndex;
|
|
||||||
}
|
|
||||||
if (rnaPath.endsWith(".scale")) {
|
|
||||||
return Ipo.AC_SIZE_X + arrayIndex;
|
|
||||||
}
|
|
||||||
throw new IllegalStateException("Unknown curve rna path: " + rnaPath);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,204 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.animations;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.jme3.animation.Bone;
|
||||||
|
import com.jme3.math.Matrix4f;
|
||||||
|
import com.jme3.math.Quaternion;
|
||||||
|
import com.jme3.math.Transform;
|
||||||
|
import com.jme3.math.Vector3f;
|
||||||
|
import com.jme3.scene.plugins.blender.BlenderContext;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.DynamicArray;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
import com.jme3.scene.plugins.blender.objects.ObjectHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class holds the basic data that describes a bone.
|
||||||
|
*
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
public class BoneContext {
|
||||||
|
/** The structure of the bone. */
|
||||||
|
private Structure boneStructure;
|
||||||
|
/** Bone's pose channel structure. */
|
||||||
|
private Structure poseChannel;
|
||||||
|
/** Bone's name. */
|
||||||
|
private String boneName;
|
||||||
|
/** This variable indicates if the Y axis should be the UP axis. */
|
||||||
|
private boolean fixUpAxis;
|
||||||
|
/** The bone's armature matrix. */
|
||||||
|
private Matrix4f armatureMatrix;
|
||||||
|
/** The parent context. */
|
||||||
|
private BoneContext parent;
|
||||||
|
/** The children of this context. */
|
||||||
|
private List<BoneContext> children = new ArrayList<BoneContext>();
|
||||||
|
/** Created bone (available after calling 'buildBone' method). */
|
||||||
|
private Bone bone;
|
||||||
|
/** Bone's pose transform (available after calling 'buildBone' method). */
|
||||||
|
private Transform poseTransform = new Transform();
|
||||||
|
/** The bone's rest matrix. */
|
||||||
|
private Matrix4f restMatrix;
|
||||||
|
/** Bone's total inverse transformation. */
|
||||||
|
private Matrix4f inverseTotalTransformation;
|
||||||
|
/** Bone's parent inverse matrix. */
|
||||||
|
private Matrix4f inverseParentMatrix;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor. Creates the basic set of bone's data.
|
||||||
|
*
|
||||||
|
* @param boneStructure
|
||||||
|
* the bone's structure
|
||||||
|
* @param objectToArmatureMatrix
|
||||||
|
* object-to-armature transformation matrix
|
||||||
|
* @param bonesPoseChannels
|
||||||
|
* a map of pose channels for each bone OMA
|
||||||
|
* @param blenderContext
|
||||||
|
* the blender context
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* an exception is thrown when problem with blender data reading
|
||||||
|
* occurs
|
||||||
|
*/
|
||||||
|
public BoneContext(Structure boneStructure, Matrix4f objectToArmatureMatrix, final Map<Long, Structure> bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
|
this(boneStructure, null, objectToArmatureMatrix, bonesPoseChannels, blenderContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor. Creates the basic set of bone's data.
|
||||||
|
*
|
||||||
|
* @param boneStructure
|
||||||
|
* the bone's structure
|
||||||
|
* @param parent
|
||||||
|
* bone's parent (null if the bone is the root bone)
|
||||||
|
* @param objectToArmatureMatrix
|
||||||
|
* object-to-armature transformation matrix
|
||||||
|
* @param bonesPoseChannels
|
||||||
|
* a map of pose channels for each bone OMA
|
||||||
|
* @param blenderContext
|
||||||
|
* the blender context
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* an exception is thrown when problem with blender data reading
|
||||||
|
* occurs
|
||||||
|
*/
|
||||||
|
private BoneContext(Structure boneStructure, BoneContext parent, Matrix4f objectToArmatureMatrix, final Map<Long, Structure> bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
|
this.parent = parent;
|
||||||
|
this.boneStructure = boneStructure;
|
||||||
|
boneName = boneStructure.getFieldValue("name").toString();
|
||||||
|
ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
|
||||||
|
armatureMatrix = objectHelper.getMatrix(boneStructure, "arm_mat", true);
|
||||||
|
|
||||||
|
fixUpAxis = blenderContext.getBlenderKey().isFixUpAxis();
|
||||||
|
this.computeRestMatrix(objectToArmatureMatrix);
|
||||||
|
List<Structure> childbase = ((Structure) boneStructure.getFieldValue("childbase")).evaluateListBase(blenderContext);
|
||||||
|
for (Structure child : childbase) {
|
||||||
|
this.children.add(new BoneContext(child, this, objectToArmatureMatrix, bonesPoseChannels, blenderContext));
|
||||||
|
}
|
||||||
|
|
||||||
|
poseChannel = bonesPoseChannels.get(boneStructure.getOldMemoryAddress());
|
||||||
|
|
||||||
|
blenderContext.setBoneContext(boneStructure.getOldMemoryAddress(), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method computes the rest matrix for the bone.
|
||||||
|
*
|
||||||
|
* @param objectToArmatureMatrix
|
||||||
|
* object-to-armature transformation matrix
|
||||||
|
*/
|
||||||
|
private void computeRestMatrix(Matrix4f objectToArmatureMatrix) {
|
||||||
|
if (parent != null) {
|
||||||
|
inverseParentMatrix = parent.inverseTotalTransformation.clone();
|
||||||
|
} else if (fixUpAxis) {
|
||||||
|
inverseParentMatrix = objectToArmatureMatrix.clone();
|
||||||
|
} else {
|
||||||
|
inverseParentMatrix = Matrix4f.IDENTITY.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
restMatrix = armatureMatrix.clone();
|
||||||
|
inverseTotalTransformation = restMatrix.invert();
|
||||||
|
|
||||||
|
restMatrix = inverseParentMatrix.mult(restMatrix);
|
||||||
|
|
||||||
|
for (BoneContext child : this.children) {
|
||||||
|
child.computeRestMatrix(objectToArmatureMatrix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method computes the pose transform for the bone.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private void computePoseTransform() {
|
||||||
|
DynamicArray<Number> loc = (DynamicArray<Number>) poseChannel.getFieldValue("loc");
|
||||||
|
DynamicArray<Number> size = (DynamicArray<Number>) poseChannel.getFieldValue("size");
|
||||||
|
DynamicArray<Number> quat = (DynamicArray<Number>) poseChannel.getFieldValue("quat");
|
||||||
|
if (fixUpAxis) {
|
||||||
|
poseTransform.setTranslation(loc.get(0).floatValue(), -loc.get(2).floatValue(), loc.get(1).floatValue());
|
||||||
|
poseTransform.setRotation(new Quaternion(quat.get(1).floatValue(), quat.get(3).floatValue(), -quat.get(2).floatValue(), quat.get(0).floatValue()));
|
||||||
|
poseTransform.setScale(size.get(0).floatValue(), size.get(2).floatValue(), size.get(1).floatValue());
|
||||||
|
} else {
|
||||||
|
poseTransform.setTranslation(loc.get(0).floatValue(), loc.get(1).floatValue(), loc.get(2).floatValue());
|
||||||
|
poseTransform.setRotation(new Quaternion(quat.get(0).floatValue(), quat.get(1).floatValue(), quat.get(2).floatValue(), quat.get(3).floatValue()));
|
||||||
|
poseTransform.setScale(size.get(0).floatValue(), size.get(1).floatValue(), size.get(2).floatValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
Transform localTransform = new Transform(bone.getLocalPosition(), bone.getLocalRotation());
|
||||||
|
localTransform.setScale(bone.getLocalScale());
|
||||||
|
localTransform.getTranslation().addLocal(poseTransform.getTranslation());
|
||||||
|
localTransform.getRotation().multLocal(poseTransform.getRotation());
|
||||||
|
localTransform.getScale().multLocal(poseTransform.getScale());
|
||||||
|
|
||||||
|
poseTransform.set(localTransform);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method builds the bone. It recursively builds the bone's children.
|
||||||
|
*
|
||||||
|
* @param bones
|
||||||
|
* a list of bones where the newly created bone will be added
|
||||||
|
* @param boneOMAs
|
||||||
|
* the map between bone and its old memory address
|
||||||
|
* @param blenderContext
|
||||||
|
* the blender context
|
||||||
|
* @return newly created bone
|
||||||
|
*/
|
||||||
|
public Bone buildBone(List<Bone> bones, Map<Bone, Long> boneOMAs, BlenderContext blenderContext) {
|
||||||
|
Long boneOMA = boneStructure.getOldMemoryAddress();
|
||||||
|
bone = new Bone(boneName);
|
||||||
|
bones.add(bone);
|
||||||
|
boneOMAs.put(bone, boneOMA);
|
||||||
|
blenderContext.addLoadedFeatures(boneOMA, boneName, boneStructure, bone);
|
||||||
|
|
||||||
|
Matrix4f pose = this.restMatrix.clone();
|
||||||
|
ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
|
||||||
|
|
||||||
|
Vector3f poseLocation = pose.toTranslationVector();
|
||||||
|
Quaternion rotation = pose.toRotationQuat();
|
||||||
|
Vector3f scale = objectHelper.getScale(pose);
|
||||||
|
|
||||||
|
bone.setBindTransforms(poseLocation, rotation, scale);
|
||||||
|
for (BoneContext child : children) {
|
||||||
|
bone.addChild(child.buildBone(bones, boneOMAs, blenderContext));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.computePoseTransform();
|
||||||
|
|
||||||
|
return bone;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bone's pose transformation
|
||||||
|
*/
|
||||||
|
public Transform getPoseTransform() {
|
||||||
|
return poseTransform;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return built bone (available after calling 'buildBone' method)
|
||||||
|
*/
|
||||||
|
public Bone getBone() {
|
||||||
|
return bone;
|
||||||
|
}
|
||||||
|
}
|
@ -9,209 +9,228 @@ import com.jme3.math.Vector3f;
|
|||||||
import com.jme3.scene.plugins.blender.curves.BezierCurve;
|
import com.jme3.scene.plugins.blender.curves.BezierCurve;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is used to calculate bezier curves value for the given frames. The Ipo (interpolation object) consists
|
* This class is used to calculate bezier curves value for the given frames. The
|
||||||
* of several b-spline curves (connected 3rd degree bezier curves) of a different type.
|
* Ipo (interpolation object) consists of several b-spline curves (connected 3rd
|
||||||
|
* degree bezier curves) of a different type.
|
||||||
|
*
|
||||||
* @author Marcin Roguski
|
* @author Marcin Roguski
|
||||||
*/
|
*/
|
||||||
public class Ipo {
|
public class Ipo {
|
||||||
|
|
||||||
public static final int AC_LOC_X = 1;
|
public static final int AC_LOC_X = 1;
|
||||||
public static final int AC_LOC_Y = 2;
|
public static final int AC_LOC_Y = 2;
|
||||||
public static final int AC_LOC_Z = 3;
|
public static final int AC_LOC_Z = 3;
|
||||||
public static final int OB_ROT_X = 7;
|
public static final int OB_ROT_X = 7;
|
||||||
public static final int OB_ROT_Y = 8;
|
public static final int OB_ROT_Y = 8;
|
||||||
public static final int OB_ROT_Z = 9;
|
public static final int OB_ROT_Z = 9;
|
||||||
public static final int AC_SIZE_X = 13;
|
public static final int AC_SIZE_X = 13;
|
||||||
public static final int AC_SIZE_Y = 14;
|
public static final int AC_SIZE_Y = 14;
|
||||||
public static final int AC_SIZE_Z = 15;
|
public static final int AC_SIZE_Z = 15;
|
||||||
public static final int AC_QUAT_W = 25;
|
public static final int AC_QUAT_W = 25;
|
||||||
public static final int AC_QUAT_X = 26;
|
public static final int AC_QUAT_X = 26;
|
||||||
public static final int AC_QUAT_Y = 27;
|
public static final int AC_QUAT_Y = 27;
|
||||||
public static final int AC_QUAT_Z = 28;
|
public static final int AC_QUAT_Z = 28;
|
||||||
|
|
||||||
/** A list of bezier curves for this interpolation object. */
|
/** A list of bezier curves for this interpolation object. */
|
||||||
private BezierCurve[] bezierCurves;
|
private BezierCurve[] bezierCurves;
|
||||||
/** Each ipo contains one bone track. */
|
/** Each ipo contains one bone track. */
|
||||||
private Track calculatedTrack;
|
private Track calculatedTrack;
|
||||||
/** 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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor. Stores the bezier curves.
|
* Constructor. Stores the bezier curves.
|
||||||
* @param bezierCurves
|
*
|
||||||
* a table of bezier curves
|
* @param bezierCurves
|
||||||
*/
|
* a table of bezier curves
|
||||||
public Ipo(BezierCurve[] bezierCurves, boolean fixUpAxis) {
|
*/
|
||||||
this.bezierCurves = bezierCurves;
|
public Ipo(BezierCurve[] bezierCurves, boolean fixUpAxis) {
|
||||||
this.fixUpAxis = fixUpAxis;
|
this.bezierCurves = bezierCurves;
|
||||||
}
|
this.fixUpAxis = fixUpAxis;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method calculates the ipo value for the first curve.
|
* This method calculates the ipo value for the first curve.
|
||||||
* @param frame
|
*
|
||||||
* the frame for which the value is calculated
|
* @param frame
|
||||||
* @return calculated ipo value
|
* the frame for which the value is calculated
|
||||||
*/
|
* @return calculated ipo value
|
||||||
public float calculateValue(int frame) {
|
*/
|
||||||
return this.calculateValue(frame, 0);
|
public float calculateValue(int frame) {
|
||||||
}
|
return this.calculateValue(frame, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method calculates the ipo value for the curve of the specified index. Make sure you do not exceed the
|
* This method calculates the ipo value for the curve of the specified
|
||||||
* curves amount. Alway chech the amount of curves before calling this method.
|
* index. Make sure you do not exceed the curves amount. Alway chech the
|
||||||
* @param frame
|
* amount of curves before calling this method.
|
||||||
* the frame for which the value is calculated
|
*
|
||||||
* @param curveIndex
|
* @param frame
|
||||||
* the index of the curve
|
* the frame for which the value is calculated
|
||||||
* @return calculated ipo value
|
* @param curveIndex
|
||||||
*/
|
* the index of the curve
|
||||||
public float calculateValue(int frame, int curveIndex) {
|
* @return calculated ipo value
|
||||||
return bezierCurves[curveIndex].evaluate(frame, BezierCurve.Y_VALUE);
|
*/
|
||||||
}
|
public float calculateValue(int frame, int curveIndex) {
|
||||||
|
return bezierCurves[curveIndex].evaluate(frame, BezierCurve.Y_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns the curves amount.
|
* This method returns the curves amount.
|
||||||
* @return the curves amount
|
*
|
||||||
*/
|
* @return the curves amount
|
||||||
public int getCurvesAmount() {
|
*/
|
||||||
return bezierCurves.length;
|
public int getCurvesAmount() {
|
||||||
}
|
return bezierCurves.length;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns the frame where last bezier triple center point of the specified bezier curve is located.
|
* This method returns the frame where last bezier triple center point of
|
||||||
* @return the frame number of the last defined bezier triple point for the specified ipo
|
* the specified bezier curve is located.
|
||||||
*/
|
*
|
||||||
public int getLastFrame() {
|
* @return the frame number of the last defined bezier triple point for the
|
||||||
int result = 1;
|
* specified ipo
|
||||||
for (int i = 0; i < bezierCurves.length; ++i) {
|
*/
|
||||||
int tempResult = bezierCurves[i].getLastFrame();
|
public int getLastFrame() {
|
||||||
if (tempResult > result) {
|
int result = 1;
|
||||||
result = tempResult;
|
for (int i = 0; i < bezierCurves.length; ++i) {
|
||||||
}
|
int tempResult = bezierCurves[i].getLastFrame();
|
||||||
}
|
if (tempResult > result) {
|
||||||
return result;
|
result = tempResult;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method calculates the value of the curves as a bone track between the specified frames.
|
* This method calculates the value of the curves as a bone track between
|
||||||
* @param targetIndex
|
* the specified frames.
|
||||||
* the index of the target for which the method calculates the tracks
|
*
|
||||||
* IMPORTANT! Aet to -1 (or any negative number) if you want to load spatial animation.
|
* @param targetIndex
|
||||||
* @param startFrame
|
* the index of the target for which the method calculates the
|
||||||
* the firs frame of tracks (inclusive)
|
* tracks IMPORTANT! Aet to -1 (or any negative number) if you
|
||||||
* @param stopFrame
|
* want to load spatial animation.
|
||||||
* the last frame of the tracks (inclusive)
|
* @param startFrame
|
||||||
* @param fps
|
* the firs frame of tracks (inclusive)
|
||||||
* frame rate (frames per second)
|
* @param stopFrame
|
||||||
* @return bone track for the specified bone
|
* the last frame of the tracks (inclusive)
|
||||||
*/
|
* @param fps
|
||||||
public Track calculateTrack(int targetIndex, int startFrame, int stopFrame, int fps) {
|
* frame rate (frames per second)
|
||||||
if(calculatedTrack == null) {
|
* @param spatialTrack
|
||||||
//preparing data for track
|
* this flag indicates if the track belongs to a spatial or to a
|
||||||
int framesAmount = stopFrame - startFrame;
|
* bone; the diference is important because it appears that bones
|
||||||
float start = (startFrame - 1.0f) / fps;
|
* in blender have the same type of coordinate system (Y as UP)
|
||||||
float timeBetweenFrames = 1.0f / fps;
|
* as jme while other features have different one (Z is UP)
|
||||||
|
* @return bone track for the specified bone
|
||||||
|
*/
|
||||||
|
public Track calculateTrack(int targetIndex, int startFrame, int stopFrame, int fps, boolean spatialTrack) {
|
||||||
|
if (calculatedTrack == null) {
|
||||||
|
// preparing data for track
|
||||||
|
int framesAmount = stopFrame - startFrame;
|
||||||
|
float start = (startFrame - 1.0f) / fps;
|
||||||
|
float timeBetweenFrames = 1.0f / fps;
|
||||||
|
|
||||||
float[] times = new float[framesAmount + 1];
|
float[] times = new float[framesAmount + 1];
|
||||||
Vector3f[] translations = new Vector3f[framesAmount + 1];
|
Vector3f[] translations = new Vector3f[framesAmount + 1];
|
||||||
float[] translation = new float[3];
|
float[] translation = new float[3];
|
||||||
Quaternion[] rotations = new Quaternion[framesAmount + 1];
|
Quaternion[] rotations = new Quaternion[framesAmount + 1];
|
||||||
float[] quaternionRotation = new float[4];
|
float[] quaternionRotation = new float[4];
|
||||||
float[] objectRotation = new float[3];
|
float[] objectRotation = new float[3];
|
||||||
boolean bSpatialTrack = targetIndex < 0;
|
Vector3f[] scales = new Vector3f[framesAmount + 1];
|
||||||
Vector3f[] scales = new Vector3f[framesAmount + 1];
|
float[] scale = new float[] { 1.0f, 1.0f, 1.0f };
|
||||||
float[] scale = new float[] {1.0f, 1.0f, 1.0f};
|
float degreeToRadiansFactor = FastMath.DEG_TO_RAD * 10;// the values in blender are divided by 10, so we need to mult it here
|
||||||
float degreeToRadiansFactor = FastMath.DEG_TO_RAD * 10;//the values in blender are divided by 10, so we need to mult it here
|
|
||||||
|
|
||||||
//calculating track data
|
// calculating track data
|
||||||
for (int frame = startFrame; frame <= stopFrame; ++frame) {
|
for (int frame = startFrame; frame <= stopFrame; ++frame) {
|
||||||
int index = frame - startFrame;
|
int index = frame - startFrame;
|
||||||
times[index] = start + (frame - 1) * timeBetweenFrames;
|
times[index] = start + (frame - 1) * timeBetweenFrames;
|
||||||
for (int j = 0; j < bezierCurves.length; ++j) {
|
for (int j = 0; j < bezierCurves.length; ++j) {
|
||||||
double value = bezierCurves[j].evaluate(frame, BezierCurve.Y_VALUE);
|
double value = bezierCurves[j].evaluate(frame, BezierCurve.Y_VALUE);
|
||||||
switch (bezierCurves[j].getType()) {
|
switch (bezierCurves[j].getType()) {
|
||||||
//LOCATION
|
// LOCATION
|
||||||
case AC_LOC_X:
|
case AC_LOC_X:
|
||||||
translation[0] = (float) value;
|
translation[0] = (float) value;
|
||||||
break;
|
break;
|
||||||
case AC_LOC_Y:
|
case AC_LOC_Y:
|
||||||
if(fixUpAxis) {
|
if (fixUpAxis && spatialTrack) {
|
||||||
translation[2] = (float) -value;
|
translation[2] = (float) -value;
|
||||||
} else {
|
} else {
|
||||||
translation[1] = (float) value;
|
translation[1] = (float) value;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AC_LOC_Z:
|
case AC_LOC_Z:
|
||||||
translation[fixUpAxis ? 1 : 2] = (float) value;
|
translation[fixUpAxis && spatialTrack ? 1 : 2] = (float) value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//ROTATION (used with object animation)
|
// ROTATION (used with object animation)
|
||||||
//the value here is in degrees divided by 10 (so in example: 9 = PI/2)
|
// the value here is in degrees divided by 10 (so in
|
||||||
case OB_ROT_X:
|
// example: 9 = PI/2)
|
||||||
objectRotation[0] = (float) value * degreeToRadiansFactor;
|
case OB_ROT_X:
|
||||||
break;
|
objectRotation[0] = (float) value * degreeToRadiansFactor;
|
||||||
case OB_ROT_Y:
|
break;
|
||||||
if(fixUpAxis) {
|
case OB_ROT_Y:
|
||||||
objectRotation[2] = (float) -value * degreeToRadiansFactor;
|
if (fixUpAxis) {
|
||||||
} else {
|
objectRotation[2] = (float) -value * degreeToRadiansFactor;
|
||||||
objectRotation[1] = (float) value * degreeToRadiansFactor;
|
} else {
|
||||||
}
|
objectRotation[1] = (float) value * degreeToRadiansFactor;
|
||||||
break;
|
}
|
||||||
case OB_ROT_Z:
|
break;
|
||||||
objectRotation[fixUpAxis ? 1 : 2] = (float) value * degreeToRadiansFactor;
|
case OB_ROT_Z:
|
||||||
break;
|
objectRotation[fixUpAxis ? 1 : 2] = (float) value * degreeToRadiansFactor;
|
||||||
|
break;
|
||||||
|
|
||||||
//SIZE
|
// SIZE
|
||||||
case AC_SIZE_X:
|
case AC_SIZE_X:
|
||||||
scale[0] = (float) value;
|
scale[0] = (float) value;
|
||||||
break;
|
break;
|
||||||
case AC_SIZE_Y:
|
case AC_SIZE_Y:
|
||||||
if(fixUpAxis) {
|
if (fixUpAxis && spatialTrack) {
|
||||||
scale[2] = (float) value;
|
scale[2] = (float) value;
|
||||||
} else {
|
} else {
|
||||||
scale[1] = (float) value;
|
scale[1] = (float) value;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AC_SIZE_Z:
|
case AC_SIZE_Z:
|
||||||
scale[fixUpAxis ? 1 : 2] = (float) value;
|
scale[fixUpAxis && spatialTrack ? 1 : 2] = (float) value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//QUATERNION ROTATION (used with bone animation)
|
// QUATERNION ROTATION (used with bone animation), dunno
|
||||||
case AC_QUAT_W:
|
// why but here we shouldn't check the
|
||||||
quaternionRotation[3] = (float) value;
|
// spatialTrack flag value
|
||||||
break;
|
case AC_QUAT_W:
|
||||||
case AC_QUAT_X:
|
quaternionRotation[3] = (float) value;
|
||||||
quaternionRotation[0] = (float) value;
|
break;
|
||||||
break;
|
case AC_QUAT_X:
|
||||||
case AC_QUAT_Y:
|
quaternionRotation[0] = (float) value;
|
||||||
if(fixUpAxis) {
|
break;
|
||||||
quaternionRotation[2] = -(float) value;
|
case AC_QUAT_Y:
|
||||||
} else {
|
if (fixUpAxis) {
|
||||||
quaternionRotation[1] = (float) value;
|
quaternionRotation[2] = -(float) value;
|
||||||
}
|
} else {
|
||||||
break;
|
quaternionRotation[1] = (float) value;
|
||||||
case AC_QUAT_Z:
|
}
|
||||||
if(fixUpAxis) {
|
break;
|
||||||
quaternionRotation[1] = (float) value;
|
case AC_QUAT_Z:
|
||||||
} else {
|
if (fixUpAxis) {
|
||||||
quaternionRotation[2] = (float) value;
|
quaternionRotation[1] = (float) value;
|
||||||
}
|
} else {
|
||||||
break;
|
quaternionRotation[2] = (float) value;
|
||||||
default:
|
}
|
||||||
throw new IllegalStateException("Unknown ipo curve type: " + bezierCurves[j].getType());
|
break;
|
||||||
}
|
default:
|
||||||
}
|
throw new IllegalStateException("Unknown ipo curve type: " + bezierCurves[j].getType());
|
||||||
translations[index] = new Vector3f(translation[0], translation[1], translation[2]);
|
}
|
||||||
rotations[index] = bSpatialTrack ? new Quaternion().fromAngles(objectRotation)
|
}
|
||||||
: new Quaternion(quaternionRotation[0], quaternionRotation[1], quaternionRotation[2], quaternionRotation[3]);
|
translations[index] = new Vector3f(translation[0], translation[1], translation[2]);
|
||||||
scales[index] = new Vector3f(scale[0], scale[1], scale[2]);
|
rotations[index] = spatialTrack ? new Quaternion().fromAngles(objectRotation) : new Quaternion(quaternionRotation[0], quaternionRotation[1], quaternionRotation[2], quaternionRotation[3]);
|
||||||
}
|
scales[index] = new Vector3f(scale[0], scale[1], scale[2]);
|
||||||
if(bSpatialTrack) {
|
}
|
||||||
calculatedTrack = new SpatialTrack(times, translations, rotations, scales);
|
if (spatialTrack) {
|
||||||
} else {
|
calculatedTrack = new SpatialTrack(times, translations, rotations, scales);
|
||||||
calculatedTrack = new BoneTrack(targetIndex, times, translations, rotations, scales);
|
} else {
|
||||||
}
|
calculatedTrack = new BoneTrack(targetIndex, times, translations, rotations, scales);
|
||||||
}
|
}
|
||||||
return calculatedTrack;
|
}
|
||||||
}
|
return calculatedTrack;
|
||||||
|
}
|
||||||
}
|
}
|
@ -7,114 +7,193 @@ import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
|
|||||||
import com.jme3.scene.plugins.blender.BlenderContext;
|
import com.jme3.scene.plugins.blender.BlenderContext;
|
||||||
import com.jme3.scene.plugins.blender.curves.BezierCurve;
|
import com.jme3.scene.plugins.blender.curves.BezierCurve;
|
||||||
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.BlenderInputStream;
|
||||||
|
import com.jme3.scene.plugins.blender.file.FileBlockHeader;
|
||||||
import com.jme3.scene.plugins.blender.file.Pointer;
|
import com.jme3.scene.plugins.blender.file.Pointer;
|
||||||
import com.jme3.scene.plugins.blender.file.Structure;
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class helps to compute values from interpolation curves for features like animation or constraint influence. The
|
* This class helps to compute values from interpolation curves for features
|
||||||
* curves are 3rd degree bezier curves.
|
* like animation or constraint influence. The curves are 3rd degree bezier
|
||||||
|
* curves.
|
||||||
|
*
|
||||||
* @author Marcin Roguski
|
* @author Marcin Roguski
|
||||||
*/
|
*/
|
||||||
public class IpoHelper extends AbstractBlenderHelper {
|
public class IpoHelper extends AbstractBlenderHelper {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor parses the given blender version and stores the result. Some functionalities may differ in
|
* This constructor parses the given blender version and stores the result.
|
||||||
* different blender versions.
|
* Some functionalities may differ in different blender versions.
|
||||||
* @param blenderVersion
|
*
|
||||||
* the version read from the blend file
|
* @param blenderVersion
|
||||||
* @param fixUpAxis
|
* the version read from the blend file
|
||||||
* a variable that indicates if the Y asxis is the UP axis or not
|
* @param fixUpAxis
|
||||||
*/
|
* a variable that indicates if the Y asxis is the UP axis or not
|
||||||
public IpoHelper(String blenderVersion, boolean fixUpAxis) {
|
*/
|
||||||
super(blenderVersion, fixUpAxis);
|
public IpoHelper(String blenderVersion, boolean fixUpAxis) {
|
||||||
}
|
super(blenderVersion, fixUpAxis);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method creates an ipo object used for interpolation calculations.
|
* This method creates an ipo object used for interpolation calculations.
|
||||||
* @param ipoStructure
|
*
|
||||||
* the structure with ipo definition
|
* @param ipoStructure
|
||||||
* @param blenderContext
|
* the structure with ipo definition
|
||||||
* the blender context
|
* @param blenderContext
|
||||||
* @return the ipo object
|
* the blender context
|
||||||
* @throws BlenderFileException
|
* @return the ipo object
|
||||||
* this exception is thrown when the blender file is somehow corrupted
|
* @throws BlenderFileException
|
||||||
*/
|
* this exception is thrown when the blender file is somehow
|
||||||
public Ipo createIpo(Structure ipoStructure, BlenderContext blenderContext) throws BlenderFileException {
|
* corrupted
|
||||||
Structure curvebase = (Structure) ipoStructure.getFieldValue("curve");
|
*/
|
||||||
|
public Ipo fromIpoStructure(Structure ipoStructure, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
|
Structure curvebase = (Structure) ipoStructure.getFieldValue("curve");
|
||||||
|
|
||||||
//preparing bezier curves
|
// preparing bezier curves
|
||||||
Ipo result = null;
|
Ipo result = null;
|
||||||
List<Structure> curves = curvebase.evaluateListBase(blenderContext);//IpoCurve
|
List<Structure> curves = curvebase.evaluateListBase(blenderContext);// IpoCurve
|
||||||
if (curves.size() > 0) {
|
if (curves.size() > 0) {
|
||||||
BezierCurve[] bezierCurves = new BezierCurve[curves.size()];
|
BezierCurve[] bezierCurves = new BezierCurve[curves.size()];
|
||||||
int frame = 0;
|
int frame = 0;
|
||||||
for (Structure curve : curves) {
|
for (Structure curve : curves) {
|
||||||
Pointer pBezTriple = (Pointer) curve.getFieldValue("bezt");
|
Pointer pBezTriple = (Pointer) curve.getFieldValue("bezt");
|
||||||
List<Structure> bezTriples = pBezTriple.fetchData(blenderContext.getInputStream());
|
List<Structure> bezTriples = pBezTriple.fetchData(blenderContext.getInputStream());
|
||||||
int type = ((Number) curve.getFieldValue("adrcode")).intValue();
|
int type = ((Number) curve.getFieldValue("adrcode")).intValue();
|
||||||
bezierCurves[frame++] = new BezierCurve(type, bezTriples, 2);
|
bezierCurves[frame++] = new BezierCurve(type, bezTriples, 2);
|
||||||
}
|
}
|
||||||
curves.clear();
|
curves.clear();
|
||||||
result = new Ipo(bezierCurves, fixUpAxis);
|
result = new Ipo(bezierCurves, fixUpAxis);
|
||||||
blenderContext.addLoadedFeatures(ipoStructure.getOldMemoryAddress(), ipoStructure.getName(), ipoStructure, result);
|
blenderContext.addLoadedFeatures(ipoStructure.getOldMemoryAddress(), ipoStructure.getName(), ipoStructure, result);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method creates an ipo with only a single value. No track type is specified so do not use it for calculating
|
* This method creates an ipo object used for interpolation calculations. It
|
||||||
* tracks.
|
* should be called for blender version 2.50 and higher.
|
||||||
* @param constValue
|
*
|
||||||
* the value of this ipo
|
* @param actionStructure
|
||||||
* @return constant ipo
|
* the structure with action definition
|
||||||
*/
|
* @param blenderContext
|
||||||
public Ipo createIpo(float constValue) {
|
* the blender context
|
||||||
return new ConstIpo(constValue);
|
* @return the ipo object
|
||||||
}
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
public Ipo fromAction(Structure actionStructure, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
|
Ipo result = null;
|
||||||
|
List<Structure> curves = ((Structure) actionStructure.getFieldValue("curves")).evaluateListBase(blenderContext);// FCurve
|
||||||
|
if (curves.size() > 0) {
|
||||||
|
BezierCurve[] bezierCurves = new BezierCurve[curves.size()];
|
||||||
|
int frame = 0;
|
||||||
|
for (Structure curve : curves) {
|
||||||
|
Pointer pBezTriple = (Pointer) curve.getFieldValue("bezt");
|
||||||
|
List<Structure> bezTriples = pBezTriple.fetchData(blenderContext.getInputStream());
|
||||||
|
int type = this.getCurveType(curve, blenderContext);
|
||||||
|
bezierCurves[frame++] = new BezierCurve(type, bezTriples, 2);
|
||||||
|
}
|
||||||
|
curves.clear();
|
||||||
|
result = new Ipo(bezierCurves, fixUpAxis);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) {
|
* This method returns the type of the ipo curve.
|
||||||
return true;
|
*
|
||||||
}
|
* @param structure
|
||||||
|
* the structure must contain the 'rna_path' field and
|
||||||
|
* 'array_index' field (the type is not important here)
|
||||||
|
* @param blenderContext
|
||||||
|
* the blender context
|
||||||
|
* @return the type of the curve
|
||||||
|
*/
|
||||||
|
public int getCurveType(Structure structure, BlenderContext blenderContext) {
|
||||||
|
// reading rna path first
|
||||||
|
BlenderInputStream bis = blenderContext.getInputStream();
|
||||||
|
int currentPosition = bis.getPosition();
|
||||||
|
Pointer pRnaPath = (Pointer) structure.getFieldValue("rna_path");
|
||||||
|
FileBlockHeader dataFileBlock = blenderContext.getFileBlock(pRnaPath.getOldMemoryAddress());
|
||||||
|
bis.setPosition(dataFileBlock.getBlockPosition());
|
||||||
|
String rnaPath = bis.readString();
|
||||||
|
bis.setPosition(currentPosition);
|
||||||
|
int arrayIndex = ((Number) structure.getFieldValue("array_index")).intValue();
|
||||||
|
|
||||||
/**
|
// determining the curve type
|
||||||
* Ipo constant curve. This is a curve with only one value and no specified type. This type of ipo cannot be used to
|
if (rnaPath.endsWith("location")) {
|
||||||
* calculate tracks. It should only be used to calculate single value for a given frame.
|
return Ipo.AC_LOC_X + arrayIndex;
|
||||||
* @author Marcin Roguski
|
}
|
||||||
*/
|
if (rnaPath.endsWith("rotation_quaternion")) {
|
||||||
private class ConstIpo extends Ipo {
|
return Ipo.AC_QUAT_W + arrayIndex;
|
||||||
|
}
|
||||||
|
if (rnaPath.endsWith("scale")) {
|
||||||
|
return Ipo.AC_SIZE_X + arrayIndex;
|
||||||
|
}
|
||||||
|
if (rnaPath.endsWith("rotation")) {
|
||||||
|
return Ipo.OB_ROT_X + arrayIndex;
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("Unknown curve rna path: " + rnaPath);
|
||||||
|
}
|
||||||
|
|
||||||
/** The constant value of this ipo. */
|
/**
|
||||||
private float constValue;
|
* This method creates an ipo with only a single value. No track type is
|
||||||
|
* specified so do not use it for calculating tracks.
|
||||||
|
*
|
||||||
|
* @param constValue
|
||||||
|
* the value of this ipo
|
||||||
|
* @return constant ipo
|
||||||
|
*/
|
||||||
|
public Ipo fromValue(float constValue) {
|
||||||
|
return new ConstIpo(constValue);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Constructor. Stores the constant value of this ipo.
|
public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) {
|
||||||
* @param constValue
|
return true;
|
||||||
* the constant value of this ipo
|
}
|
||||||
*/
|
|
||||||
public ConstIpo(float constValue) {
|
|
||||||
super(null, false);
|
|
||||||
this.constValue = constValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public float calculateValue(int frame) {
|
* Ipo constant curve. This is a curve with only one value and no specified
|
||||||
return constValue;
|
* type. This type of ipo cannot be used to calculate tracks. It should only
|
||||||
}
|
* be used to calculate single value for a given frame.
|
||||||
|
*
|
||||||
|
* @author Marcin Roguski
|
||||||
|
*/
|
||||||
|
private class ConstIpo extends Ipo {
|
||||||
|
|
||||||
@Override
|
/** The constant value of this ipo. */
|
||||||
public float calculateValue(int frame, int curveIndex) {
|
private float constValue;
|
||||||
return constValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public int getCurvesAmount() {
|
* Constructor. Stores the constant value of this ipo.
|
||||||
return 0;
|
*
|
||||||
}
|
* @param constValue
|
||||||
|
* the constant value of this ipo
|
||||||
|
*/
|
||||||
|
public ConstIpo(float constValue) {
|
||||||
|
super(null, false);
|
||||||
|
this.constValue = constValue;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BoneTrack calculateTrack(int boneIndex, int startFrame, int stopFrame, int fps) {
|
public float calculateValue(int frame) {
|
||||||
throw new IllegalStateException("Constatnt ipo object cannot be used for calculating bone tracks!");
|
return constValue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
|
public float calculateValue(int frame, int curveIndex) {
|
||||||
|
return constValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCurvesAmount() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BoneTrack calculateTrack(int boneIndex, int startFrame, int stopFrame, int fps, boolean boneTrack) {
|
||||||
|
throw new IllegalStateException("Constatnt ipo object cannot be used for calculating bone tracks!");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,9 +20,6 @@ import com.jme3.scene.plugins.blender.objects.ObjectHelper;
|
|||||||
* @author Marcin Roguski (Kaelthas)
|
* @author Marcin Roguski (Kaelthas)
|
||||||
*/
|
*/
|
||||||
public abstract class Constraint {
|
public abstract class Constraint {
|
||||||
public static final int BAKE_DYNAMIC = 0x01;
|
|
||||||
public static final int BAKE_STATIC = 0x02;
|
|
||||||
|
|
||||||
/** The name of this constraint. */
|
/** The name of this constraint. */
|
||||||
protected final String name;
|
protected final String name;
|
||||||
/** The constraint's owner. */
|
/** The constraint's owner. */
|
||||||
@ -79,32 +76,19 @@ public abstract class Constraint {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This method bakes the required sontraints into its owner.
|
* This method bakes the required sontraints into its owner.
|
||||||
* @param bakeFlag the bake type flag support the following values:
|
|
||||||
* <li> BAKE_DYNAMIC - bake animation's constraints
|
|
||||||
* <li> BAKE_STATIC - bake static constraints
|
|
||||||
*/
|
*/
|
||||||
public void bake(int bakeFlag) {
|
public void bake() {
|
||||||
this.owner.update();
|
this.owner.update();
|
||||||
if(this.target != null) {
|
if(this.target != null) {
|
||||||
this.target.update();
|
this.target.update();
|
||||||
}
|
}
|
||||||
if((bakeFlag & BAKE_DYNAMIC) != 0) {
|
this.bakeConstraint();
|
||||||
this.bakeDynamic();
|
|
||||||
}
|
|
||||||
if((bakeFlag & BAKE_STATIC) != 0) {
|
|
||||||
this.bakeStatic();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bake the animation's constraints into its owner.
|
* Bake the animation's constraints into its owner.
|
||||||
*/
|
*/
|
||||||
protected abstract void bakeDynamic();
|
protected abstract void bakeConstraint();
|
||||||
|
|
||||||
/**
|
|
||||||
* Bake the static constraints into its owner.
|
|
||||||
*/
|
|
||||||
protected abstract void bakeStatic();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns the bone traces for the bone that is affected by the given constraint.
|
* This method returns the bone traces for the bone that is affected by the given constraint.
|
||||||
|
@ -35,13 +35,7 @@ import java.util.logging.Logger;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void bakeDynamic() {
|
protected void bakeConstraint() {
|
||||||
// TODO: implement 'Action' constraint
|
|
||||||
LOGGER.log(Level.WARNING, "'Action' constraint NOT implemented!");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void bakeStatic() {
|
|
||||||
// TODO: implement 'Action' constraint
|
// TODO: implement 'Action' constraint
|
||||||
LOGGER.log(Level.WARNING, "'Action' constraint NOT implemented!");
|
LOGGER.log(Level.WARNING, "'Action' constraint NOT implemented!");
|
||||||
}
|
}
|
||||||
|
@ -35,13 +35,7 @@ import java.util.logging.Logger;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void bakeDynamic() {
|
protected void bakeConstraint() {
|
||||||
// TODO: implement ChildOf constraint
|
|
||||||
LOGGER.log(Level.WARNING, "ChildOf constraint NOT implemented!");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void bakeStatic() {
|
|
||||||
// TODO: implement ChildOf constraint
|
// TODO: implement ChildOf constraint
|
||||||
LOGGER.log(Level.WARNING, "ChildOf constraint NOT implemented!");
|
LOGGER.log(Level.WARNING, "ChildOf constraint NOT implemented!");
|
||||||
}
|
}
|
||||||
|
@ -36,13 +36,7 @@ import java.util.logging.Logger;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void bakeDynamic() {
|
protected void bakeConstraint() {
|
||||||
//TODO: implement when curves are implemented
|
|
||||||
LOGGER.log(Level.INFO, "'Clamp to' not yet implemented! Curves not yet implemented!", name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void bakeStatic() {
|
|
||||||
//TODO: implement when curves are implemented
|
//TODO: implement when curves are implemented
|
||||||
LOGGER.log(Level.INFO, "'Clamp to' not yet implemented! Curves not yet implemented!", name);
|
LOGGER.log(Level.INFO, "'Clamp to' not yet implemented! Curves not yet implemented!", name);
|
||||||
}
|
}
|
||||||
|
@ -36,13 +36,7 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void bakeDynamic() {
|
protected void bakeConstraint() {
|
||||||
// TODO Auto-generated method stub
|
|
||||||
LOGGER.log(Level.WARNING, "'Damp Track' constraint NOT implemented!");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void bakeStatic() {
|
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
LOGGER.log(Level.WARNING, "'Damp Track' constraint NOT implemented!");
|
LOGGER.log(Level.WARNING, "'Damp Track' constraint NOT implemented!");
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package com.jme3.scene.plugins.blender.constraints;
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
import com.jme3.animation.Animation;
|
import com.jme3.animation.Animation;
|
||||||
import com.jme3.animation.Bone;
|
|
||||||
import com.jme3.math.Matrix4f;
|
import com.jme3.math.Matrix4f;
|
||||||
import com.jme3.math.Vector3f;
|
import com.jme3.math.Vector3f;
|
||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
@ -47,10 +46,10 @@ import com.jme3.scene.plugins.ogre.AnimData;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void bakeDynamic() {
|
protected void bakeConstraint() {
|
||||||
|
Object owner = this.owner.getObject();
|
||||||
AnimData animData = blenderContext.getAnimData(this.owner.getOma());
|
AnimData animData = blenderContext.getAnimData(this.owner.getOma());
|
||||||
if(animData != null) {
|
if(animData != null) {
|
||||||
Object owner = this.owner.getObject();
|
|
||||||
if(owner instanceof Spatial) {
|
if(owner instanceof Spatial) {
|
||||||
Vector3f targetLocation = ((Spatial) owner).getWorldTranslation();
|
Vector3f targetLocation = ((Spatial) owner).getWorldTranslation();
|
||||||
for(Animation animation : animData.anims) {
|
for(Animation animation : animData.anims) {
|
||||||
@ -66,22 +65,17 @@ import com.jme3.scene.plugins.ogre.AnimData;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
// apply static constraint only to spatials
|
||||||
protected void bakeStatic() {
|
|
||||||
Matrix4f targetWorldMatrix = target.getWorldTransformMatrix();
|
|
||||||
Vector3f targetLocation = targetWorldMatrix.toTranslationVector();
|
|
||||||
Matrix4f m = owner.getParentWorldTransformMatrix();
|
|
||||||
m.invertLocal();
|
|
||||||
Matrix4f ownerWorldMatrix = owner.getWorldTransformMatrix();
|
|
||||||
Vector3f ownerLocation = ownerWorldMatrix.toTranslationVector();
|
|
||||||
this.distLimit(ownerLocation, targetLocation, ipo.calculateValue(0));
|
|
||||||
Object owner = this.owner.getObject();
|
|
||||||
if(owner instanceof Spatial) {
|
if(owner instanceof Spatial) {
|
||||||
|
Matrix4f targetWorldMatrix = target.getWorldTransformMatrix();
|
||||||
|
Vector3f targetLocation = targetWorldMatrix.toTranslationVector();
|
||||||
|
Matrix4f m = this.owner.getParentWorldTransformMatrix();
|
||||||
|
m.invertLocal();
|
||||||
|
Matrix4f ownerWorldMatrix = this.owner.getWorldTransformMatrix();
|
||||||
|
Vector3f ownerLocation = ownerWorldMatrix.toTranslationVector();
|
||||||
|
this.distLimit(ownerLocation, targetLocation, ipo.calculateValue(0));
|
||||||
((Spatial) owner).setLocalTranslation(m.mult(ownerLocation));
|
((Spatial) owner).setLocalTranslation(m.mult(ownerLocation));
|
||||||
} else {
|
|
||||||
((Bone) owner).setBindTransforms(m.mult(ownerLocation), ((Bone) owner).getLocalRotation(), ((Bone) owner).getLocalScale());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,13 +35,7 @@ import java.util.logging.Logger;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void bakeDynamic() {
|
protected void bakeConstraint() {
|
||||||
//TODO: implement when curves are implemented
|
|
||||||
LOGGER.log(Level.INFO, "'Follow path' not implemented! Curves not yet implemented!");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void bakeStatic() {
|
|
||||||
//TODO: implement when curves are implemented
|
//TODO: implement when curves are implemented
|
||||||
LOGGER.log(Level.INFO, "'Follow path' not implemented! Curves not yet implemented!");
|
LOGGER.log(Level.INFO, "'Follow path' not implemented! Curves not yet implemented!");
|
||||||
}
|
}
|
||||||
|
@ -93,7 +93,7 @@ public class ConstraintHelper extends AbstractBlenderHelper {
|
|||||||
Pointer pIpo = (Pointer) constraintChannel.getFieldValue("ipo");
|
Pointer pIpo = (Pointer) constraintChannel.getFieldValue("ipo");
|
||||||
if (pIpo.isNotNull()) {
|
if (pIpo.isNotNull()) {
|
||||||
String constraintName = constraintChannel.getFieldValue("name").toString();
|
String constraintName = constraintChannel.getFieldValue("name").toString();
|
||||||
Ipo ipo = ipoHelper.createIpo(pIpo.fetchData(blenderContext.getInputStream()).get(0), blenderContext);
|
Ipo ipo = ipoHelper.fromIpoStructure(pIpo.fetchData(blenderContext.getInputStream()).get(0), blenderContext);
|
||||||
ipos.put(constraintName, ipo);
|
ipos.put(constraintName, ipo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,7 +120,7 @@ public class ConstraintHelper extends AbstractBlenderHelper {
|
|||||||
Ipo ipo = ipoMap==null ? null : ipoMap.get(constraintName);
|
Ipo ipo = ipoMap==null ? null : ipoMap.get(constraintName);
|
||||||
if (ipo == null) {
|
if (ipo == null) {
|
||||||
float enforce = ((Number) constraint.getFieldValue("enforce")).floatValue();
|
float enforce = ((Number) constraint.getFieldValue("enforce")).floatValue();
|
||||||
ipo = ipoHelper.createIpo(enforce);
|
ipo = ipoHelper.fromValue(enforce);
|
||||||
}
|
}
|
||||||
constraintsList.add(this.createConstraint(constraint, boneOMA, ipo, blenderContext));
|
constraintsList.add(this.createConstraint(constraint, boneOMA, ipo, blenderContext));
|
||||||
}
|
}
|
||||||
@ -140,7 +140,7 @@ public class ConstraintHelper extends AbstractBlenderHelper {
|
|||||||
Ipo ipo = objectConstraintsIpos!=null ? objectConstraintsIpos.get(constraintName) : null;
|
Ipo ipo = objectConstraintsIpos!=null ? objectConstraintsIpos.get(constraintName) : null;
|
||||||
if (ipo == null) {
|
if (ipo == null) {
|
||||||
float enforce = ((Number) constraint.getFieldValue("enforce")).floatValue();
|
float enforce = ((Number) constraint.getFieldValue("enforce")).floatValue();
|
||||||
ipo = ipoHelper.createIpo(enforce);
|
ipo = ipoHelper.fromValue(enforce);
|
||||||
}
|
}
|
||||||
constraintsList.add(this.createConstraint(constraint, objectStructure.getOldMemoryAddress(), ipo, blenderContext));
|
constraintsList.add(this.createConstraint(constraint, objectStructure.getOldMemoryAddress(), ipo, blenderContext));
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ import java.util.logging.Logger;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void bakeDynamic() {
|
protected void bakeConstraint() {
|
||||||
// try {
|
// try {
|
||||||
// IK solver is only attached to bones
|
// IK solver is only attached to bones
|
||||||
// Bone ownerBone = (Bone) blenderContext.getLoadedFeature(ownerOMA, LoadedFeatureDataType.LOADED_FEATURE);
|
// Bone ownerBone = (Bone) blenderContext.getLoadedFeature(ownerOMA, LoadedFeatureDataType.LOADED_FEATURE);
|
||||||
@ -127,12 +127,6 @@ import java.util.logging.Logger;
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void bakeStatic() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns bones used for rotation calculations.
|
* This method returns bones used for rotation calculations.
|
||||||
* @param bone
|
* @param bone
|
||||||
|
@ -3,6 +3,7 @@ package com.jme3.scene.plugins.blender.constraints;
|
|||||||
import com.jme3.animation.Animation;
|
import com.jme3.animation.Animation;
|
||||||
import com.jme3.math.Transform;
|
import com.jme3.math.Transform;
|
||||||
import com.jme3.math.Vector3f;
|
import com.jme3.math.Vector3f;
|
||||||
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.scene.plugins.blender.BlenderContext;
|
import com.jme3.scene.plugins.blender.BlenderContext;
|
||||||
import com.jme3.scene.plugins.blender.animations.Ipo;
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
@ -61,10 +62,10 @@ import com.jme3.scene.plugins.ogre.AnimData;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void bakeDynamic() {
|
protected void bakeConstraint() {
|
||||||
AnimData animData = blenderContext.getAnimData(owner.getOma());
|
Object owner = this.owner.getObject();
|
||||||
|
AnimData animData = blenderContext.getAnimData(this.owner.getOma());
|
||||||
if(animData != null) {
|
if(animData != null) {
|
||||||
Object owner = this.owner.getObject();
|
|
||||||
Transform targetTransform = this.target.getTransform();
|
Transform targetTransform = this.target.getTransform();
|
||||||
for(Animation animation : animData.anims) {
|
for(Animation animation : animData.anims) {
|
||||||
BlenderTrack blenderTrack = this.getTrack(owner, animData.skeleton, animation);
|
BlenderTrack blenderTrack = this.getTrack(owner, animData.skeleton, animation);
|
||||||
@ -76,15 +77,14 @@ import com.jme3.scene.plugins.ogre.AnimData;
|
|||||||
blenderTrack.setKeyframes(blenderTrack.getTimes(), translations, blenderTrack.getRotations(), blenderTrack.getScales());
|
blenderTrack.setKeyframes(blenderTrack.getTimes(), translations, blenderTrack.getRotations(), blenderTrack.getScales());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if(owner instanceof Spatial) {
|
||||||
protected void bakeStatic() {
|
Transform targetTransform = this.target.getTransform();
|
||||||
Transform targetTransform = this.target.getTransform();
|
Transform ownerTransform = this.owner.getTransform();
|
||||||
Transform ownerTransform = this.owner.getTransform();
|
Vector3f ownerLocation = ownerTransform.getTranslation();
|
||||||
Vector3f ownerLocation = ownerTransform.getTranslation();
|
this.locLike(ownerLocation, targetTransform.getTranslation(), ipo.calculateValue(0));
|
||||||
this.locLike(ownerLocation, targetTransform.getTranslation(), ipo.calculateValue(0));
|
this.owner.applyTransform(ownerTransform);
|
||||||
this.owner.applyTransform(ownerTransform);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void locLike(Vector3f ownerLocation, Vector3f targetLocation, float influence) {
|
private void locLike(Vector3f ownerLocation, Vector3f targetLocation, float influence) {
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
package com.jme3.scene.plugins.blender.constraints;
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
import com.jme3.animation.Animation;
|
import com.jme3.animation.Animation;
|
||||||
import com.jme3.math.Transform;
|
import com.jme3.math.Transform;
|
||||||
import com.jme3.math.Vector3f;
|
import com.jme3.math.Vector3f;
|
||||||
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.scene.plugins.blender.BlenderContext;
|
import com.jme3.scene.plugins.blender.BlenderContext;
|
||||||
import com.jme3.scene.plugins.blender.animations.Ipo;
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
@ -73,7 +76,7 @@ import com.jme3.scene.plugins.ogre.AnimData;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void bakeDynamic() {
|
protected void bakeConstraint() {
|
||||||
Object owner = this.owner.getObject();
|
Object owner = this.owner.getObject();
|
||||||
AnimData animData = blenderContext.getAnimData(this.owner.getOma());
|
AnimData animData = blenderContext.getAnimData(this.owner.getOma());
|
||||||
if(animData != null) {
|
if(animData != null) {
|
||||||
@ -82,19 +85,20 @@ import com.jme3.scene.plugins.ogre.AnimData;
|
|||||||
Vector3f[] translations = track.getTranslations();
|
Vector3f[] translations = track.getTranslations();
|
||||||
int maxFrames = translations.length;
|
int maxFrames = translations.length;
|
||||||
for (int frame = 0; frame < maxFrames; ++frame) {
|
for (int frame = 0; frame < maxFrames; ++frame) {
|
||||||
|
System.out.print(translations[frame] + "\t\t");
|
||||||
this.locLimit(translations[frame], ipo.calculateValue(frame));
|
this.locLimit(translations[frame], ipo.calculateValue(frame));
|
||||||
|
System.out.println(translations[frame]);
|
||||||
}
|
}
|
||||||
track.setKeyframes(track.getTimes(), translations, track.getRotations(), track.getScales());
|
track.setKeyframes(track.getTimes(), translations, track.getRotations(), track.getScales());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if(owner instanceof Spatial) {
|
||||||
protected void bakeStatic() {
|
Transform ownerTransform = this.owner.getTransform();
|
||||||
Transform ownerTransform = this.owner.getTransform();
|
Vector3f ownerLocation = ownerTransform.getTranslation();
|
||||||
Vector3f ownerLocation = ownerTransform.getTranslation();
|
this.locLimit(ownerLocation, ipo.calculateValue(0));
|
||||||
this.locLimit(ownerLocation, ipo.calculateValue(0));
|
this.owner.applyTransform(ownerTransform);
|
||||||
this.owner.applyTransform(ownerTransform);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,13 +36,7 @@ import java.util.logging.Logger;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void bakeDynamic() {
|
protected void bakeConstraint() {
|
||||||
// TODO: implement 'Lock track' constraint
|
|
||||||
LOGGER.log(Level.WARNING, "'Lock track' constraint NOT implemented!");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void bakeStatic() {
|
|
||||||
// TODO: implement 'Lock track' constraint
|
// TODO: implement 'Lock track' constraint
|
||||||
LOGGER.log(Level.WARNING, "'Lock track' constraint NOT implemented!");
|
LOGGER.log(Level.WARNING, "'Lock track' constraint NOT implemented!");
|
||||||
}
|
}
|
||||||
|
@ -35,13 +35,7 @@ import java.util.logging.Logger;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void bakeDynamic() {
|
protected void bakeConstraint() {
|
||||||
// TODO: implement 'Min max' constraint
|
|
||||||
LOGGER.log(Level.WARNING, "'Min max' constraint NOT implemented!");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void bakeStatic() {
|
|
||||||
// TODO: implement 'Min max' constraint
|
// TODO: implement 'Min max' constraint
|
||||||
LOGGER.log(Level.WARNING, "'Min max' constraint NOT implemented!");
|
LOGGER.log(Level.WARNING, "'Min max' constraint NOT implemented!");
|
||||||
}
|
}
|
||||||
|
@ -33,8 +33,5 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void bakeDynamic() {}
|
protected void bakeConstraint() {}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void bakeStatic() {}
|
|
||||||
}
|
}
|
||||||
|
@ -37,13 +37,7 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void bakeDynamic() {
|
protected void bakeConstraint() {
|
||||||
// TODO Auto-generated method stub
|
|
||||||
LOGGER.log(Level.WARNING, "'Pivot' constraint NOT implemented!");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void bakeStatic() {
|
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
LOGGER.log(Level.WARNING, "'Pivot' constraint NOT implemented!");
|
LOGGER.log(Level.WARNING, "'Pivot' constraint NOT implemented!");
|
||||||
}
|
}
|
||||||
|
@ -35,13 +35,7 @@ import java.util.logging.Logger;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void bakeDynamic() {
|
protected void bakeConstraint() {
|
||||||
// TODO: implement 'Python' constraint
|
|
||||||
LOGGER.log(Level.WARNING, "'Python' constraint NOT implemented!");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void bakeStatic() {
|
|
||||||
// TODO: implement 'Python' constraint
|
// TODO: implement 'Python' constraint
|
||||||
LOGGER.log(Level.WARNING, "'Python' constraint NOT implemented!");
|
LOGGER.log(Level.WARNING, "'Python' constraint NOT implemented!");
|
||||||
}
|
}
|
||||||
|
@ -35,13 +35,7 @@ import java.util.logging.Logger;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void bakeDynamic() {
|
protected void bakeConstraint() {
|
||||||
// TODO: implement 'Rigid body joint' constraint
|
|
||||||
LOGGER.log(Level.WARNING, "'Rigid body joint' constraint NOT implemented!");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void bakeStatic() {
|
|
||||||
// TODO: implement 'Rigid body joint' constraint
|
// TODO: implement 'Rigid body joint' constraint
|
||||||
LOGGER.log(Level.WARNING, "'Rigid body joint' constraint NOT implemented!");
|
LOGGER.log(Level.WARNING, "'Rigid body joint' constraint NOT implemented!");
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package com.jme3.scene.plugins.blender.constraints;
|
|||||||
import com.jme3.animation.Animation;
|
import com.jme3.animation.Animation;
|
||||||
import com.jme3.math.Quaternion;
|
import com.jme3.math.Quaternion;
|
||||||
import com.jme3.math.Transform;
|
import com.jme3.math.Transform;
|
||||||
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.scene.plugins.blender.BlenderContext;
|
import com.jme3.scene.plugins.blender.BlenderContext;
|
||||||
import com.jme3.scene.plugins.blender.animations.Ipo;
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
@ -47,10 +48,10 @@ import com.jme3.scene.plugins.ogre.AnimData;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void bakeDynamic() {
|
protected void bakeConstraint() {
|
||||||
|
Object owner = this.owner.getObject();
|
||||||
AnimData animData = blenderContext.getAnimData(this.owner.getOma());
|
AnimData animData = blenderContext.getAnimData(this.owner.getOma());
|
||||||
if(animData != null) {
|
if(animData != null) {
|
||||||
Object owner = this.owner.getObject();
|
|
||||||
Transform targetTransform = this.target.getTransform();
|
Transform targetTransform = this.target.getTransform();
|
||||||
Quaternion targetRotation = targetTransform.getRotation();
|
Quaternion targetRotation = targetTransform.getRotation();
|
||||||
for(Animation animation : animData.anims) {
|
for(Animation animation : animData.anims) {
|
||||||
@ -66,15 +67,14 @@ import com.jme3.scene.plugins.ogre.AnimData;
|
|||||||
track.setKeyframes(track.getTimes(), track.getTranslations(), rotations, track.getScales());
|
track.setKeyframes(track.getTimes(), track.getTranslations(), rotations, track.getScales());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if(owner instanceof Spatial) {
|
||||||
protected void bakeStatic() {
|
Transform targetTransform = this.target.getTransform();
|
||||||
Transform targetTransform = this.target.getTransform();
|
Transform ownerTransform = this.owner.getTransform();
|
||||||
Transform ownerTransform = this.owner.getTransform();
|
Quaternion ownerRotation = ownerTransform.getRotation();
|
||||||
Quaternion ownerRotation = ownerTransform.getRotation();
|
this.rotLike(ownerRotation, ownerRotation.toAngles(null), targetTransform.getRotation().toAngles(null), ipo.calculateValue(0));
|
||||||
this.rotLike(ownerRotation, ownerRotation.toAngles(null), targetTransform.getRotation().toAngles(null), ipo.calculateValue(0));
|
this.owner.applyTransform(ownerTransform);
|
||||||
this.owner.applyTransform(ownerTransform);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void rotLike(Quaternion ownerRotation, float[] ownerAngles, float[] targetAngles, float influence) {
|
private void rotLike(Quaternion ownerRotation, float[] ownerAngles, float[] targetAngles, float influence) {
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
package com.jme3.scene.plugins.blender.constraints;
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
import com.jme3.animation.Animation;
|
import com.jme3.animation.Animation;
|
||||||
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.Transform;
|
||||||
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.scene.plugins.blender.BlenderContext;
|
import com.jme3.scene.plugins.blender.BlenderContext;
|
||||||
import com.jme3.scene.plugins.blender.animations.Ipo;
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
@ -68,10 +71,10 @@ import com.jme3.scene.plugins.ogre.AnimData;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void bakeDynamic() {
|
protected void bakeConstraint() {
|
||||||
AnimData animData = blenderContext.getAnimData(owner.getOma());
|
Object owner = this.owner.getObject();
|
||||||
|
AnimData animData = blenderContext.getAnimData(this.owner.getOma());
|
||||||
if(animData != null) {
|
if(animData != null) {
|
||||||
Object owner = this.owner.getObject();
|
|
||||||
for(Animation animation : animData.anims) {
|
for(Animation animation : animData.anims) {
|
||||||
BlenderTrack track = this.getTrack(owner, animData.skeleton, animation);
|
BlenderTrack track = this.getTrack(owner, animData.skeleton, animation);
|
||||||
Quaternion[] rotations = track.getRotations();
|
Quaternion[] rotations = track.getRotations();
|
||||||
@ -79,21 +82,22 @@ import com.jme3.scene.plugins.ogre.AnimData;
|
|||||||
int maxFrames = rotations.length;
|
int maxFrames = rotations.length;
|
||||||
for (int frame = 0; frame < maxFrames; ++frame) {
|
for (int frame = 0; frame < maxFrames; ++frame) {
|
||||||
rotations[frame].toAngles(angles);
|
rotations[frame].toAngles(angles);
|
||||||
|
System.out.print(Arrays.toString(angles) + "\t\t");
|
||||||
this.rotLimit(angles, ipo.calculateValue(frame));
|
this.rotLimit(angles, ipo.calculateValue(frame));
|
||||||
|
System.out.println(Arrays.toString(angles));
|
||||||
rotations[frame].fromAngles(angles);
|
rotations[frame].fromAngles(angles);
|
||||||
}
|
}
|
||||||
track.setKeyframes(track.getTimes(), track.getTranslations(), rotations, track.getScales());
|
track.setKeyframes(track.getTimes(), track.getTranslations(), rotations, track.getScales());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if(owner instanceof Spatial) {
|
||||||
protected void bakeStatic() {
|
Transform ownerTransform = this.owner.getTransform();
|
||||||
Transform ownerTransform = this.owner.getTransform();
|
float[] angles = ownerTransform.getRotation().toAngles(null);
|
||||||
float[] angles = ownerTransform.getRotation().toAngles(null);
|
this.rotLimit(angles, ipo.calculateValue(0));
|
||||||
this.rotLimit(angles, ipo.calculateValue(0));
|
ownerTransform.getRotation().fromAngles(angles);
|
||||||
ownerTransform.getRotation().fromAngles(angles);
|
this.owner.applyTransform(ownerTransform);
|
||||||
this.owner.applyTransform(ownerTransform);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -114,7 +118,7 @@ import com.jme3.scene.plugins.ogre.AnimData;
|
|||||||
}
|
}
|
||||||
angles[0] -= difference;
|
angles[0] -= difference;
|
||||||
}
|
}
|
||||||
if ((flag & LIMIT_YROT) != 0) {
|
if ((flag & LIMIT_ZROT) != 0) {
|
||||||
float difference = 0.0f;
|
float difference = 0.0f;
|
||||||
if (angles[1] < limits[1][0]) {
|
if (angles[1] < limits[1][0]) {
|
||||||
difference = (angles[1] - limits[1][0]) * influence;
|
difference = (angles[1] - limits[1][0]) * influence;
|
||||||
@ -123,7 +127,7 @@ import com.jme3.scene.plugins.ogre.AnimData;
|
|||||||
}
|
}
|
||||||
angles[1] -= difference;
|
angles[1] -= difference;
|
||||||
}
|
}
|
||||||
if ((flag & LIMIT_ZROT) != 0) {
|
/*if ((flag & LIMIT_ZROT) != 0) {
|
||||||
float difference = 0.0f;
|
float difference = 0.0f;
|
||||||
if (angles[2] < limits[2][0]) {
|
if (angles[2] < limits[2][0]) {
|
||||||
difference = (angles[2] - limits[2][0]) * influence;
|
difference = (angles[2] - limits[2][0]) * influence;
|
||||||
@ -131,6 +135,6 @@ import com.jme3.scene.plugins.ogre.AnimData;
|
|||||||
difference = (angles[2] - limits[2][1]) * influence;
|
difference = (angles[2] - limits[2][1]) * influence;
|
||||||
}
|
}
|
||||||
angles[2] -= difference;
|
angles[2] -= difference;
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ import com.jme3.scene.plugins.ogre.AnimData;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void bakeDynamic() {
|
protected void bakeConstraint() {
|
||||||
//loading mesh points (blender ensures that the target is a mesh-object)
|
//loading mesh points (blender ensures that the target is a mesh-object)
|
||||||
List<Vector3f> pts = new ArrayList<Vector3f>();
|
List<Vector3f> pts = new ArrayList<Vector3f>();
|
||||||
Node target = (Node) this.target.getObject();
|
Node target = (Node) this.target.getObject();
|
||||||
@ -86,11 +86,7 @@ import com.jme3.scene.plugins.ogre.AnimData;
|
|||||||
track.setKeyframes(track.getTimes(), translations, rotations, track.getScales());
|
track.setKeyframes(track.getTimes(), translations, rotations, track.getScales());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void bakeStatic() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
|
//TODO: static constraint for spatials
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package com.jme3.scene.plugins.blender.constraints;
|
|||||||
import com.jme3.animation.Animation;
|
import com.jme3.animation.Animation;
|
||||||
import com.jme3.math.Transform;
|
import com.jme3.math.Transform;
|
||||||
import com.jme3.math.Vector3f;
|
import com.jme3.math.Vector3f;
|
||||||
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.scene.plugins.blender.BlenderContext;
|
import com.jme3.scene.plugins.blender.BlenderContext;
|
||||||
import com.jme3.scene.plugins.blender.animations.Ipo;
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
@ -52,10 +53,10 @@ import com.jme3.scene.plugins.ogre.AnimData;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void bakeDynamic() {
|
protected void bakeConstraint() {
|
||||||
|
Object owner = this.owner.getObject();
|
||||||
AnimData animData = blenderContext.getAnimData(this.owner.getOma());
|
AnimData animData = blenderContext.getAnimData(this.owner.getOma());
|
||||||
if(animData != null) {
|
if(animData != null) {
|
||||||
Object owner = this.owner.getObject();
|
|
||||||
Transform targetTransform = this.target.getTransform();
|
Transform targetTransform = this.target.getTransform();
|
||||||
Vector3f targetScale = targetTransform.getScale();
|
Vector3f targetScale = targetTransform.getScale();
|
||||||
for(Animation animation : animData.anims) {
|
for(Animation animation : animData.anims) {
|
||||||
@ -68,14 +69,13 @@ import com.jme3.scene.plugins.ogre.AnimData;
|
|||||||
track.setKeyframes(track.getTimes(), track.getTranslations(), track.getRotations(), scales);
|
track.setKeyframes(track.getTimes(), track.getTranslations(), track.getRotations(), scales);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if(owner instanceof Spatial) {
|
||||||
protected void bakeStatic() {
|
Transform targetTransform = this.target.getTransform();
|
||||||
Transform targetTransform = this.target.getTransform();
|
Transform ownerTransform = this.owner.getTransform();
|
||||||
Transform ownerTransform = this.owner.getTransform();
|
this.sizeLike(ownerTransform.getScale(), targetTransform.getScale(), ipo.calculateValue(0));
|
||||||
this.sizeLike(ownerTransform.getScale(), targetTransform.getScale(), ipo.calculateValue(0));
|
this.owner.applyTransform(ownerTransform);
|
||||||
this.owner.applyTransform(ownerTransform);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sizeLike(Vector3f ownerScale, Vector3f targetScale, float influence) {
|
private void sizeLike(Vector3f ownerScale, Vector3f targetScale, float influence) {
|
||||||
|
@ -3,6 +3,7 @@ package com.jme3.scene.plugins.blender.constraints;
|
|||||||
import com.jme3.animation.Animation;
|
import com.jme3.animation.Animation;
|
||||||
import com.jme3.math.Transform;
|
import com.jme3.math.Transform;
|
||||||
import com.jme3.math.Vector3f;
|
import com.jme3.math.Vector3f;
|
||||||
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.scene.plugins.blender.BlenderContext;
|
import com.jme3.scene.plugins.blender.BlenderContext;
|
||||||
import com.jme3.scene.plugins.blender.animations.Ipo;
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
@ -73,10 +74,10 @@ import com.jme3.scene.plugins.ogre.AnimData;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void bakeDynamic() {
|
protected void bakeConstraint() {
|
||||||
|
Object owner = this.owner.getObject();
|
||||||
AnimData animData = blenderContext.getAnimData(this.owner.getOma());
|
AnimData animData = blenderContext.getAnimData(this.owner.getOma());
|
||||||
if(animData != null) {
|
if(animData != null) {
|
||||||
Object owner = this.owner.getObject();
|
|
||||||
for(Animation animation : animData.anims) {
|
for(Animation animation : animData.anims) {
|
||||||
BlenderTrack track = this.getTrack(owner, animData.skeleton, animation);
|
BlenderTrack track = this.getTrack(owner, animData.skeleton, animation);
|
||||||
Vector3f[] scales = track.getScales();
|
Vector3f[] scales = track.getScales();
|
||||||
@ -87,13 +88,12 @@ import com.jme3.scene.plugins.ogre.AnimData;
|
|||||||
track.setKeyframes(track.getTimes(), track.getTranslations(), track.getRotations(), scales);
|
track.setKeyframes(track.getTimes(), track.getTranslations(), track.getRotations(), scales);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if(owner instanceof Spatial) {
|
||||||
protected void bakeStatic() {
|
Transform ownerTransform = this.owner.getTransform();
|
||||||
Transform ownerTransform = this.owner.getTransform();
|
this.sizeLimit(ownerTransform.getScale(), ipo.calculateValue(0));
|
||||||
this.sizeLimit(ownerTransform.getScale(), ipo.calculateValue(0));
|
this.owner.applyTransform(ownerTransform);
|
||||||
this.owner.applyTransform(ownerTransform);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sizeLimit(Vector3f scale, float influence) {
|
private void sizeLimit(Vector3f scale, float influence) {
|
||||||
|
@ -37,14 +37,8 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void bakeDynamic() {
|
protected void bakeConstraint() {
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
LOGGER.log(Level.WARNING, "'Splie IK' constraint NOT implemented!");
|
LOGGER.log(Level.WARNING, "'Splie IK' constraint NOT implemented!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void bakeStatic() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
LOGGER.log(Level.WARNING, "'Spline IK' constraint NOT implemented!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -35,13 +35,7 @@ import java.util.logging.Logger;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void bakeDynamic() {
|
protected void bakeConstraint() {
|
||||||
// TODO: implement 'Stretch to' constraint
|
|
||||||
LOGGER.log(Level.WARNING, "'Stretch to' constraint NOT implemented!");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void bakeStatic() {
|
|
||||||
// TODO: implement 'Stretch to' constraint
|
// TODO: implement 'Stretch to' constraint
|
||||||
LOGGER.log(Level.WARNING, "'Stretch to' constraint NOT implemented!");
|
LOGGER.log(Level.WARNING, "'Stretch to' constraint NOT implemented!");
|
||||||
}
|
}
|
||||||
|
@ -35,13 +35,7 @@ import java.util.logging.Logger;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void bakeDynamic() {
|
protected void bakeConstraint() {
|
||||||
// TODO: implement 'Transform' constraint
|
|
||||||
LOGGER.log(Level.WARNING, "'Transform' constraint NOT implemented!");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void bakeStatic() {
|
|
||||||
// TODO: implement 'Transform' constraint
|
// TODO: implement 'Transform' constraint
|
||||||
LOGGER.log(Level.WARNING, "'Transform' constraint NOT implemented!");
|
LOGGER.log(Level.WARNING, "'Transform' constraint NOT implemented!");
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.jme3.scene.plugins.blender.constraints;
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
import com.jme3.animation.Bone;
|
import com.jme3.animation.Bone;
|
||||||
|
import com.jme3.math.FastMath;
|
||||||
import com.jme3.math.Matrix4f;
|
import com.jme3.math.Matrix4f;
|
||||||
import com.jme3.math.Quaternion;
|
import com.jme3.math.Quaternion;
|
||||||
import com.jme3.math.Transform;
|
import com.jme3.math.Transform;
|
||||||
@ -8,6 +9,7 @@ import com.jme3.math.Vector3f;
|
|||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.scene.plugins.blender.BlenderContext;
|
import com.jme3.scene.plugins.blender.BlenderContext;
|
||||||
import com.jme3.scene.plugins.blender.BlenderContext.LoadedFeatureDataType;
|
import com.jme3.scene.plugins.blender.BlenderContext.LoadedFeatureDataType;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.BoneContext;
|
||||||
import com.jme3.scene.plugins.blender.constraints.Constraint.Space;
|
import com.jme3.scene.plugins.blender.constraints.Constraint.Space;
|
||||||
import com.jme3.scene.plugins.blender.file.DynamicArray;
|
import com.jme3.scene.plugins.blender.file.DynamicArray;
|
||||||
import com.jme3.scene.plugins.blender.file.Structure;
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
@ -156,6 +158,7 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Bone
|
// Bone
|
||||||
|
BoneContext boneContext = blenderContext.getBoneContext(oma);
|
||||||
switch (space) {
|
switch (space) {
|
||||||
case CONSTRAINT_SPACE_LOCAL:
|
case CONSTRAINT_SPACE_LOCAL:
|
||||||
Transform localTransform = new Transform(bone.getLocalPosition(), bone.getLocalRotation());
|
Transform localTransform = new Transform(bone.getLocalPosition(), bone.getLocalRotation());
|
||||||
@ -173,8 +176,9 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
worldTransform.setScale(bone.getWorldBindScale());
|
worldTransform.setScale(bone.getWorldBindScale());
|
||||||
return worldTransform;
|
return worldTransform;
|
||||||
case CONSTRAINT_SPACE_POSE:
|
case CONSTRAINT_SPACE_POSE:
|
||||||
// TODO
|
Transform poseTransform = new Transform(bone.getLocalPosition(), bone.getLocalRotation());
|
||||||
return null;
|
poseTransform.setScale(bone.getLocalScale());
|
||||||
|
return poseTransform;
|
||||||
case CONSTRAINT_SPACE_PARLOCAL:
|
case CONSTRAINT_SPACE_PARLOCAL:
|
||||||
Transform parentLocalTransform = new Transform(bone.getLocalPosition(), bone.getLocalRotation());
|
Transform parentLocalTransform = new Transform(bone.getLocalPosition(), bone.getLocalRotation());
|
||||||
parentLocalTransform.setScale(bone.getLocalScale());
|
parentLocalTransform.setScale(bone.getLocalScale());
|
||||||
@ -228,11 +232,15 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
break;
|
break;
|
||||||
case CONSTRAINT_SPACE_WORLD:
|
case CONSTRAINT_SPACE_WORLD:
|
||||||
Matrix4f m = this.getParentWorldTransformMatrix();
|
Matrix4f m = this.getParentWorldTransformMatrix();
|
||||||
m.invertLocal();
|
// m.invertLocal();
|
||||||
transform.setTranslation(m.mult(transform.getTranslation()));
|
transform.setTranslation(m.mult(transform.getTranslation()));
|
||||||
transform.setRotation(m.mult(transform.getRotation(), null));
|
transform.setRotation(m.mult(transform.getRotation(), null));
|
||||||
transform.setScale(transform.getScale());
|
transform.setScale(transform.getScale());
|
||||||
bone.setBindTransforms(transform.getTranslation(), transform.getRotation(), transform.getScale());
|
bone.setBindTransforms(transform.getTranslation(), transform.getRotation(), transform.getScale());
|
||||||
|
// float x = FastMath.HALF_PI/2;
|
||||||
|
// float y = -FastMath.HALF_PI;
|
||||||
|
// float z = -FastMath.HALF_PI/2;
|
||||||
|
// bone.setBindTransforms(new Vector3f(0,0,0), new Quaternion().fromAngles(x, y, z), new Vector3f(1,1,1));
|
||||||
break;
|
break;
|
||||||
case CONSTRAINT_SPACE_PARLOCAL:
|
case CONSTRAINT_SPACE_PARLOCAL:
|
||||||
Vector3f parentLocalTranslation = bone.getLocalPosition().add(transform.getTranslation());
|
Vector3f parentLocalTranslation = bone.getLocalPosition().add(transform.getTranslation());
|
||||||
@ -240,7 +248,7 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
bone.setBindTransforms(parentLocalTranslation, parentLocalRotation, transform.getScale());
|
bone.setBindTransforms(parentLocalTranslation, parentLocalRotation, transform.getScale());
|
||||||
break;
|
break;
|
||||||
case CONSTRAINT_SPACE_POSE:
|
case CONSTRAINT_SPACE_POSE:
|
||||||
// TODO:
|
bone.setBindTransforms(transform.getTranslation(), transform.getRotation(), transform.getScale());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException("Invalid space type for target object: " + space.toString());
|
throw new IllegalStateException("Invalid space type for target object: " + space.toString());
|
||||||
|
@ -42,8 +42,8 @@ import com.jme3.util.BufferUtils;
|
|||||||
* @author Marcin Roguski (Kaelthas)
|
* @author Marcin Roguski (Kaelthas)
|
||||||
*/
|
*/
|
||||||
/* package */class ArmatureModifier extends Modifier {
|
/* package */class ArmatureModifier extends Modifier {
|
||||||
private static final Logger LOGGER = Logger.getLogger(ArmatureModifier.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(ArmatureModifier.class.getName());
|
||||||
private static final int MAXIMUM_WEIGHTS_PER_VERTEX = 4;
|
private static final int MAXIMUM_WEIGHTS_PER_VERTEX = 4;
|
||||||
// @Marcin it was an Ogre limitation, but as long as we use a MaxNumWeight
|
// @Marcin it was an Ogre limitation, but as long as we use a MaxNumWeight
|
||||||
// variable in mesh,
|
// variable in mesh,
|
||||||
// i guess this limitation has no sense for the blender loader...so i guess
|
// i guess this limitation has no sense for the blender loader...so i guess
|
||||||
@ -55,17 +55,18 @@ import com.jme3.util.BufferUtils;
|
|||||||
// Rémy
|
// Rémy
|
||||||
|
|
||||||
/** Loaded animation data. */
|
/** Loaded animation data. */
|
||||||
private AnimData animData;
|
private AnimData animData;
|
||||||
/** Old memory address of the mesh that will have the skeleton applied. */
|
/** Old memory address of the mesh that will have the skeleton applied. */
|
||||||
private Long meshOMA;
|
private Long meshOMA;
|
||||||
/**
|
/**
|
||||||
* The maxiumum amount of bone groups applied to a single vertex (max = MAXIMUM_WEIGHTS_PER_VERTEX).
|
* The maxiumum amount of bone groups applied to a single vertex (max =
|
||||||
|
* MAXIMUM_WEIGHTS_PER_VERTEX).
|
||||||
*/
|
*/
|
||||||
private int boneGroups;
|
private int boneGroups;
|
||||||
/** The weights of vertices. */
|
/** The weights of vertices. */
|
||||||
private VertexBuffer verticesWeights;
|
private VertexBuffer verticesWeights;
|
||||||
/** The indexes of bones applied to vertices. */
|
/** The indexes of bones applied to vertices. */
|
||||||
private VertexBuffer verticesWeightsIndices;
|
private VertexBuffer verticesWeightsIndices;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor reads animation data from the object structore. The
|
* This constructor reads animation data from the object structore. The
|
||||||
@ -83,9 +84,12 @@ import com.jme3.util.BufferUtils;
|
|||||||
*/
|
*/
|
||||||
public ArmatureModifier(Structure objectStructure, Structure modifierStructure, BlenderContext blenderContext) throws BlenderFileException {
|
public ArmatureModifier(Structure objectStructure, Structure modifierStructure, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
Structure meshStructure = ((Pointer) objectStructure.getFieldValue("data")).fetchData(blenderContext.getInputStream()).get(0);
|
Structure meshStructure = ((Pointer) objectStructure.getFieldValue("data")).fetchData(blenderContext.getInputStream()).get(0);
|
||||||
Pointer pDvert = (Pointer) meshStructure.getFieldValue("dvert");// dvert = DeformVERTices
|
Pointer pDvert = (Pointer) meshStructure.getFieldValue("dvert");// dvert
|
||||||
|
// =
|
||||||
|
// DeformVERTices
|
||||||
|
|
||||||
//if pDvert==null then there are not vertex groups and no need to load skeleton (untill bone envelopes are supported)
|
// if pDvert==null then there are not vertex groups and no need to load
|
||||||
|
// skeleton (untill bone envelopes are supported)
|
||||||
if (this.validate(modifierStructure, blenderContext) && pDvert.isNotNull()) {
|
if (this.validate(modifierStructure, blenderContext) && pDvert.isNotNull()) {
|
||||||
Pointer pArmatureObject = (Pointer) modifierStructure.getFieldValue("object");
|
Pointer pArmatureObject = (Pointer) modifierStructure.getFieldValue("object");
|
||||||
if (pArmatureObject.isNotNull()) {
|
if (pArmatureObject.isNotNull()) {
|
||||||
@ -116,7 +120,8 @@ import com.jme3.util.BufferUtils;
|
|||||||
armatureHelper.buildBones(bonebase.get(i), null, bonesList, objectToArmatureTransformation, bonesPoseChannels, blenderContext);
|
armatureHelper.buildBones(bonebase.get(i), null, bonesList, objectToArmatureTransformation, bonesPoseChannels, blenderContext);
|
||||||
}
|
}
|
||||||
bonesList.add(0, new Bone(""));
|
bonesList.add(0, new Bone(""));
|
||||||
Skeleton skeleton = new Skeleton(bonesList.toArray(new Bone[bonesList.size()]));
|
Bone[] bones = bonesList.toArray(new Bone[bonesList.size()]);
|
||||||
|
Skeleton skeleton = new Skeleton(bones);
|
||||||
|
|
||||||
// read mesh indexes
|
// read mesh indexes
|
||||||
this.meshOMA = meshStructure.getOldMemoryAddress();
|
this.meshOMA = meshStructure.getOldMemoryAddress();
|
||||||
@ -132,25 +137,30 @@ import com.jme3.util.BufferUtils;
|
|||||||
String actionName = actionStructure.getName();
|
String actionName = actionStructure.getName();
|
||||||
|
|
||||||
BoneTrack[] tracks = armatureHelper.getTracks(actionStructure, skeleton, blenderContext);
|
BoneTrack[] tracks = armatureHelper.getTracks(actionStructure, skeleton, blenderContext);
|
||||||
// determining the animation time
|
if(tracks != null && tracks.length > 0) {
|
||||||
float maximumTrackLength = 0;
|
// determining the animation time
|
||||||
for (BoneTrack track : tracks) {
|
float maximumTrackLength = 0;
|
||||||
float length = track.getLength();
|
for (BoneTrack track : tracks) {
|
||||||
if (length > maximumTrackLength) {
|
float length = track.getLength();
|
||||||
maximumTrackLength = length;
|
if (length > maximumTrackLength) {
|
||||||
|
maximumTrackLength = length;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Animation boneAnimation = new Animation(actionName, maximumTrackLength);
|
Animation boneAnimation = new Animation(actionName, maximumTrackLength);
|
||||||
boneAnimation.setTracks(tracks);
|
boneAnimation.setTracks(tracks);
|
||||||
animations.add(boneAnimation);
|
animations.add(boneAnimation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
animData = new AnimData(skeleton, animations);
|
animData = new AnimData(skeleton, animations);
|
||||||
|
|
||||||
// store the animation data for each bone
|
// store the animation data for each bone
|
||||||
for (Structure boneStructure : bonebase) {
|
for (Bone bone : bones) {
|
||||||
blenderContext.setAnimData(boneStructure.getOldMemoryAddress(), animData);
|
Long boneOma = armatureHelper.getBoneOMA(bone);
|
||||||
|
if (boneOma != null) {
|
||||||
|
blenderContext.setAnimData(boneOma, animData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -177,28 +187,14 @@ import com.jme3.util.BufferUtils;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// applying bone transforms before constraints are baked
|
// applying constraints to Bones
|
||||||
ArmatureHelper armatureHelper = blenderContext.getHelper(ArmatureHelper.class);
|
ArmatureHelper armatureHelper = blenderContext.getHelper(ArmatureHelper.class);
|
||||||
//TODO: should we apply static bone poses ??? (this breaks the animation)
|
|
||||||
// for (int i = 0; i < animData.skeleton.getBoneCount(); ++i) {
|
|
||||||
// Bone bone = animData.skeleton.getBone(i);
|
|
||||||
// Transform transform = armatureHelper.getBoneBindTransform(bone);
|
|
||||||
// Transform boneTransform = armatureHelper.getLocalTransform(bone);
|
|
||||||
// if(transform!=null && boneTransform!=null) {
|
|
||||||
// bone.setBindTransforms(boneTransform.getTranslation().addLocal(transform.getTranslation()),
|
|
||||||
// boneTransform.getRotation().multLocal(transform.getRotation()),
|
|
||||||
// boneTransform.getScale().multLocal(transform.getScale()));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// applying constraints to Bones (and only to bones, object constraints
|
|
||||||
// are applied in the ObjectHelper)
|
|
||||||
for (int i = 0; i < animData.skeleton.getBoneCount(); ++i) {
|
for (int i = 0; i < animData.skeleton.getBoneCount(); ++i) {
|
||||||
Long boneOMA = armatureHelper.getBoneOMA(animData.skeleton.getBone(i));
|
Long boneOMA = armatureHelper.getBoneOMA(animData.skeleton.getBone(i));
|
||||||
List<Constraint> constraints = blenderContext.getConstraints(boneOMA);
|
List<Constraint> constraints = blenderContext.getConstraints(boneOMA);
|
||||||
if (constraints != null && constraints.size() > 0) {
|
if (constraints != null && constraints.size() > 0) {
|
||||||
for (Constraint constraint : constraints) {
|
for (Constraint constraint : constraints) {
|
||||||
constraint.bake(Constraint.BAKE_DYNAMIC | Constraint.BAKE_STATIC);
|
constraint.bake();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,82 +31,165 @@
|
|||||||
*/
|
*/
|
||||||
package com.jme3.scene.plugins.blender.modifiers;
|
package com.jme3.scene.plugins.blender.modifiers;
|
||||||
|
|
||||||
import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
|
|
||||||
import com.jme3.scene.plugins.blender.BlenderContext;
|
|
||||||
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
|
||||||
import com.jme3.scene.plugins.blender.file.Pointer;
|
|
||||||
import com.jme3.scene.plugins.blender.file.Structure;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
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.scene.plugins.blender.AbstractBlenderHelper;
|
||||||
|
import com.jme3.scene.plugins.blender.BlenderContext;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.IpoHelper;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Pointer;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class that is used in modifiers calculations.
|
* A class that is used in modifiers calculations.
|
||||||
|
*
|
||||||
* @author Marcin Roguski
|
* @author Marcin Roguski
|
||||||
*/
|
*/
|
||||||
public class ModifierHelper extends AbstractBlenderHelper {
|
public class ModifierHelper extends AbstractBlenderHelper {
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(ModifierHelper.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(ModifierHelper.class.getName());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor parses the given blender version and stores the result. Some functionalities may differ in
|
* This constructor parses the given blender version and stores the result.
|
||||||
* different blender versions.
|
* Some functionalities may differ in different blender versions.
|
||||||
* @param blenderVersion
|
*
|
||||||
* the version read from the blend file
|
* @param blenderVersion
|
||||||
* @param fixUpAxis
|
* the version read from the blend file
|
||||||
* a variable that indicates if the Y asxis is the UP axis or not
|
* @param fixUpAxis
|
||||||
*/
|
* a variable that indicates if the Y asxis is the UP axis or not
|
||||||
public ModifierHelper(String blenderVersion, boolean fixUpAxis) {
|
*/
|
||||||
super(blenderVersion, fixUpAxis);
|
public ModifierHelper(String blenderVersion, boolean fixUpAxis) {
|
||||||
}
|
super(blenderVersion, fixUpAxis);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method reads the given object's modifiers.
|
* This method reads the given object's modifiers.
|
||||||
* @param objectStructure
|
*
|
||||||
* the object structure
|
* @param objectStructure
|
||||||
* @param blenderContext
|
* the object structure
|
||||||
* the blender context
|
* @param blenderContext
|
||||||
* @throws BlenderFileException
|
* the blender context
|
||||||
* this exception is thrown when the blender file is somehow corrupted
|
* @throws BlenderFileException
|
||||||
*/
|
* this exception is thrown when the blender file is somehow
|
||||||
public Collection<Modifier> readModifiers(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException {
|
* corrupted
|
||||||
Collection<Modifier> result = new ArrayList<Modifier>();
|
*/
|
||||||
Structure modifiersListBase = (Structure) objectStructure.getFieldValue("modifiers");
|
public Collection<Modifier> readModifiers(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
List<Structure> modifiers = modifiersListBase.evaluateListBase(blenderContext);
|
Collection<Modifier> result = new ArrayList<Modifier>();
|
||||||
for (Structure modifierStructure : modifiers) {
|
Structure modifiersListBase = (Structure) objectStructure.getFieldValue("modifiers");
|
||||||
Modifier modifier = null;
|
List<Structure> modifiers = modifiersListBase.evaluateListBase(blenderContext);
|
||||||
if (Modifier.ARRAY_MODIFIER_DATA.equals(modifierStructure.getType())) {
|
for (Structure modifierStructure : modifiers) {
|
||||||
modifier = new ArrayModifier(modifierStructure, blenderContext);
|
Modifier modifier = null;
|
||||||
} else if (Modifier.MIRROR_MODIFIER_DATA.equals(modifierStructure.getType())) {
|
if (Modifier.ARRAY_MODIFIER_DATA.equals(modifierStructure.getType())) {
|
||||||
modifier = new MirrorModifier(modifierStructure, blenderContext);
|
modifier = new ArrayModifier(modifierStructure, blenderContext);
|
||||||
} else if (Modifier.ARMATURE_MODIFIER_DATA.equals(modifierStructure.getType())) {
|
} else if (Modifier.MIRROR_MODIFIER_DATA.equals(modifierStructure.getType())) {
|
||||||
modifier = new ArmatureModifier(objectStructure, modifierStructure, blenderContext);
|
modifier = new MirrorModifier(modifierStructure, blenderContext);
|
||||||
} else if (Modifier.PARTICLE_MODIFIER_DATA.equals(modifierStructure.getType())) {
|
} else if (Modifier.ARMATURE_MODIFIER_DATA.equals(modifierStructure.getType())) {
|
||||||
modifier = new ParticlesModifier(modifierStructure, blenderContext);
|
modifier = new ArmatureModifier(objectStructure, modifierStructure, blenderContext);
|
||||||
}
|
} else if (Modifier.PARTICLE_MODIFIER_DATA.equals(modifierStructure.getType())) {
|
||||||
|
modifier = new ParticlesModifier(modifierStructure, blenderContext);
|
||||||
|
}
|
||||||
|
|
||||||
if(modifier != null) {
|
if (modifier != null) {
|
||||||
result.add(modifier);
|
result.add(modifier);
|
||||||
blenderContext.addModifier(objectStructure.getOldMemoryAddress(), modifier);
|
blenderContext.addModifier(objectStructure.getOldMemoryAddress(), modifier);
|
||||||
} else {
|
} else {
|
||||||
LOGGER.log(Level.WARNING, "Unsupported modifier type: {0}", modifierStructure.getType());
|
LOGGER.log(Level.WARNING, "Unsupported modifier type: {0}", modifierStructure.getType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//at the end read object's animation modifier
|
// at the end read object's animation modifier (object animation is
|
||||||
Pointer pIpo = (Pointer) objectStructure.getFieldValue("ipo");
|
// either described by action or by ipo of the object)
|
||||||
if (pIpo.isNotNull()) {
|
Modifier modifier;
|
||||||
Modifier modifier = new ObjectAnimationModifier(objectStructure, blenderContext);
|
if (blenderVersion <= 249) {
|
||||||
result.add(modifier);
|
modifier = this.readAnimationModifier249(objectStructure, blenderContext);
|
||||||
blenderContext.addModifier(objectStructure.getOldMemoryAddress(), modifier);
|
} else {
|
||||||
}
|
modifier = this.readAnimationModifier250(objectStructure, blenderContext);
|
||||||
return result;
|
}
|
||||||
}
|
if (modifier != null) {
|
||||||
|
result.add(modifier);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) {
|
public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method reads the object's animation modifier for blender version
|
||||||
|
* 2.49 and lower.
|
||||||
|
*
|
||||||
|
* @param objectStructure
|
||||||
|
* the object's structure
|
||||||
|
* @param blenderContext
|
||||||
|
* the blender context
|
||||||
|
* @return loaded modifier
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
private Modifier readAnimationModifier249(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
|
Modifier result = null;
|
||||||
|
Pointer pAction = (Pointer) objectStructure.getFieldValue("action");
|
||||||
|
IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class);
|
||||||
|
if (pAction.isNotNull()) {
|
||||||
|
Structure action = pAction.fetchData(blenderContext.getInputStream()).get(0);
|
||||||
|
List<Structure> actionChannels = ((Structure) action.getFieldValue("chanbase")).evaluateListBase(blenderContext);
|
||||||
|
if (actionChannels.size() == 1) {// object's animtion action has
|
||||||
|
// only one channel
|
||||||
|
Pointer pChannelIpo = (Pointer) actionChannels.get(0).getFieldValue("ipo");
|
||||||
|
Structure ipoStructure = pChannelIpo.fetchData(blenderContext.getInputStream()).get(0);
|
||||||
|
Ipo ipo = ipoHelper.fromIpoStructure(ipoStructure, blenderContext);
|
||||||
|
result = new ObjectAnimationModifier(ipo, action.getName(), objectStructure.getOldMemoryAddress(), blenderContext);
|
||||||
|
blenderContext.addModifier(objectStructure.getOldMemoryAddress(), result);
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("Object's action cannot have more than one channel!");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Pointer pIpo = (Pointer) objectStructure.getFieldValue("ipo");
|
||||||
|
if (pIpo.isNotNull()) {
|
||||||
|
Structure ipoStructure = pIpo.fetchData(blenderContext.getInputStream()).get(0);
|
||||||
|
Ipo ipo = ipoHelper.fromIpoStructure(ipoStructure, blenderContext);
|
||||||
|
result = new ObjectAnimationModifier(ipo, objectStructure.getName(), objectStructure.getOldMemoryAddress(), blenderContext);
|
||||||
|
blenderContext.addModifier(objectStructure.getOldMemoryAddress(), result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method reads the object's animation modifier for blender version
|
||||||
|
* 2.50 and higher.
|
||||||
|
*
|
||||||
|
* @param objectStructure
|
||||||
|
* the object's structure
|
||||||
|
* @param blenderContext
|
||||||
|
* the blender context
|
||||||
|
* @return loaded modifier
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
private Modifier readAnimationModifier250(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
|
Modifier result = null;
|
||||||
|
Pointer pAnimData = (Pointer) objectStructure.getFieldValue("adt");
|
||||||
|
if (pAnimData.isNotNull()) {
|
||||||
|
Structure animData = pAnimData.fetchData(blenderContext.getInputStream()).get(0);
|
||||||
|
Pointer pAction = (Pointer) animData.getFieldValue("action");
|
||||||
|
if (pAction.isNotNull()) {
|
||||||
|
Structure actionStructure = pAction.fetchData(blenderContext.getInputStream()).get(0);
|
||||||
|
IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class);
|
||||||
|
Ipo ipo = ipoHelper.fromAction(actionStructure, blenderContext);
|
||||||
|
result = new ObjectAnimationModifier(ipo, actionStructure.getName(), objectStructure.getOldMemoryAddress(), blenderContext);
|
||||||
|
blenderContext.addModifier(objectStructure.getOldMemoryAddress(), result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package com.jme3.scene.plugins.blender.modifiers;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@ -12,11 +11,7 @@ import com.jme3.animation.SpatialTrack;
|
|||||||
import com.jme3.scene.Node;
|
import com.jme3.scene.Node;
|
||||||
import com.jme3.scene.plugins.blender.BlenderContext;
|
import com.jme3.scene.plugins.blender.BlenderContext;
|
||||||
import com.jme3.scene.plugins.blender.animations.Ipo;
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
import com.jme3.scene.plugins.blender.animations.IpoHelper;
|
|
||||||
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
import com.jme3.scene.plugins.blender.file.FileBlockHeader;
|
|
||||||
import com.jme3.scene.plugins.blender.file.Pointer;
|
|
||||||
import com.jme3.scene.plugins.blender.file.Structure;
|
|
||||||
import com.jme3.scene.plugins.ogre.AnimData;
|
import com.jme3.scene.plugins.ogre.AnimData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -25,12 +20,10 @@ import com.jme3.scene.plugins.ogre.AnimData;
|
|||||||
* @author Marcin Roguski (Kaelthas)
|
* @author Marcin Roguski (Kaelthas)
|
||||||
*/
|
*/
|
||||||
/* package */class ObjectAnimationModifier extends Modifier {
|
/* package */class ObjectAnimationModifier extends Modifier {
|
||||||
private static final Logger LOGGER = Logger.getLogger(ObjectAnimationModifier.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(ObjectAnimationModifier.class.getName());
|
||||||
|
|
||||||
/** Loaded animation data. */
|
/** Loaded animation data. */
|
||||||
private AnimData animData;
|
private AnimData animData;
|
||||||
/** Old memory address of the object structure that will have the modifier applied. */
|
|
||||||
private Long objectOMA;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor reads animation of the object itself (without bones) and
|
* This constructor reads animation of the object itself (without bones) and
|
||||||
@ -40,67 +33,41 @@ import com.jme3.scene.plugins.ogre.AnimData;
|
|||||||
* animation should be working. The stored modifier is an anim data and
|
* animation should be working. The stored modifier is an anim data and
|
||||||
* additional data is given object's OMA.
|
* additional data is given object's OMA.
|
||||||
*
|
*
|
||||||
* @param objectStructure
|
* @param ipo
|
||||||
* the structure of the object
|
* the object's interpolation curves
|
||||||
|
* @param objectAnimationName
|
||||||
|
* the name of object's animation
|
||||||
|
* @param objectOMA
|
||||||
|
* the OMA of the object
|
||||||
* @param blenderContext
|
* @param blenderContext
|
||||||
* the blender context
|
* the blender context
|
||||||
* @return animation modifier is returned, it should be separately applied
|
|
||||||
* when the object is loaded
|
|
||||||
* @throws BlenderFileException
|
* @throws BlenderFileException
|
||||||
* this exception is thrown when the blender file is somehow
|
* this exception is thrown when the blender file is somehow
|
||||||
* corrupted
|
* corrupted
|
||||||
*/
|
*/
|
||||||
public ObjectAnimationModifier(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException {
|
public ObjectAnimationModifier(Ipo ipo, String objectAnimationName, Long objectOMA, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
objectOMA = objectStructure.getOldMemoryAddress();
|
int fps = blenderContext.getBlenderKey().getFps();
|
||||||
Pointer pIpo = (Pointer) objectStructure.getFieldValue("ipo");
|
|
||||||
if (pIpo.isNotNull()) {
|
|
||||||
// check if there is an action name connected with this ipo
|
|
||||||
String objectAnimationName = null;
|
|
||||||
List<FileBlockHeader> actionBlocks = blenderContext.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00));
|
|
||||||
if(actionBlocks != null) {
|
|
||||||
for (FileBlockHeader actionBlock : actionBlocks) {
|
|
||||||
Structure action = actionBlock.getStructure(blenderContext);
|
|
||||||
List<Structure> actionChannels = ((Structure) action.getFieldValue("chanbase")).evaluateListBase(blenderContext);
|
|
||||||
if (actionChannels.size() == 1) {// object's animtion action has only one channel
|
|
||||||
Pointer pChannelIpo = (Pointer) actionChannels.get(0).getFieldValue("ipo");
|
|
||||||
if (pChannelIpo.equals(pIpo)) {
|
|
||||||
objectAnimationName = action.getName();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String objectName = objectStructure.getName();
|
// calculating track
|
||||||
if (objectAnimationName == null) {// set the object's animation name to object's name
|
SpatialTrack track = (SpatialTrack) ipo.calculateTrack(-1, 0, ipo.getLastFrame(), fps, true);
|
||||||
objectAnimationName = objectName;
|
|
||||||
}
|
|
||||||
|
|
||||||
IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class);
|
Animation animation = new Animation(objectAnimationName, ipo.getLastFrame() / fps);
|
||||||
Structure ipoStructure = pIpo.fetchData(blenderContext.getInputStream()).get(0);
|
animation.setTracks(new SpatialTrack[] { track });
|
||||||
Ipo ipo = ipoHelper.createIpo(ipoStructure, blenderContext);
|
ArrayList<Animation> animations = new ArrayList<Animation>(1);
|
||||||
int fps = blenderContext.getBlenderKey().getFps();
|
animations.add(animation);
|
||||||
|
|
||||||
// calculating track for the only bone in this skeleton
|
animData = new AnimData(null, animations);
|
||||||
SpatialTrack track = (SpatialTrack) ipo.calculateTrack(-1, 0, ipo.getLastFrame(), fps);
|
blenderContext.setAnimData(objectOMA, animData);
|
||||||
|
|
||||||
Animation animation = new Animation(objectAnimationName, ipo.getLastFrame() / fps);
|
|
||||||
animation.setTracks(new SpatialTrack[] { track });
|
|
||||||
ArrayList<Animation> animations = new ArrayList<Animation>(1);
|
|
||||||
animations.add(animation);
|
|
||||||
|
|
||||||
animData = new AnimData(null, animations);
|
|
||||||
blenderContext.setAnimData(objectOMA, animData);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Node apply(Node node, BlenderContext blenderContext) {
|
public Node apply(Node node, BlenderContext blenderContext) {
|
||||||
if(invalid) {
|
if (invalid) {
|
||||||
LOGGER.log(Level.WARNING, "Armature modifier is invalid! Cannot be applied to: {0}", node.getName());
|
LOGGER.log(Level.WARNING, "Armature modifier is invalid! Cannot be applied to: {0}", node.getName());
|
||||||
}//if invalid, animData will be null
|
}// if invalid, animData will be null
|
||||||
if(animData != null) {
|
if (animData != null) {
|
||||||
//INFO: constraints for this modifier are applied in the ObjectHelper when the whole object is loaded
|
// INFO: constraints for this modifier are applied in the
|
||||||
|
// ObjectHelper when the whole object is loaded
|
||||||
ArrayList<Animation> animList = animData.anims;
|
ArrayList<Animation> animList = animData.anims;
|
||||||
if (animList != null && animList.size() > 0) {
|
if (animList != null && animList.size() > 0) {
|
||||||
HashMap<String, Animation> anims = new HashMap<String, Animation>();
|
HashMap<String, Animation> anims = new HashMap<String, Animation>();
|
||||||
|
@ -261,7 +261,7 @@ public class ObjectHelper extends AbstractBlenderHelper {
|
|||||||
List<Constraint> objectConstraints = blenderContext.getConstraints(objectStructure.getOldMemoryAddress());
|
List<Constraint> objectConstraints = blenderContext.getConstraints(objectStructure.getOldMemoryAddress());
|
||||||
if(objectConstraints!=null) {
|
if(objectConstraints!=null) {
|
||||||
for(Constraint objectConstraint : objectConstraints) {
|
for(Constraint objectConstraint : objectConstraints) {
|
||||||
objectConstraint.bake(Constraint.BAKE_STATIC);
|
objectConstraint.bake();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user