Many changes to blender importer:
- constraints refactoring (easier use and less code) - constraints support for blender 2.50+ (although not all of the constraints are supported) - Y is up axis issue fixed for animations - owner and target spaces evaluation support for constraints (two bone space modes still to do) - simplified code for bones loading (though still needs some refactoring) git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@8877 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
This commit is contained in:
parent
fb2d8c647d
commit
a1d73d159d
@ -60,17 +60,11 @@ public abstract class AbstractBlenderHelper {
|
|||||||
* versions.
|
* versions.
|
||||||
* @param blenderVersion
|
* @param blenderVersion
|
||||||
* the version read from the blend file
|
* the version read from the blend file
|
||||||
*/
|
|
||||||
public AbstractBlenderHelper(String blenderVersion) {
|
|
||||||
this.blenderVersion = Integer.parseInt(blenderVersion);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method sets the Y is UP axis. By default the UP axis is Z (just like in blender).
|
|
||||||
* @param fixUpAxis
|
* @param fixUpAxis
|
||||||
* a variable that indicates if the Y asxis is the UP axis or not
|
* a variable that indicates if the Y asxis is the UP axis or not
|
||||||
*/
|
*/
|
||||||
public void setyIsUpAxis(boolean fixUpAxis) {
|
public AbstractBlenderHelper(String blenderVersion, boolean fixUpAxis) {
|
||||||
|
this.blenderVersion = Integer.parseInt(blenderVersion);
|
||||||
this.fixUpAxis = fixUpAxis;
|
this.fixUpAxis = fixUpAxis;
|
||||||
if(fixUpAxis) {
|
if(fixUpAxis) {
|
||||||
upAxisRotationQuaternion = new Quaternion().fromAngles(-FastMath.HALF_PI, 0, 0);
|
upAxisRotationQuaternion = new Quaternion().fromAngles(-FastMath.HALF_PI, 0, 0);
|
||||||
|
@ -31,6 +31,16 @@
|
|||||||
*/
|
*/
|
||||||
package com.jme3.scene.plugins.blender;
|
package com.jme3.scene.plugins.blender;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.EmptyStackException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Stack;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import com.jme3.asset.AssetManager;
|
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;
|
||||||
@ -44,14 +54,13 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
import com.jme3.scene.plugins.blender.materials.MaterialContext;
|
import com.jme3.scene.plugins.blender.materials.MaterialContext;
|
||||||
import com.jme3.scene.plugins.blender.meshes.MeshContext;
|
import com.jme3.scene.plugins.blender.meshes.MeshContext;
|
||||||
import com.jme3.scene.plugins.blender.modifiers.Modifier;
|
import com.jme3.scene.plugins.blender.modifiers.Modifier;
|
||||||
import java.io.IOException;
|
import com.jme3.scene.plugins.ogre.AnimData;
|
||||||
import java.util.*;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The class that stores temporary data and manages it during loading the belnd file. This class is intended to be used
|
* The class that stores temporary data and manages it during loading the belnd
|
||||||
* in a single loading thread. It holds the state of loading operations.
|
* file. This class is intended to be used in a single loading thread. It holds
|
||||||
|
* the state of loading operations.
|
||||||
|
*
|
||||||
* @author Marcin Roguski (Kaelthas)
|
* @author Marcin Roguski (Kaelthas)
|
||||||
*/
|
*/
|
||||||
public class BlenderContext {
|
public class BlenderContext {
|
||||||
@ -65,29 +74,39 @@ public class BlenderContext {
|
|||||||
private BlenderInputStream inputStream;
|
private BlenderInputStream inputStream;
|
||||||
/** The asset manager. */
|
/** The asset manager. */
|
||||||
private AssetManager assetManager;
|
private AssetManager assetManager;
|
||||||
/** A map containing the file block headers. The key is the old pointer address. */
|
/**
|
||||||
|
* A map containing the file block headers. The key is the old pointer
|
||||||
|
* address.
|
||||||
|
*/
|
||||||
private Map<Long, FileBlockHeader> fileBlockHeadersByOma = new HashMap<Long, FileBlockHeader>();
|
private Map<Long, FileBlockHeader> fileBlockHeadersByOma = new HashMap<Long, FileBlockHeader>();
|
||||||
/** A map containing the file block headers. The key is the block code. */
|
/** A map containing the file block headers. The key is the block code. */
|
||||||
private Map<Integer, List<FileBlockHeader>> fileBlockHeadersByCode = new HashMap<Integer, List<FileBlockHeader>>();
|
private Map<Integer, List<FileBlockHeader>> fileBlockHeadersByCode = new HashMap<Integer, List<FileBlockHeader>>();
|
||||||
/**
|
/**
|
||||||
* This map stores the loaded features by their old memory address. The first object in the value table is the
|
* This map stores the loaded features by their old memory address. The
|
||||||
* loaded structure and the second - the structure already converted into proper data.
|
* first object in the value table is the loaded structure and the second -
|
||||||
|
* the structure already converted into proper data.
|
||||||
*/
|
*/
|
||||||
private Map<Long, Object[]> loadedFeatures = new HashMap<Long, Object[]>();
|
private Map<Long, Object[]> loadedFeatures = new HashMap<Long, Object[]>();
|
||||||
/**
|
/**
|
||||||
* This map stores the loaded features by their name. Only features with ID structure can be stored here.
|
* This map stores the loaded features by their name. Only features with ID
|
||||||
* The first object in the value table is the
|
* structure can be stored here. The first object in the value table is the
|
||||||
* loaded structure and the second - the structure already converted into proper data.
|
* loaded structure and the second - the structure already converted into
|
||||||
|
* proper data.
|
||||||
*/
|
*/
|
||||||
private Map<String, Object[]> loadedFeaturesByName = new HashMap<String, Object[]>();
|
private Map<String, Object[]> loadedFeaturesByName = new HashMap<String, Object[]>();
|
||||||
/** A stack that hold the parent structure of currently loaded feature. */
|
/** A stack that hold the parent structure of currently loaded feature. */
|
||||||
private Stack<Structure> parentStack = new Stack<Structure>();
|
private Stack<Structure> parentStack = new Stack<Structure>();
|
||||||
/** A map storing loaded ipos. The key is the ipo's owner old memory address and the value is the ipo. */
|
/**
|
||||||
|
* A map storing loaded ipos. The key is the ipo's owner old memory address
|
||||||
|
* and the value is the ipo.
|
||||||
|
*/
|
||||||
private Map<Long, Ipo> loadedIpos = new HashMap<Long, Ipo>();
|
private Map<Long, Ipo> loadedIpos = new HashMap<Long, Ipo>();
|
||||||
/** A list of modifiers for the specified object. */
|
/** A list of modifiers for the specified object. */
|
||||||
protected Map<Long, List<Modifier>> modifiers = new HashMap<Long, List<Modifier>>();
|
protected Map<Long, List<Modifier>> modifiers = new HashMap<Long, List<Modifier>>();
|
||||||
/** A list of constraints for the specified object. */
|
/** A list of constraints for the specified object. */
|
||||||
protected Map<Long, List<Constraint>> constraints = new HashMap<Long, List<Constraint>>();
|
protected Map<Long, List<Constraint>> constraints = new HashMap<Long, List<Constraint>>();
|
||||||
|
/** Anim data loaded for features. */
|
||||||
|
private Map<Long, AnimData> animData = new HashMap<Long, AnimData>();
|
||||||
/** 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 material contexts. */
|
/** A map of material contexts. */
|
||||||
@ -97,6 +116,7 @@ public class BlenderContext {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This method sets the blender key.
|
* This method sets the blender key.
|
||||||
|
*
|
||||||
* @param blenderKey
|
* @param blenderKey
|
||||||
* the blender key
|
* the blender key
|
||||||
*/
|
*/
|
||||||
@ -106,6 +126,7 @@ public class BlenderContext {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns the blender key.
|
* This method returns the blender key.
|
||||||
|
*
|
||||||
* @return the blender key
|
* @return the blender key
|
||||||
*/
|
*/
|
||||||
public BlenderKey getBlenderKey() {
|
public BlenderKey getBlenderKey() {
|
||||||
@ -114,6 +135,7 @@ public class BlenderContext {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This method sets the dna block data.
|
* This method sets the dna block data.
|
||||||
|
*
|
||||||
* @param dnaBlockData
|
* @param dnaBlockData
|
||||||
* the dna block data
|
* the dna block data
|
||||||
*/
|
*/
|
||||||
@ -123,6 +145,7 @@ public class BlenderContext {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns the dna block data.
|
* This method returns the dna block data.
|
||||||
|
*
|
||||||
* @return the dna block data
|
* @return the dna block data
|
||||||
*/
|
*/
|
||||||
public DnaBlockData getDnaBlockData() {
|
public DnaBlockData getDnaBlockData() {
|
||||||
@ -131,6 +154,7 @@ public class BlenderContext {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns the asset manager.
|
* This method returns the asset manager.
|
||||||
|
*
|
||||||
* @return the asset manager
|
* @return the asset manager
|
||||||
*/
|
*/
|
||||||
public AssetManager getAssetManager() {
|
public AssetManager getAssetManager() {
|
||||||
@ -139,6 +163,7 @@ public class BlenderContext {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This method sets the asset manager.
|
* This method sets the asset manager.
|
||||||
|
*
|
||||||
* @param assetManager
|
* @param assetManager
|
||||||
* the asset manager
|
* the asset manager
|
||||||
*/
|
*/
|
||||||
@ -148,6 +173,7 @@ public class BlenderContext {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns the input stream of the blend file.
|
* This method returns the input stream of the blend file.
|
||||||
|
*
|
||||||
* @return the input stream of the blend file
|
* @return the input stream of the blend file
|
||||||
*/
|
*/
|
||||||
public BlenderInputStream getInputStream() {
|
public BlenderInputStream getInputStream() {
|
||||||
@ -156,6 +182,7 @@ public class BlenderContext {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This method sets the input stream of the blend file.
|
* This method sets the input stream of the blend file.
|
||||||
|
*
|
||||||
* @param inputStream
|
* @param inputStream
|
||||||
* the input stream of the blend file
|
* the input stream of the blend file
|
||||||
*/
|
*/
|
||||||
@ -164,7 +191,9 @@ public class BlenderContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method adds a file block header to the map. Its old memory address is the key.
|
* This method adds a file block header to the map. Its old memory address
|
||||||
|
* is the key.
|
||||||
|
*
|
||||||
* @param oldMemoryAddress
|
* @param oldMemoryAddress
|
||||||
* the address of the block header
|
* the address of the block header
|
||||||
* @param fileBlockHeader
|
* @param fileBlockHeader
|
||||||
@ -181,8 +210,9 @@ public class BlenderContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns the block header of a given memory address. If the header is not present then null is
|
* This method returns the block header of a given memory address. If the
|
||||||
* returned.
|
* header is not present then null is returned.
|
||||||
|
*
|
||||||
* @param oldMemoryAddress
|
* @param oldMemoryAddress
|
||||||
* the address of the block header
|
* the address of the block header
|
||||||
* @return loaded header or null if it was not yet loaded
|
* @return loaded header or null if it was not yet loaded
|
||||||
@ -193,6 +223,7 @@ public class BlenderContext {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns a list of file blocks' headers of a specified code.
|
* This method returns a list of file blocks' headers of a specified code.
|
||||||
|
*
|
||||||
* @param code
|
* @param code
|
||||||
* the code of file blocks
|
* the code of file blocks
|
||||||
* @return a list of file blocks' headers of a specified code
|
* @return a list of file blocks' headers of a specified code
|
||||||
@ -211,6 +242,7 @@ public class BlenderContext {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This method adds a helper instance to the helpers' map.
|
* This method adds a helper instance to the helpers' map.
|
||||||
|
*
|
||||||
* @param <T>
|
* @param <T>
|
||||||
* the type of the helper
|
* the type of the helper
|
||||||
* @param clazz
|
* @param clazz
|
||||||
@ -228,10 +260,13 @@ public class BlenderContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method adds a loaded feature to the map. The key is its unique old memory address.
|
* This method adds a loaded feature to the map. The key is its unique old
|
||||||
|
* memory address.
|
||||||
|
*
|
||||||
* @param oldMemoryAddress
|
* @param oldMemoryAddress
|
||||||
* the address of the feature
|
* the address of the feature
|
||||||
* @param featureName the name of the feature
|
* @param featureName
|
||||||
|
* the name of the feature
|
||||||
* @param structure
|
* @param structure
|
||||||
* the filled structure of the feature
|
* the filled structure of the feature
|
||||||
* @param feature
|
* @param feature
|
||||||
@ -241,7 +276,7 @@ public class BlenderContext {
|
|||||||
if (oldMemoryAddress == null || structure == null || feature == null) {
|
if (oldMemoryAddress == null || structure == null || feature == null) {
|
||||||
throw new IllegalArgumentException("One of the given arguments is null!");
|
throw new IllegalArgumentException("One of the given arguments is null!");
|
||||||
}
|
}
|
||||||
Object[] storedData = new Object[]{structure, feature};
|
Object[] storedData = new Object[] { structure, feature };
|
||||||
loadedFeatures.put(oldMemoryAddress, storedData);
|
loadedFeatures.put(oldMemoryAddress, storedData);
|
||||||
if (featureName != null) {
|
if (featureName != null) {
|
||||||
loadedFeaturesByName.put(featureName, storedData);
|
loadedFeaturesByName.put(featureName, storedData);
|
||||||
@ -249,12 +284,14 @@ public class BlenderContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns the feature of a given memory address. If the feature is not yet loaded then null is
|
* This method returns the feature of a given memory address. If the feature
|
||||||
* returned.
|
* is not yet loaded then null is returned.
|
||||||
|
*
|
||||||
* @param oldMemoryAddress
|
* @param oldMemoryAddress
|
||||||
* the address of the feature
|
* the address of the feature
|
||||||
* @param loadedFeatureDataType
|
* @param loadedFeatureDataType
|
||||||
* the type of data we want to retreive it can be either filled structure or already converted feature
|
* the type of data we want to retreive it can be either filled
|
||||||
|
* structure or already converted feature
|
||||||
* @return loaded feature or null if it was not yet loaded
|
* @return loaded feature or null if it was not yet loaded
|
||||||
*/
|
*/
|
||||||
public Object getLoadedFeature(Long oldMemoryAddress, LoadedFeatureDataType loadedFeatureDataType) {
|
public Object getLoadedFeature(Long oldMemoryAddress, LoadedFeatureDataType loadedFeatureDataType) {
|
||||||
@ -266,12 +303,14 @@ public class BlenderContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns the feature of a given name. If the feature is not yet loaded then null is
|
* This method returns the feature of a given name. If the feature is not
|
||||||
* returned.
|
* yet loaded then null is returned.
|
||||||
|
*
|
||||||
* @param featureName
|
* @param featureName
|
||||||
* the name of the feature
|
* the name of the feature
|
||||||
* @param loadedFeatureDataType
|
* @param loadedFeatureDataType
|
||||||
* the type of data we want to retreive it can be either filled structure or already converted feature
|
* the type of data we want to retreive it can be either filled
|
||||||
|
* structure or already converted feature
|
||||||
* @return loaded feature or null if it was not yet loaded
|
* @return loaded feature or null if it was not yet loaded
|
||||||
*/
|
*/
|
||||||
public Object getLoadedFeature(String featureName, LoadedFeatureDataType loadedFeatureDataType) {
|
public Object getLoadedFeature(String featureName, LoadedFeatureDataType loadedFeatureDataType) {
|
||||||
@ -291,6 +330,7 @@ public class BlenderContext {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This method adds the structure to the parent stack.
|
* This method adds the structure to the parent stack.
|
||||||
|
*
|
||||||
* @param parent
|
* @param parent
|
||||||
* the structure to be added to the stack
|
* the structure to be added to the stack
|
||||||
*/
|
*/
|
||||||
@ -300,6 +340,7 @@ public class BlenderContext {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This method removes the structure from the top of the parent's stack.
|
* This method removes the structure from the top of the parent's stack.
|
||||||
|
*
|
||||||
* @return the structure that was removed from the stack
|
* @return the structure that was removed from the stack
|
||||||
*/
|
*/
|
||||||
public Structure popParent() {
|
public Structure popParent() {
|
||||||
@ -311,7 +352,9 @@ public class BlenderContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method retreives the structure at the top of the parent's stack but does not remove it.
|
* This method retreives the structure at the top of the parent's stack but
|
||||||
|
* does not remove it.
|
||||||
|
*
|
||||||
* @return the structure from the top of the stack
|
* @return the structure from the top of the stack
|
||||||
*/
|
*/
|
||||||
public Structure peekParent() {
|
public Structure peekParent() {
|
||||||
@ -322,20 +365,45 @@ public class BlenderContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method adds new ipo curve for the feature.
|
||||||
|
*
|
||||||
|
* @param ownerOMA
|
||||||
|
* the OMA of blender feature that owns the ipo
|
||||||
|
* @param ipo
|
||||||
|
* the ipo to be added
|
||||||
|
*/
|
||||||
public void addIpo(Long ownerOMA, Ipo ipo) {
|
public void addIpo(Long ownerOMA, Ipo ipo) {
|
||||||
loadedIpos.put(ownerOMA, ipo);
|
loadedIpos.put(ownerOMA, ipo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method removes the ipo curve from the feature.
|
||||||
|
*
|
||||||
|
* @param ownerOMA
|
||||||
|
* the OMA of blender feature that owns the ipo
|
||||||
|
* @param ipo
|
||||||
|
* the ipo that was just removed
|
||||||
|
*/
|
||||||
public Ipo removeIpo(Long ownerOma) {
|
public Ipo removeIpo(Long ownerOma) {
|
||||||
return loadedIpos.remove(ownerOma);
|
return loadedIpos.remove(ownerOma);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the ipo curve of the feature.
|
||||||
|
*
|
||||||
|
* @param ownerOMA
|
||||||
|
* the OMA of blender feature that owns the ipo
|
||||||
|
* @param ipo
|
||||||
|
* the ipo that belongs to the specified owner
|
||||||
|
*/
|
||||||
public Ipo getIpo(Long ownerOMA) {
|
public Ipo getIpo(Long ownerOMA) {
|
||||||
return loadedIpos.get(ownerOMA);
|
return loadedIpos.get(ownerOMA);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method adds a new modifier to the list.
|
* This method adds a new modifier to the list.
|
||||||
|
*
|
||||||
* @param ownerOMA
|
* @param ownerOMA
|
||||||
* the owner's old memory address
|
* the owner's old memory address
|
||||||
* @param modifier
|
* @param modifier
|
||||||
@ -351,8 +419,11 @@ public class BlenderContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns modifiers for the object specified by its old memory address and the modifier type. If no
|
* This method returns modifiers for the object specified by its old memory
|
||||||
* modifiers are found - empty list is returned. If the type is null - all modifiers for the object are returned.
|
* address and the modifier type. If no modifiers are found - empty list is
|
||||||
|
* returned. If the type is null - all modifiers for the object are
|
||||||
|
* returned.
|
||||||
|
*
|
||||||
* @param objectOMA
|
* @param objectOMA
|
||||||
* object's old memory address
|
* object's old memory address
|
||||||
* @param type
|
* @param type
|
||||||
@ -374,6 +445,7 @@ public class BlenderContext {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This method adds a new modifier to the list.
|
* This method adds a new modifier to the list.
|
||||||
|
*
|
||||||
* @param ownerOMA
|
* @param ownerOMA
|
||||||
* the owner's old memory address
|
* the owner's old memory address
|
||||||
* @param constraints
|
* @param constraints
|
||||||
@ -389,19 +461,44 @@ public class BlenderContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns constraints for the object specified by its old memory address. If no
|
* This method returns constraints for the object specified by its old
|
||||||
* modifiers are found - <b>null</b> is returned.
|
* memory address. If no modifiers are found - <b>null</b> is returned.
|
||||||
|
*
|
||||||
* @param objectOMA
|
* @param objectOMA
|
||||||
* object's old memory address
|
* object's old memory address
|
||||||
* @return the list of object's modifiers or null
|
* @return the list of object's modifiers or null
|
||||||
*/
|
*/
|
||||||
public List<Constraint> getConstraints(Long objectOMA) {
|
public List<Constraint> getConstraints(Long objectOMA) {
|
||||||
return constraints.get(objectOMA);
|
return objectOMA == null ? null : constraints.get(objectOMA);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method sets the anim data for the specified OMA of its owner.
|
||||||
|
*
|
||||||
|
* @param ownerOMA
|
||||||
|
* the owner's old memory address
|
||||||
|
* @param animData
|
||||||
|
* the animation data for the feature specified by ownerOMA
|
||||||
|
*/
|
||||||
|
public void setAnimData(Long ownerOMA, AnimData animData) {
|
||||||
|
this.animData.put(ownerOMA, animData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the animation data for the specified owner.
|
||||||
|
*
|
||||||
|
* @param ownerOMA
|
||||||
|
* the old memory address of the animation data owner
|
||||||
|
* @return the animation data or null if none exists
|
||||||
|
*/
|
||||||
|
public AnimData getAnimData(Long ownerOMA) {
|
||||||
|
return this.animData.get(ownerOMA);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method sets the mesh context for the given mesh old memory address.
|
* This method sets the mesh context for the given mesh old memory address.
|
||||||
* If the context is already set it will be replaced.
|
* If the context is already set it will be replaced.
|
||||||
|
*
|
||||||
* @param meshOMA
|
* @param meshOMA
|
||||||
* the mesh's old memory address
|
* the mesh's old memory address
|
||||||
* @param meshContext
|
* @param meshContext
|
||||||
@ -412,8 +509,9 @@ public class BlenderContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns the mesh context for the given mesh old memory address.
|
* This method returns the mesh context for the given mesh old memory
|
||||||
* If no context exists then <b>null</b> is returned.
|
* address. If no context exists then <b>null</b> is returned.
|
||||||
|
*
|
||||||
* @param meshOMA
|
* @param meshOMA
|
||||||
* the mesh's old memory address
|
* the mesh's old memory address
|
||||||
* @return mesh's context
|
* @return mesh's context
|
||||||
@ -423,8 +521,9 @@ public class BlenderContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method sets the material context for the given material.
|
* This method sets the material context for the given material. If the
|
||||||
* If the context is already set it will be replaced.
|
* context is already set it will be replaced.
|
||||||
|
*
|
||||||
* @param material
|
* @param material
|
||||||
* the material
|
* the material
|
||||||
* @param materialContext
|
* @param materialContext
|
||||||
@ -435,8 +534,9 @@ public class BlenderContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns the material context for the given material.
|
* This method returns the material context for the given material. If no
|
||||||
* If no context exists then <b>null</b> is returned.
|
* context exists then <b>null</b> is returned.
|
||||||
|
*
|
||||||
* @param material
|
* @param material
|
||||||
* the material
|
* the material
|
||||||
* @return material's context
|
* @return material's context
|
||||||
@ -447,6 +547,7 @@ public class BlenderContext {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This metod returns the default material.
|
* This metod returns the default material.
|
||||||
|
*
|
||||||
* @return the default material
|
* @return the default material
|
||||||
*/
|
*/
|
||||||
public synchronized Material getDefaultMaterial() {
|
public synchronized Material getDefaultMaterial() {
|
||||||
@ -469,8 +570,9 @@ public class BlenderContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This enum defines what loaded data type user wants to retreive. It can be either filled structure or already
|
* This enum defines what loaded data type user wants to retreive. It can be
|
||||||
* converted data.
|
* either filled structure or already converted data.
|
||||||
|
*
|
||||||
* @author Marcin Roguski
|
* @author Marcin Roguski
|
||||||
*/
|
*/
|
||||||
public static enum LoadedFeatureDataType {
|
public static enum LoadedFeatureDataType {
|
||||||
|
@ -189,30 +189,20 @@ public class BlenderLoader extends AbstractBlenderLoader {
|
|||||||
blenderContext.setBlenderKey(blenderKey);
|
blenderContext.setBlenderKey(blenderKey);
|
||||||
|
|
||||||
// creating helpers
|
// creating helpers
|
||||||
blenderContext.putHelper(ArmatureHelper.class, new ArmatureHelper(inputStream.getVersionNumber()));
|
blenderContext.putHelper(ArmatureHelper.class, new ArmatureHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis()));
|
||||||
blenderContext.putHelper(TextureHelper.class, new TextureHelper(inputStream.getVersionNumber()));
|
blenderContext.putHelper(TextureHelper.class, new TextureHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis()));
|
||||||
blenderContext.putHelper(MeshHelper.class, new MeshHelper(inputStream.getVersionNumber()));
|
blenderContext.putHelper(MeshHelper.class, new MeshHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis()));
|
||||||
blenderContext.putHelper(ObjectHelper.class, new ObjectHelper(inputStream.getVersionNumber()));
|
blenderContext.putHelper(ObjectHelper.class, new ObjectHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis()));
|
||||||
blenderContext.putHelper(CurvesHelper.class, new CurvesHelper(inputStream.getVersionNumber()));
|
blenderContext.putHelper(CurvesHelper.class, new CurvesHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis()));
|
||||||
blenderContext.putHelper(LightHelper.class, new LightHelper(inputStream.getVersionNumber()));
|
blenderContext.putHelper(LightHelper.class, new LightHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis()));
|
||||||
blenderContext.putHelper(CameraHelper.class, new CameraHelper(inputStream.getVersionNumber()));
|
blenderContext.putHelper(CameraHelper.class, new CameraHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis()));
|
||||||
blenderContext.putHelper(ModifierHelper.class, new ModifierHelper(inputStream.getVersionNumber()));
|
blenderContext.putHelper(ModifierHelper.class, new ModifierHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis()));
|
||||||
blenderContext.putHelper(MaterialHelper.class, new MaterialHelper(inputStream.getVersionNumber()));
|
blenderContext.putHelper(MaterialHelper.class, new MaterialHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis()));
|
||||||
blenderContext.putHelper(ConstraintHelper.class, new ConstraintHelper(inputStream.getVersionNumber(), blenderContext));
|
blenderContext.putHelper(ConstraintHelper.class, new ConstraintHelper(inputStream.getVersionNumber(), blenderContext, blenderKey.isFixUpAxis()));
|
||||||
blenderContext.putHelper(IpoHelper.class, new IpoHelper(inputStream.getVersionNumber()));
|
blenderContext.putHelper(IpoHelper.class, new IpoHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis()));
|
||||||
blenderContext.putHelper(ParticlesHelper.class, new ParticlesHelper(inputStream.getVersionNumber()));
|
blenderContext.putHelper(ParticlesHelper.class, new ParticlesHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis()));
|
||||||
|
|
||||||
// setting additional data to helpers
|
// setting additional data to helpers
|
||||||
if (blenderKey.isFixUpAxis()) {
|
|
||||||
AbstractBlenderHelper helper = blenderContext.getHelper(ObjectHelper.class);
|
|
||||||
helper.setyIsUpAxis(true);
|
|
||||||
helper = blenderContext.getHelper(CurvesHelper.class);
|
|
||||||
helper.setyIsUpAxis(true);
|
|
||||||
helper = blenderContext.getHelper(ArmatureHelper.class);
|
|
||||||
helper.setyIsUpAxis(true);
|
|
||||||
helper = blenderContext.getHelper(MeshHelper.class);
|
|
||||||
helper.setyIsUpAxis(true);
|
|
||||||
}
|
|
||||||
MaterialHelper materialHelper = blenderContext.getHelper(MaterialHelper.class);
|
MaterialHelper materialHelper = blenderContext.getHelper(MaterialHelper.class);
|
||||||
materialHelper.setFaceCullMode(blenderKey.getFaceCullMode());
|
materialHelper.setFaceCullMode(blenderKey.getFaceCullMode());
|
||||||
|
|
||||||
|
@ -31,16 +31,6 @@
|
|||||||
*/
|
*/
|
||||||
package com.jme3.scene.plugins.blender.animations;
|
package com.jme3.scene.plugins.blender.animations;
|
||||||
|
|
||||||
import com.jme3.animation.Bone;
|
|
||||||
import com.jme3.animation.BoneTrack;
|
|
||||||
import com.jme3.math.Matrix4f;
|
|
||||||
import com.jme3.math.Quaternion;
|
|
||||||
import com.jme3.math.Vector3f;
|
|
||||||
import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
|
|
||||||
import com.jme3.scene.plugins.blender.BlenderContext;
|
|
||||||
import com.jme3.scene.plugins.blender.curves.BezierCurve;
|
|
||||||
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
|
||||||
import com.jme3.scene.plugins.blender.file.*;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -48,33 +38,119 @@ import java.util.Map;
|
|||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import com.jme3.animation.Bone;
|
||||||
|
import com.jme3.animation.BoneTrack;
|
||||||
|
import com.jme3.animation.Skeleton;
|
||||||
|
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.BlenderContext;
|
||||||
|
import com.jme3.scene.plugins.blender.curves.BezierCurve;
|
||||||
|
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.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
|
* @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. */
|
||||||
|
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. Some functionalities may differ in
|
||||||
* different blender versions.
|
* different blender versions.
|
||||||
* @param blenderVersion
|
* @param blenderVersion
|
||||||
* the version read from the blend file
|
* the version read from the blend file
|
||||||
|
* @param fixUpAxis
|
||||||
|
* a variable that indicates if the Y asxis is the UP axis or not
|
||||||
*/
|
*/
|
||||||
public ArmatureHelper(String blenderVersion) {
|
public ArmatureHelper(String blenderVersion, boolean fixUpAxis) {
|
||||||
super(blenderVersion);
|
super(blenderVersion, fixUpAxis);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The map of the bones. Maps a bone name to its index in the armature. Should be cleared after the object had been
|
* This method builds the object's bones structure.
|
||||||
* read. TODO: probably bones can have identical names in different armatures
|
*
|
||||||
|
* @param boneStructure
|
||||||
|
* the structure containing the bones' data
|
||||||
|
* @param parent
|
||||||
|
* the parent bone
|
||||||
|
* @param result
|
||||||
|
* the list where the newly created bone will be added
|
||||||
|
* @param bonesPoseChannels
|
||||||
|
* a map of bones poses channels
|
||||||
|
* @param blenderContext
|
||||||
|
* the blender context
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* an exception is thrown when there is problem with the blender
|
||||||
|
* file
|
||||||
*/
|
*/
|
||||||
protected Map<String, Integer> bonesMap = new HashMap<String, Integer>();
|
@SuppressWarnings("unchecked")
|
||||||
/** A map of bones and their old memory addresses. */
|
public void buildBones(Structure boneStructure, Bone parent, List<Bone> result, Matrix4f arbt,
|
||||||
protected Map<Bone, Long> bonesOMAs = new HashMap<Bone, Long>();
|
final Map<Long, Structure> bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
/** This list contains bones hierarchy and their matrices. It is later converted into jme bones. */
|
String boneName = boneStructure.getFieldValue("name").toString();
|
||||||
protected List<BoneTransformationData> boneDataRoots = new ArrayList<BoneTransformationData>();
|
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
|
* This method returns the old memory address of a bone. If the bone does not exist in the blend file - zero is
|
||||||
@ -91,6 +167,16 @@ public class ArmatureHelper extends AbstractBlenderHelper {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the bind transform for the specified bone.
|
||||||
|
* @param bone
|
||||||
|
* the bone
|
||||||
|
* @return bone's bind transform
|
||||||
|
*/
|
||||||
|
public Transform getBoneBindTransform(Bone bone) {
|
||||||
|
return boneBindTransforms.get(bone);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 is used by a bone and the key is the
|
||||||
* bone index in the armature.
|
* bone index in the armature.
|
||||||
@ -100,15 +186,15 @@ public class ArmatureHelper extends AbstractBlenderHelper {
|
|||||||
* @throws BlenderFileException
|
* @throws BlenderFileException
|
||||||
* this exception is thrown when the blender file is somehow corrupted
|
* this exception is thrown when the blender file is somehow corrupted
|
||||||
*/
|
*/
|
||||||
public Map<Integer, Integer> getGroupToBoneIndexMap(Structure defBaseStructure, BlenderContext blenderContext) throws BlenderFileException {
|
public Map<Integer, Integer> getGroupToBoneIndexMap(Structure defBaseStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
Map<Integer, Integer> result = null;
|
Map<Integer, Integer> result = null;
|
||||||
if (bonesMap != null && bonesMap.size() != 0) {
|
if (skeleton.getBoneCount() != 0) {
|
||||||
result = new HashMap<Integer, Integer>();
|
result = new HashMap<Integer, Integer>();
|
||||||
List<Structure> deformGroups = defBaseStructure.evaluateListBase(blenderContext);//bDeformGroup
|
List<Structure> deformGroups = defBaseStructure.evaluateListBase(blenderContext);//bDeformGroup
|
||||||
int groupIndex = 0;
|
int groupIndex = 0;
|
||||||
for (Structure deformGroup : deformGroups) {
|
for (Structure deformGroup : deformGroups) {
|
||||||
String deformGroupName = deformGroup.getFieldValue("name").toString();
|
String deformGroupName = deformGroup.getFieldValue("name").toString();
|
||||||
Integer boneIndex = bonesMap.get(deformGroupName);
|
Integer boneIndex = this.getBoneIndex(skeleton, deformGroupName);
|
||||||
if (boneIndex != null) {
|
if (boneIndex != null) {
|
||||||
result.put(Integer.valueOf(groupIndex), boneIndex);
|
result.put(Integer.valueOf(groupIndex), boneIndex);
|
||||||
}
|
}
|
||||||
@ -118,191 +204,6 @@ public class ArmatureHelper extends AbstractBlenderHelper {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This bone returns transformation matrix of the bone that is relative to
|
|
||||||
* its armature object.
|
|
||||||
* @param boneStructure the bone's structure
|
|
||||||
* @return bone's transformation matrix in armature space
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected Matrix4f getArmatureMatrix(Structure boneStructure) {
|
|
||||||
DynamicArray<Number> boneMat = (DynamicArray<Number>) boneStructure.getFieldValue("arm_mat");
|
|
||||||
Matrix4f m = new Matrix4f();
|
|
||||||
for (int i = 0; i < 4; ++i) {
|
|
||||||
for (int j = 0; j < 4; ++j) {
|
|
||||||
m.set(i, j, boneMat.get(j, i).floatValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(fixUpAxis) {
|
|
||||||
Vector3f translation = m.toTranslationVector();
|
|
||||||
Quaternion rotation = m.toRotationQuat();
|
|
||||||
|
|
||||||
float y = translation.y;
|
|
||||||
translation.y = translation.z;
|
|
||||||
translation.z = -y;
|
|
||||||
|
|
||||||
rotation = upAxisRotationQuaternion.mult(rotation);
|
|
||||||
|
|
||||||
m.setRotationQuaternion(rotation);
|
|
||||||
m.setTranslation(translation);
|
|
||||||
//TODO: what about scale ??
|
|
||||||
}
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method reads the bone with its children.
|
|
||||||
* @param boneStructure
|
|
||||||
* a structure containing the bone data
|
|
||||||
* @param parent
|
|
||||||
* the bone parent; if null then we read the root bone
|
|
||||||
* @param blenderContext
|
|
||||||
* the blender context
|
|
||||||
* @return the bone transformation data; contains bone chierarchy and the bone's matrices
|
|
||||||
* @throws BlenderFileException
|
|
||||||
* this exception is thrown when the blender file is somehow corrupted
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public BoneTransformationData readBoneAndItsChildren(Structure boneStructure, BoneTransformationData parent, BlenderContext blenderContext) throws BlenderFileException {
|
|
||||||
String name = boneStructure.getFieldValue("name").toString();
|
|
||||||
Bone bone = new Bone(name);
|
|
||||||
int bonesAmount = bonesOMAs.size();
|
|
||||||
bonesOMAs.put(bone, boneStructure.getOldMemoryAddress());
|
|
||||||
if (bonesAmount == bonesOMAs.size()) {
|
|
||||||
throw new IllegalStateException("Two bones has the same hash value and thereforw a bone was overriden in the bones<->OMA map! Improve the hash algorithm!");
|
|
||||||
}
|
|
||||||
Matrix4f boneArmatureMatrix = this.getArmatureMatrix(boneStructure);
|
|
||||||
DynamicArray<Float> sizeArray = (DynamicArray<Float>) boneStructure.getFieldValue("size");
|
|
||||||
Vector3f size = new Vector3f(sizeArray.get(0), sizeArray.get(1), sizeArray.get(2));
|
|
||||||
BoneTransformationData boneTransformationData = new BoneTransformationData(boneArmatureMatrix, size, bone, parent);
|
|
||||||
blenderContext.addLoadedFeatures(boneStructure.getOldMemoryAddress(), name, boneStructure, bone);
|
|
||||||
|
|
||||||
Structure childbase = (Structure) boneStructure.getFieldValue("childbase");
|
|
||||||
List<Structure> children = childbase.evaluateListBase(blenderContext);//Bone
|
|
||||||
for (Structure boneChild : children) {
|
|
||||||
this.readBoneAndItsChildren(boneChild, boneTransformationData, blenderContext);
|
|
||||||
}
|
|
||||||
return boneTransformationData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method assigns transformations to the bone.
|
|
||||||
* @param btd
|
|
||||||
* the bone data containing the bone we assign transformation to
|
|
||||||
* @param additionalRootBoneTransformation
|
|
||||||
* additional bone transformation which indicates it's mesh parent and armature object transformations
|
|
||||||
* @param boneList
|
|
||||||
* a list of all read bones
|
|
||||||
*/
|
|
||||||
protected void assignBonesMatrices(BoneTransformationData btd, Matrix4f additionalRootBoneTransformation, List<Bone> boneList) {
|
|
||||||
LOGGER.info("[" + btd.bone.getName() + "] additionalRootBoneTransformation =\n" + additionalRootBoneTransformation);
|
|
||||||
Matrix4f totalInverseParentMatrix = btd.parent != null ? btd.parent.totalInverseBoneParentMatrix : Matrix4f.IDENTITY;
|
|
||||||
LOGGER.info("[" + btd.bone.getName() + "] totalInverseParentMatrix =\n" + totalInverseParentMatrix);
|
|
||||||
Matrix4f restMatrix = additionalRootBoneTransformation.mult(btd.boneArmatureMatrix);
|
|
||||||
LOGGER.info("[" + btd.bone.getName() + "] restMatrix =\n" + restMatrix);
|
|
||||||
btd.totalInverseBoneParentMatrix = restMatrix.clone().invert();
|
|
||||||
restMatrix = totalInverseParentMatrix.mult(restMatrix);
|
|
||||||
LOGGER.info("[" + btd.bone.getName() + "] resultMatrix =\n" + restMatrix);
|
|
||||||
btd.bone.setBindTransforms(restMatrix.toTranslationVector(), restMatrix.toRotationQuat(), btd.size);
|
|
||||||
boneList.add(btd.bone);
|
|
||||||
bonesMap.put(btd.bone.getName(), Integer.valueOf(boneList.size() - 1));
|
|
||||||
if (btd.children != null && btd.children.size() > 0) {
|
|
||||||
for (BoneTransformationData child : btd.children) {
|
|
||||||
this.assignBonesMatrices(child, additionalRootBoneTransformation, boneList);
|
|
||||||
btd.bone.addChild(child.bone);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addBoneDataRoot(BoneTransformationData dataRoot) {
|
|
||||||
this.boneDataRoots.add(dataRoot);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns bone transformation data for the bone of a given index.
|
|
||||||
* @param index
|
|
||||||
* the index of the bone
|
|
||||||
* @return bone's transformation data
|
|
||||||
*/
|
|
||||||
public BoneTransformationData getBoneTransformationDataRoot(int index) {
|
|
||||||
return boneDataRoots.get(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns the amount of bones transformations roots.
|
|
||||||
* @return the amount of bones transformations roots
|
|
||||||
*/
|
|
||||||
public int getBoneTransformationDataRootsSize() {
|
|
||||||
return boneDataRoots.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class holds the data needed later for bone transformation calculation and to bind parent with children.
|
|
||||||
* @author Marcin Roguski
|
|
||||||
*/
|
|
||||||
public static class BoneTransformationData {
|
|
||||||
|
|
||||||
/** Inverse matrix of bone's parent bone. */
|
|
||||||
private Matrix4f totalInverseBoneParentMatrix;
|
|
||||||
/** Bone's matrix in armature's space. */
|
|
||||||
private Matrix4f boneArmatureMatrix;
|
|
||||||
/** Bone's size (apparently it is held outside the transformation matrix. */
|
|
||||||
private Vector3f size;
|
|
||||||
/** The bone the data applies to. */
|
|
||||||
private Bone bone;
|
|
||||||
/** The parent of the above mentioned bone (not assigned yet). */
|
|
||||||
private BoneTransformationData parent;
|
|
||||||
/** The children of the current bone. */
|
|
||||||
private List<BoneTransformationData> children;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Private constructor creates the object and assigns the given data.
|
|
||||||
* @param boneArmatureMatrix
|
|
||||||
* the matrix of the current bone
|
|
||||||
* @param size
|
|
||||||
* the bone's size
|
|
||||||
* @param bone
|
|
||||||
* the current bone
|
|
||||||
* @param parent
|
|
||||||
* the parent structure of the bone
|
|
||||||
*/
|
|
||||||
private BoneTransformationData(Matrix4f boneArmatureMatrix, Vector3f size, Bone bone, BoneTransformationData parent) {
|
|
||||||
this.boneArmatureMatrix = boneArmatureMatrix;
|
|
||||||
this.size = size;
|
|
||||||
this.bone = bone;
|
|
||||||
this.parent = parent;
|
|
||||||
this.children = new ArrayList<ArmatureHelper.BoneTransformationData>();
|
|
||||||
if (this.parent != null) {
|
|
||||||
this.parent.children.add(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method creates the whole bones structure. Assignes transformations to bones and combines children with
|
|
||||||
* parents.
|
|
||||||
* @param armatureOMA
|
|
||||||
* old memory address of bones' armature object
|
|
||||||
* @param additionalRootBoneTransformation
|
|
||||||
* additional bone transformation which indicates it's mesh parent and armature object transformations
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public Bone[] buildBonesStructure(Long armatureOMA, Matrix4f additionalRootBoneTransformation) {
|
|
||||||
List<Bone> bones = new ArrayList<Bone>(boneDataRoots.size() + 1);
|
|
||||||
bones.add(new Bone(""));
|
|
||||||
for (BoneTransformationData btd : boneDataRoots) {
|
|
||||||
this.assignBonesMatrices(btd, additionalRootBoneTransformation, bones);
|
|
||||||
}
|
|
||||||
return bones.toArray(new Bone[bones.size()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearState() {
|
|
||||||
bonesMap.clear();
|
|
||||||
boneDataRoots.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) {
|
public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) {
|
||||||
return true;
|
return true;
|
||||||
@ -320,11 +221,11 @@ 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, 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, blenderContext);
|
return this.getTracks249(actionStructure, skeleton, blenderContext);
|
||||||
} else {
|
} else {
|
||||||
return this.getTracks250(actionStructure, blenderContext);
|
return this.getTracks250(actionStructure, skeleton, blenderContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,19 +241,15 @@ 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, 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();
|
int fps = blenderContext.getBlenderKey().getFps();
|
||||||
Structure groups = (Structure) actionStructure.getFieldValue("groups");
|
Structure groups = (Structure) actionStructure.getFieldValue("groups");
|
||||||
List<Structure> actionGroups = groups.evaluateListBase(blenderContext);//bActionGroup
|
List<Structure> actionGroups = groups.evaluateListBase(blenderContext);//bActionGroup
|
||||||
if (actionGroups != null && actionGroups.size() > 0 && (bonesMap == null || bonesMap.size() == 0)) {
|
|
||||||
throw new IllegalStateException("No bones found! Cannot proceed to calculating tracks!");
|
|
||||||
}
|
|
||||||
|
|
||||||
List<BoneTrack> tracks = new ArrayList<BoneTrack>();
|
List<BoneTrack> tracks = new ArrayList<BoneTrack>();
|
||||||
for (Structure actionGroup : actionGroups) {
|
for (Structure actionGroup : actionGroups) {
|
||||||
String name = actionGroup.getFieldValue("name").toString();
|
String name = actionGroup.getFieldValue("name").toString();
|
||||||
Integer boneIndex = bonesMap.get(name);
|
Integer boneIndex = this.getBoneIndex(skeleton, name);
|
||||||
if (boneIndex != null) {
|
if (boneIndex != null) {
|
||||||
List<Structure> channels = ((Structure) actionGroup.getFieldValue("channels")).evaluateListBase(blenderContext);
|
List<Structure> channels = ((Structure) actionGroup.getFieldValue("channels")).evaluateListBase(blenderContext);
|
||||||
BezierCurve[] bezierCurves = new BezierCurve[channels.size()];
|
BezierCurve[] bezierCurves = new BezierCurve[channels.size()];
|
||||||
@ -374,8 +271,8 @@ public class ArmatureHelper extends AbstractBlenderHelper {
|
|||||||
bezierCurves[channelCounter++] = new BezierCurve(type, bezTriples, 2);
|
bezierCurves[channelCounter++] = new BezierCurve(type, bezTriples, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ipo ipo = new Ipo(bezierCurves);
|
Ipo ipo = new Ipo(bezierCurves, fixUpAxis);
|
||||||
tracks.add( (BoneTrack) ipo.calculateTrack(boneIndex.intValue(), 0, ipo.getLastFrame(), fps) );
|
tracks.add((BoneTrack) ipo.calculateTrack(boneIndex.intValue(), 0, ipo.getLastFrame(), fps));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tracks.toArray(new BoneTrack[tracks.size()]);
|
return tracks.toArray(new BoneTrack[tracks.size()]);
|
||||||
@ -393,31 +290,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, 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
|
||||||
if (actionChannels != null && actionChannels.size() > 0 && (bonesMap == null || bonesMap.size() == 0)) {
|
|
||||||
throw new IllegalStateException("No bones found! Cannot proceed to calculating tracks!");
|
|
||||||
}
|
|
||||||
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 = bonesMap.get(name);
|
Integer boneIndex = this.getBoneIndex(skeleton, name);
|
||||||
if (boneIndex != null) {
|
if (boneIndex != null && boneIndex.intValue() >= 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.createIpo(ipoStructure, blenderContext);
|
||||||
tracks.add( (BoneTrack) ipo.calculateTrack(boneIndex.intValue(), 0, ipo.getLastFrame(), fps));
|
tracks.add((BoneTrack) ipo.calculateTrack(boneIndex.intValue(), 0, ipo.getLastFrame(), fps));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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.
|
||||||
|
* @param skeleton the skeleton
|
||||||
|
* @param boneName the name of the bone
|
||||||
|
* @return the index of the bone
|
||||||
|
*/
|
||||||
|
private int getBoneIndex(Skeleton skeleton, String boneName) {
|
||||||
|
int result = -1;
|
||||||
|
for(int i=0;i<skeleton.getBoneCount() && result==-1;++i) {
|
||||||
|
if(boneName.equals(skeleton.getBone(i).getName())) {
|
||||||
|
result = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method parses the information stored inside the curve rna path and returns the proper type
|
* This method parses the information stored inside the curve rna path and returns the proper type
|
||||||
* of the curve.
|
* of the curve.
|
||||||
|
@ -3,6 +3,7 @@ package com.jme3.scene.plugins.blender.animations;
|
|||||||
import com.jme3.animation.BoneTrack;
|
import com.jme3.animation.BoneTrack;
|
||||||
import com.jme3.animation.SpatialTrack;
|
import com.jme3.animation.SpatialTrack;
|
||||||
import com.jme3.animation.Track;
|
import com.jme3.animation.Track;
|
||||||
|
import com.jme3.math.FastMath;
|
||||||
import com.jme3.math.Quaternion;
|
import com.jme3.math.Quaternion;
|
||||||
import com.jme3.math.Vector3f;
|
import com.jme3.math.Vector3f;
|
||||||
import com.jme3.scene.plugins.blender.curves.BezierCurve;
|
import com.jme3.scene.plugins.blender.curves.BezierCurve;
|
||||||
@ -28,23 +29,21 @@ public class Ipo {
|
|||||||
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. */
|
||||||
|
protected boolean fixUpAxis;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor. Stores the bezier curves.
|
* Constructor. Stores the bezier curves.
|
||||||
* @param bezierCurves
|
* @param bezierCurves
|
||||||
* a table of bezier curves
|
* a table of bezier curves
|
||||||
*/
|
*/
|
||||||
public Ipo(BezierCurve[] bezierCurves) {
|
public Ipo(BezierCurve[] bezierCurves, boolean fixUpAxis) {
|
||||||
this.bezierCurves = bezierCurves;
|
this.bezierCurves = bezierCurves;
|
||||||
|
this.fixUpAxis = fixUpAxis;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -93,26 +92,6 @@ public class Ipo {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
public void modifyTranslation(int frame, Vector3f translation) {
|
|
||||||
if (calculatedTrack != null) {
|
|
||||||
calculatedTrack.getTranslations()[frame].set(translation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void modifyRotation(int frame, Quaternion rotation) {
|
|
||||||
if (calculatedTrack != null) {
|
|
||||||
calculatedTrack.getRotations()[frame].set(rotation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void modifyScale(int frame, Vector3f scale) {
|
|
||||||
if (calculatedTrack != null) {
|
|
||||||
calculatedTrack.getScales()[frame].set(scale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 the specified frames.
|
||||||
* @param targetIndex
|
* @param targetIndex
|
||||||
@ -141,7 +120,8 @@ public class Ipo {
|
|||||||
float[] objectRotation = new float[3];
|
float[] objectRotation = new float[3];
|
||||||
boolean bSpatialTrack = targetIndex < 0;
|
boolean bSpatialTrack = targetIndex < 0;
|
||||||
Vector3f[] scales = new Vector3f[framesAmount + 1];
|
Vector3f[] scales = new Vector3f[framesAmount + 1];
|
||||||
float[] scale = new float[3];
|
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
|
||||||
|
|
||||||
//calculating track data
|
//calculating track data
|
||||||
for (int frame = startFrame; frame <= stopFrame; ++frame) {
|
for (int frame = startFrame; frame <= stopFrame; ++frame) {
|
||||||
@ -150,31 +130,75 @@ public class Ipo {
|
|||||||
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
|
||||||
case AC_LOC_X:
|
case AC_LOC_X:
|
||||||
|
translation[0] = (float) value;
|
||||||
|
break;
|
||||||
case AC_LOC_Y:
|
case AC_LOC_Y:
|
||||||
|
if(fixUpAxis) {
|
||||||
|
translation[2] = (float) -value;
|
||||||
|
} else {
|
||||||
|
translation[1] = (float) value;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case AC_LOC_Z:
|
case AC_LOC_Z:
|
||||||
translation[bezierCurves[j].getType() - 1] = (float) value;
|
translation[fixUpAxis ? 1 : 2] = (float) value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
//ROTATION (used with object animation)
|
||||||
|
//the value here is in degrees divided by 10 (so in example: 9 = PI/2)
|
||||||
case OB_ROT_X:
|
case OB_ROT_X:
|
||||||
|
objectRotation[0] = (float) value * degreeToRadiansFactor;
|
||||||
|
break;
|
||||||
case OB_ROT_Y:
|
case OB_ROT_Y:
|
||||||
|
if(fixUpAxis) {
|
||||||
|
objectRotation[2] = (float) -value * degreeToRadiansFactor;
|
||||||
|
} else {
|
||||||
|
objectRotation[1] = (float) value * degreeToRadiansFactor;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case OB_ROT_Z:
|
case OB_ROT_Z:
|
||||||
objectRotation[bezierCurves[j].getType() - 7] = (float) value;
|
objectRotation[fixUpAxis ? 1 : 2] = (float) value * degreeToRadiansFactor;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
//SIZE
|
||||||
case AC_SIZE_X:
|
case AC_SIZE_X:
|
||||||
case AC_SIZE_Y:
|
scale[0] = (float) value;
|
||||||
case AC_SIZE_Z:
|
|
||||||
scale[bezierCurves[j].getType() - 13] = (float) value;
|
|
||||||
break;
|
break;
|
||||||
|
case AC_SIZE_Y:
|
||||||
|
if(fixUpAxis) {
|
||||||
|
scale[2] = (float) value;
|
||||||
|
} else {
|
||||||
|
scale[1] = (float) value;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AC_SIZE_Z:
|
||||||
|
scale[fixUpAxis ? 1 : 2] = (float) value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
//QUATERNION ROTATION (used with bone animation)
|
||||||
case AC_QUAT_W:
|
case AC_QUAT_W:
|
||||||
quaternionRotation[3] = (float) value;
|
quaternionRotation[3] = (float) value;
|
||||||
break;
|
break;
|
||||||
case AC_QUAT_X:
|
case AC_QUAT_X:
|
||||||
|
quaternionRotation[0] = (float) value;
|
||||||
|
break;
|
||||||
case AC_QUAT_Y:
|
case AC_QUAT_Y:
|
||||||
|
if(fixUpAxis) {
|
||||||
|
quaternionRotation[2] = -(float) value;
|
||||||
|
} else {
|
||||||
|
quaternionRotation[1] = (float) value;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case AC_QUAT_Z:
|
case AC_QUAT_Z:
|
||||||
quaternionRotation[bezierCurves[j].getType() - 26] = (float) value;
|
if(fixUpAxis) {
|
||||||
|
quaternionRotation[1] = (float) value;
|
||||||
|
} else {
|
||||||
|
quaternionRotation[2] = (float) value;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
//TODO: error? info? warning?
|
throw new IllegalStateException("Unknown ipo curve type: " + bezierCurves[j].getType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
translations[index] = new Vector3f(translation[0], translation[1], translation[2]);
|
translations[index] = new Vector3f(translation[0], translation[1], translation[2]);
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.jme3.scene.plugins.blender.animations;
|
package com.jme3.scene.plugins.blender.animations;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import com.jme3.animation.BoneTrack;
|
import com.jme3.animation.BoneTrack;
|
||||||
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;
|
||||||
@ -7,7 +9,6 @@ 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.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 java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 like animation or constraint influence. The
|
||||||
@ -21,9 +22,11 @@ public class IpoHelper extends AbstractBlenderHelper {
|
|||||||
* different blender versions.
|
* different blender versions.
|
||||||
* @param blenderVersion
|
* @param blenderVersion
|
||||||
* the version read from the blend file
|
* the version read from the blend file
|
||||||
|
* @param fixUpAxis
|
||||||
|
* a variable that indicates if the Y asxis is the UP axis or not
|
||||||
*/
|
*/
|
||||||
public IpoHelper(String blenderVersion) {
|
public IpoHelper(String blenderVersion, boolean fixUpAxis) {
|
||||||
super(blenderVersion);
|
super(blenderVersion, fixUpAxis);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -52,7 +55,7 @@ public class IpoHelper extends AbstractBlenderHelper {
|
|||||||
bezierCurves[frame++] = new BezierCurve(type, bezTriples, 2);
|
bezierCurves[frame++] = new BezierCurve(type, bezTriples, 2);
|
||||||
}
|
}
|
||||||
curves.clear();
|
curves.clear();
|
||||||
result = new Ipo(bezierCurves);
|
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;
|
||||||
@ -90,7 +93,7 @@ public class IpoHelper extends AbstractBlenderHelper {
|
|||||||
* the constant value of this ipo
|
* the constant value of this ipo
|
||||||
*/
|
*/
|
||||||
public ConstIpo(float constValue) {
|
public ConstIpo(float constValue) {
|
||||||
super(null);
|
super(null, false);
|
||||||
this.constValue = constValue;
|
this.constValue = constValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,9 +24,11 @@ public class CameraHelper extends AbstractBlenderHelper {
|
|||||||
* different blender versions.
|
* different blender versions.
|
||||||
* @param blenderVersion
|
* @param blenderVersion
|
||||||
* the version read from the blend file
|
* the version read from the blend file
|
||||||
|
* @param fixUpAxis
|
||||||
|
* a variable that indicates if the Y asxis is the UP axis or not
|
||||||
*/
|
*/
|
||||||
public CameraHelper(String blenderVersion) {
|
public CameraHelper(String blenderVersion, boolean fixUpAxis) {
|
||||||
super(blenderVersion);
|
super(blenderVersion, fixUpAxis);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,147 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import com.jme3.animation.AnimChannel;
|
||||||
|
import com.jme3.animation.AnimControl;
|
||||||
|
import com.jme3.animation.BoneTrack;
|
||||||
|
import com.jme3.animation.SpatialTrack;
|
||||||
|
import com.jme3.animation.Track;
|
||||||
|
import com.jme3.export.JmeExporter;
|
||||||
|
import com.jme3.export.JmeImporter;
|
||||||
|
import com.jme3.math.Quaternion;
|
||||||
|
import com.jme3.math.Vector3f;
|
||||||
|
import com.jme3.util.TempVars;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class holds either the bone track or spatial track. Is made to improve
|
||||||
|
* code readability.
|
||||||
|
*
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
/* package */final class BlenderTrack implements Track {
|
||||||
|
/** The spatial track. */
|
||||||
|
private SpatialTrack spatialTrack;
|
||||||
|
/** The bone track. */
|
||||||
|
private BoneTrack boneTrack;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs the object using spatial track (bone track is null).
|
||||||
|
*
|
||||||
|
* @param spatialTrack
|
||||||
|
* the spatial track
|
||||||
|
*/
|
||||||
|
public BlenderTrack(SpatialTrack spatialTrack) {
|
||||||
|
this.spatialTrack = spatialTrack;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs the object using bone track (spatial track is null).
|
||||||
|
*
|
||||||
|
* @param spatialTrack
|
||||||
|
* the spatial track
|
||||||
|
*/
|
||||||
|
public BlenderTrack(BoneTrack boneTrack) {
|
||||||
|
this.boneTrack = boneTrack;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the stored track (either bone or spatial)
|
||||||
|
*/
|
||||||
|
public Track getTrack() {
|
||||||
|
return boneTrack != null ? boneTrack : spatialTrack;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the array of rotations of this track
|
||||||
|
*/
|
||||||
|
public Quaternion[] getRotations() {
|
||||||
|
if (boneTrack != null) {
|
||||||
|
return boneTrack.getRotations();
|
||||||
|
}
|
||||||
|
return spatialTrack.getRotations();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the array of scales for this track
|
||||||
|
*/
|
||||||
|
public Vector3f[] getScales() {
|
||||||
|
if (boneTrack != null) {
|
||||||
|
return boneTrack.getScales();
|
||||||
|
}
|
||||||
|
return spatialTrack.getScales();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the arrays of time for this track
|
||||||
|
*/
|
||||||
|
public float[] getTimes() {
|
||||||
|
if (boneTrack != null) {
|
||||||
|
return boneTrack.getTimes();
|
||||||
|
}
|
||||||
|
return spatialTrack.getTimes();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the array of translations of this track
|
||||||
|
*/
|
||||||
|
public Vector3f[] getTranslations() {
|
||||||
|
if (boneTrack != null) {
|
||||||
|
return boneTrack.getTranslations();
|
||||||
|
}
|
||||||
|
return spatialTrack.getTranslations();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the translations, rotations and scales for this bone track
|
||||||
|
*
|
||||||
|
* @param times
|
||||||
|
* a float array with the time of each frame
|
||||||
|
* @param translations
|
||||||
|
* the translation of the bone for each frame
|
||||||
|
* @param rotations
|
||||||
|
* the rotation of the bone for each frame
|
||||||
|
* @param scales
|
||||||
|
* the scale of the bone for each frame
|
||||||
|
*/
|
||||||
|
public void setKeyframes(float[] times, Vector3f[] translations,
|
||||||
|
Quaternion[] rotations, Vector3f[] scales) {
|
||||||
|
if (boneTrack != null) {
|
||||||
|
boneTrack.setKeyframes(times, translations, rotations, scales);
|
||||||
|
} else {
|
||||||
|
spatialTrack.setKeyframes(times, translations, rotations, scales);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(JmeExporter ex) throws IOException {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(JmeImporter im) throws IOException {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTime(float time, float weight, AnimControl control,
|
||||||
|
AnimChannel channel, TempVars vars) {
|
||||||
|
if (boneTrack != null) {
|
||||||
|
boneTrack.setTime(time, weight, control, channel, vars);
|
||||||
|
} else {
|
||||||
|
spatialTrack.setTime(time, weight, control, channel, vars);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getLength() {
|
||||||
|
return spatialTrack == null ? boneTrack.getLength() : spatialTrack
|
||||||
|
.getLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlenderTrack clone() {
|
||||||
|
if (boneTrack != null) {
|
||||||
|
return new BlenderTrack(boneTrack.clone());
|
||||||
|
}
|
||||||
|
return new BlenderTrack(spatialTrack.clone());
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,12 @@
|
|||||||
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.animation.BoneTrack;
|
import com.jme3.animation.BoneTrack;
|
||||||
|
import com.jme3.animation.Skeleton;
|
||||||
|
import com.jme3.animation.SpatialTrack;
|
||||||
import com.jme3.animation.Track;
|
import com.jme3.animation.Track;
|
||||||
import com.jme3.math.Quaternion;
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.math.Vector3f;
|
|
||||||
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.BlenderContext.LoadedFeatureDataType;
|
import com.jme3.scene.plugins.blender.BlenderContext.LoadedFeatureDataType;
|
||||||
import com.jme3.scene.plugins.blender.animations.Ipo;
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
@ -17,27 +18,29 @@ import com.jme3.scene.plugins.blender.objects.ObjectHelper;
|
|||||||
/**
|
/**
|
||||||
* The implementation of a constraint.
|
* The implementation of a constraint.
|
||||||
*
|
*
|
||||||
* @author Marcin Roguski
|
* @author Marcin Roguski (Kaelthas)
|
||||||
*/
|
*/
|
||||||
public abstract class Constraint {
|
public abstract class Constraint {
|
||||||
|
|
||||||
/** The name of this constraint. */
|
/** The name of this constraint. */
|
||||||
protected final String name;
|
protected final String name;
|
||||||
/** The old memory address of the constraint's owner. */
|
/** The constraint's owner. */
|
||||||
protected Long boneOMA = -1L;
|
protected final Feature owner;
|
||||||
protected final Space ownerSpace;
|
/** The constraint's target. */
|
||||||
protected final Space targetSpace;
|
protected final Feature target;
|
||||||
/** The structure with constraint's data. */
|
/** The structure with constraint's data. */
|
||||||
protected final Structure data;
|
protected final Structure data;
|
||||||
/** The ipo object defining influence. */
|
/** The ipo object defining influence. */
|
||||||
protected final Ipo ipo;
|
protected final Ipo ipo;
|
||||||
protected BlenderContext blenderContext;
|
/** The blender context. */
|
||||||
|
protected final BlenderContext blenderContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor creates the constraint instance.
|
* This constructor creates the constraint instance.
|
||||||
*
|
*
|
||||||
* @param constraintStructure
|
* @param constraintStructure
|
||||||
* the constraint's structure (bConstraint clss in blender 2.49).
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
* @param boneOMA
|
* @param ownerOMA
|
||||||
* the old memory address of the constraint owner
|
* the old memory address of the constraint owner
|
||||||
* @param influenceIpo
|
* @param influenceIpo
|
||||||
* the ipo curve of the influence factor
|
* the ipo curve of the influence factor
|
||||||
@ -47,50 +50,46 @@ public abstract class Constraint {
|
|||||||
* this exception is thrown when the blender file is somehow
|
* this exception is thrown when the blender file is somehow
|
||||||
* corrupted
|
* corrupted
|
||||||
*/
|
*/
|
||||||
public Constraint(Structure constraintStructure, Long boneOMA,
|
public Constraint(Structure constraintStructure, Long ownerOMA,
|
||||||
Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
|
this.blenderContext = blenderContext;
|
||||||
this.name = constraintStructure.getFieldValue("name").toString();
|
this.name = constraintStructure.getFieldValue("name").toString();
|
||||||
ConstraintType constraintType = ConstraintType.valueOf(((Number)constraintStructure.getFieldValue("type")).intValue());
|
|
||||||
if(constraintType != this.getType()) {
|
|
||||||
throw new IllegalStateException("Constraint structure does not match its type for constraint: " + name);
|
|
||||||
}
|
|
||||||
Pointer pData = (Pointer) constraintStructure.getFieldValue("data");
|
Pointer pData = (Pointer) constraintStructure.getFieldValue("data");
|
||||||
if (pData.isNotNull()) {
|
if (pData.isNotNull()) {
|
||||||
data = pData.fetchData(blenderContext.getInputStream()).get(0);
|
data = pData.fetchData(blenderContext.getInputStream()).get(0);
|
||||||
|
Pointer pTar = (Pointer)data.getFieldValue("tar");
|
||||||
|
if(pTar!= null && pTar.isNotNull()) {
|
||||||
|
Structure targetStructure = pTar.fetchData(blenderContext.getInputStream()).get(0);
|
||||||
|
Long targetOMA = pTar.getOldMemoryAddress();
|
||||||
|
Space targetSpace = Space.valueOf(((Number) constraintStructure.getFieldValue("tarspace")).byteValue());
|
||||||
|
ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
|
||||||
|
Spatial target = (Spatial) objectHelper.toObject(targetStructure, blenderContext);
|
||||||
|
this.target = new Feature(target, targetSpace, targetOMA, blenderContext);
|
||||||
|
} else {
|
||||||
|
this.target = null;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new BlenderFileException("The constraint has no data specified!");
|
throw new BlenderFileException("The constraint has no data specified!");
|
||||||
}
|
}
|
||||||
this.boneOMA = boneOMA;
|
Space ownerSpace = Space.valueOf(((Number) constraintStructure.getFieldValue("ownspace")).byteValue());
|
||||||
this.ownerSpace = Space.valueOf(((Number) constraintStructure.getFieldValue("ownspace")).byteValue());
|
Object owner = blenderContext.getLoadedFeature(ownerOMA, LoadedFeatureDataType.LOADED_FEATURE);
|
||||||
this.targetSpace = Space.valueOf(((Number) constraintStructure.getFieldValue("tarspace")).byteValue());
|
if(owner instanceof Spatial) {
|
||||||
|
this.owner = new Feature((Spatial)owner, ownerSpace, ownerOMA, blenderContext);
|
||||||
|
} else {
|
||||||
|
this.owner = new Feature((Bone)owner, ownerSpace, ownerOMA, blenderContext);
|
||||||
|
}
|
||||||
this.ipo = influenceIpo;
|
this.ipo = influenceIpo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns the name of the constraint.
|
* Bake the animation's constraints into its owner.
|
||||||
*
|
|
||||||
* @return the name of the constraint
|
|
||||||
*/
|
*/
|
||||||
public String getName() {
|
public abstract void bakeDynamic();
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns the old memoty address of the bone this constraint
|
* Bake the static constraints into its owner.
|
||||||
* affects.
|
|
||||||
*
|
|
||||||
* @return the old memory address of the bone this constraint affects
|
|
||||||
*/
|
*/
|
||||||
public Long getBoneOMA() {
|
public abstract void bakeStatic();
|
||||||
return boneOMA;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns the type of the constraint.
|
|
||||||
*
|
|
||||||
* @return the type of the constraint
|
|
||||||
*/
|
|
||||||
public abstract ConstraintType getType();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
@ -100,118 +99,24 @@ public abstract class Constraint {
|
|||||||
* the bone animation that affects the skeleton
|
* the bone animation that affects the skeleton
|
||||||
* @return the bone track for the bone that is being affected by the constraint
|
* @return the bone track for the bone that is being affected by the constraint
|
||||||
*/
|
*/
|
||||||
protected Track getTrack(Animation animation, int targetIndex) {
|
protected BlenderTrack getTrack(Object owner, Skeleton skeleton, Animation animation) {
|
||||||
if (boneOMA >= 0) {//bone animation
|
if(owner instanceof Bone) {
|
||||||
|
int boneIndex = skeleton.getBoneIndex((Bone) owner);
|
||||||
for (Track track : animation.getTracks()) {
|
for (Track track : animation.getTracks()) {
|
||||||
if (((BoneTrack) track).getTargetBoneIndex() == targetIndex) {
|
if (((BoneTrack) track).getTargetBoneIndex() == boneIndex) {
|
||||||
return track;
|
return new BlenderTrack(((BoneTrack) track));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {//spatial animation
|
throw new IllegalStateException("Cannot find track for: " + owner);
|
||||||
return animation.getTracks()[0];
|
} else {
|
||||||
}
|
return new BlenderTrack((SpatialTrack)animation.getTracks()[0]);
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns the target or subtarget object (if specified).
|
|
||||||
* @param loadedFeatureDataType
|
|
||||||
* @return target or subtarget feature
|
|
||||||
* @throws BlenderFileException this exception is thrown if the blend file is somehow corrupted
|
|
||||||
*/
|
|
||||||
protected Object getTarget(LoadedFeatureDataType loadedFeatureDataType) throws BlenderFileException {
|
|
||||||
//load the feature through objectHelper, this way we are certain the object loads and has
|
|
||||||
//his own constraints applied to traces
|
|
||||||
ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
|
|
||||||
//always load the target first
|
|
||||||
Long targetOMA = ((Pointer) data.getFieldValue("tar")).getOldMemoryAddress();
|
|
||||||
Structure objectStructure = blenderContext.getFileBlock(targetOMA).getStructure(blenderContext);
|
|
||||||
Object result = objectHelper.toObject(objectStructure, blenderContext);
|
|
||||||
|
|
||||||
//subtarget should be loaded alogn with target
|
|
||||||
Object subtarget = data.getFieldValue("subtarget");
|
|
||||||
String subtargetName = subtarget==null ? null : subtarget.toString();
|
|
||||||
if (subtargetName!=null && subtargetName.length() > 0) {
|
|
||||||
result = blenderContext.getLoadedFeature(subtargetName, loadedFeatureDataType);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns target's object location.
|
|
||||||
* @return target's object location
|
|
||||||
*/
|
|
||||||
protected Vector3f getTargetLocation() {
|
|
||||||
Long targetOMA = ((Pointer) data.getFieldValue("tar")).getOldMemoryAddress();
|
|
||||||
Node targetObject = (Node) blenderContext.getLoadedFeature(targetOMA, LoadedFeatureDataType.LOADED_FEATURE);
|
|
||||||
switch (targetSpace) {
|
|
||||||
case CONSTRAINT_SPACE_LOCAL:
|
|
||||||
return targetObject.getLocalTranslation();
|
|
||||||
case CONSTRAINT_SPACE_WORLD:
|
|
||||||
return targetObject.getWorldTranslation();
|
|
||||||
default:
|
|
||||||
throw new IllegalStateException("Invalid space type for target object: " + targetSpace.toString());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns target's object location in the specified frame.
|
|
||||||
* @param frame
|
|
||||||
* the frame number
|
|
||||||
* @return target's object location
|
|
||||||
*/
|
|
||||||
protected Vector3f getTargetLocation(int frame) {
|
|
||||||
return this.getTargetLocation();//TODO: implement getting location in a specified frame
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns target's object rotation.
|
|
||||||
* @return target's object rotation
|
|
||||||
*/
|
|
||||||
protected Quaternion getTargetRotation() {
|
|
||||||
Long targetOMA = ((Pointer) data.getFieldValue("tar")).getOldMemoryAddress();
|
|
||||||
Node targetObject = (Node) blenderContext.getLoadedFeature(targetOMA, LoadedFeatureDataType.LOADED_FEATURE);
|
|
||||||
switch (targetSpace) {
|
|
||||||
case CONSTRAINT_SPACE_LOCAL:
|
|
||||||
return targetObject.getLocalRotation();
|
|
||||||
case CONSTRAINT_SPACE_WORLD:
|
|
||||||
return targetObject.getWorldRotation();
|
|
||||||
default:
|
|
||||||
throw new IllegalStateException("Invalid space type for target object: " + targetSpace.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns target's object scale.
|
|
||||||
* @return target's object scale
|
|
||||||
*/
|
|
||||||
protected Vector3f getTargetScale() {
|
|
||||||
Long targetOMA = ((Pointer) data.getFieldValue("tar")).getOldMemoryAddress();
|
|
||||||
Node targetObject = (Node) blenderContext.getLoadedFeature(targetOMA, LoadedFeatureDataType.LOADED_FEATURE);
|
|
||||||
switch (targetSpace) {
|
|
||||||
case CONSTRAINT_SPACE_LOCAL:
|
|
||||||
return targetObject.getLocalScale();
|
|
||||||
case CONSTRAINT_SPACE_WORLD:
|
|
||||||
return targetObject.getWorldScale();
|
|
||||||
default:
|
|
||||||
throw new IllegalStateException("Invalid space type for target object: " + targetSpace.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method affects the bone animation tracks for the given skeleton.
|
|
||||||
*
|
|
||||||
* @param animation
|
|
||||||
* the bone animation baked traces
|
|
||||||
* @param targetIndex
|
|
||||||
* the index of the constraint's target object
|
|
||||||
*/
|
|
||||||
public abstract void affectAnimation(Animation animation, int targetIndex);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The space of target or owner transformation.
|
* The space of target or owner transformation.
|
||||||
*
|
*
|
||||||
* @author Marcin Roguski
|
* @author Marcin Roguski (Kaelthas)
|
||||||
*/
|
*/
|
||||||
public static enum Space {
|
public static enum Space {
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package com.jme3.scene.plugins.blender.constraints;
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
import com.jme3.animation.Animation;
|
|
||||||
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;
|
||||||
@ -20,7 +19,7 @@ import java.util.logging.Logger;
|
|||||||
*
|
*
|
||||||
* @param constraintStructure
|
* @param constraintStructure
|
||||||
* the constraint's structure (bConstraint clss in blender 2.49).
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
* @param boneOMA
|
* @param ownerOMA
|
||||||
* the old memory address of the constraint owner
|
* the old memory address of the constraint owner
|
||||||
* @param influenceIpo
|
* @param influenceIpo
|
||||||
* the ipo curve of the influence factor
|
* the ipo curve of the influence factor
|
||||||
@ -30,19 +29,20 @@ import java.util.logging.Logger;
|
|||||||
* this exception is thrown when the blender file is somehow
|
* this exception is thrown when the blender file is somehow
|
||||||
* corrupted
|
* corrupted
|
||||||
*/
|
*/
|
||||||
public ConstraintAction(Structure constraintStructure, Long boneOMA,
|
public ConstraintAction(Structure constraintStructure, Long ownerOMA,
|
||||||
Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
super(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void affectAnimation(Animation animation, int targetIndex) {
|
public void bakeDynamic() {
|
||||||
// TODO: implement 'Action' constraint
|
// TODO: implement 'Action' constraint
|
||||||
LOGGER.log(Level.WARNING, "'Action' constraint NOT implemented!");
|
LOGGER.log(Level.WARNING, "'Action' constraint NOT implemented!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConstraintType getType() {
|
public void bakeStatic() {
|
||||||
return ConstraintType.CONSTRAINT_TYPE_ACTION;
|
// TODO: implement 'Action' constraint
|
||||||
|
LOGGER.log(Level.WARNING, "'Action' constraint NOT implemented!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package com.jme3.scene.plugins.blender.constraints;
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
import com.jme3.animation.Animation;
|
|
||||||
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;
|
||||||
@ -20,7 +19,7 @@ import java.util.logging.Logger;
|
|||||||
*
|
*
|
||||||
* @param constraintStructure
|
* @param constraintStructure
|
||||||
* the constraint's structure (bConstraint clss in blender 2.49).
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
* @param boneOMA
|
* @param ownerOMA
|
||||||
* the old memory address of the constraint owner
|
* the old memory address of the constraint owner
|
||||||
* @param influenceIpo
|
* @param influenceIpo
|
||||||
* the ipo curve of the influence factor
|
* the ipo curve of the influence factor
|
||||||
@ -30,19 +29,20 @@ import java.util.logging.Logger;
|
|||||||
* this exception is thrown when the blender file is somehow
|
* this exception is thrown when the blender file is somehow
|
||||||
* corrupted
|
* corrupted
|
||||||
*/
|
*/
|
||||||
public ConstraintChildOf(Structure constraintStructure, Long boneOMA,
|
public ConstraintChildOf(Structure constraintStructure, Long ownerOMA,
|
||||||
Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
super(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void affectAnimation(Animation animation, int targetIndex) {
|
public void bakeDynamic() {
|
||||||
// TODO: implement ChildOf constraint
|
// TODO: implement ChildOf constraint
|
||||||
LOGGER.log(Level.WARNING, "ChildOf constraint NOT implemented!");
|
LOGGER.log(Level.WARNING, "ChildOf constraint NOT implemented!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConstraintType getType() {
|
public void bakeStatic() {
|
||||||
return ConstraintType.CONSTRAINT_TYPE_CHILDOF;
|
// TODO: implement ChildOf constraint
|
||||||
|
LOGGER.log(Level.WARNING, "ChildOf constraint NOT implemented!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package com.jme3.scene.plugins.blender.constraints;
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
import com.jme3.animation.Animation;
|
|
||||||
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;
|
||||||
@ -20,7 +19,7 @@ import java.util.logging.Logger;
|
|||||||
*
|
*
|
||||||
* @param constraintStructure
|
* @param constraintStructure
|
||||||
* the constraint's structure (bConstraint clss in blender 2.49).
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
* @param boneOMA
|
* @param ownerOMA
|
||||||
* the old memory address of the constraint owner
|
* the old memory address of the constraint owner
|
||||||
* @param influenceIpo
|
* @param influenceIpo
|
||||||
* the ipo curve of the influence factor
|
* the ipo curve of the influence factor
|
||||||
@ -30,20 +29,21 @@ import java.util.logging.Logger;
|
|||||||
* this exception is thrown when the blender file is somehow
|
* this exception is thrown when the blender file is somehow
|
||||||
* corrupted
|
* corrupted
|
||||||
*/
|
*/
|
||||||
public ConstraintClampTo(Structure constraintStructure, Long boneOMA,
|
public ConstraintClampTo(Structure constraintStructure, Long ownerOMA,
|
||||||
Ipo influenceIpo, BlenderContext blenderContext)
|
Ipo influenceIpo, BlenderContext blenderContext)
|
||||||
throws BlenderFileException {
|
throws BlenderFileException {
|
||||||
super(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void affectAnimation(Animation animation, int targetIndex) {
|
public void bakeDynamic() {
|
||||||
//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!", this.getName());
|
LOGGER.log(Level.INFO, "'Clamp to' not yet implemented! Curves not yet implemented!", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConstraintType getType() {
|
public void bakeStatic() {
|
||||||
return ConstraintType.CONSTRAINT_TYPE_CLAMPTO;
|
//TODO: implement when curves are implemented
|
||||||
|
LOGGER.log(Level.INFO, "'Clamp to' not yet implemented! Curves not yet implemented!", name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,49 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import com.jme3.scene.plugins.blender.BlenderContext;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The damp track constraint. Available for blender 2.50+.
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
/*package*/ class ConstraintDampTrack extends Constraint {
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(ConstraintDampTrack.class.getName());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor creates the constraint instance.
|
||||||
|
*
|
||||||
|
* @param constraintStructure
|
||||||
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
|
* @param ownerOMA
|
||||||
|
* the old memory address of the constraint owner
|
||||||
|
* @param influenceIpo
|
||||||
|
* the ipo curve of the influence factor
|
||||||
|
* @param blenderContext
|
||||||
|
* the blender context
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
public ConstraintDampTrack(Structure constraintStructure, Long ownerOMA, Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
|
super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
|
||||||
|
// TODO Auto-generated constructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bakeDynamic() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
LOGGER.log(Level.WARNING, "'Damp Track' constraint NOT implemented!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bakeStatic() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
LOGGER.log(Level.WARNING, "'Damp Track' constraint NOT implemented!");
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,15 @@
|
|||||||
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.BoneTrack;
|
import com.jme3.animation.Bone;
|
||||||
|
import com.jme3.math.Matrix4f;
|
||||||
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;
|
||||||
import com.jme3.scene.plugins.blender.file.Structure;
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
import com.jme3.scene.plugins.ogre.AnimData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class represents 'Dist limit' constraint type in blender.
|
* This class represents 'Dist limit' constraint type in blender.
|
||||||
@ -17,12 +20,15 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
private static final int LIMITDIST_OUTSIDE = 1;
|
private static final int LIMITDIST_OUTSIDE = 1;
|
||||||
private static final int LIMITDIST_ONSURFACE = 2;
|
private static final int LIMITDIST_ONSURFACE = 2;
|
||||||
|
|
||||||
|
protected int mode;
|
||||||
|
protected float dist;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor creates the constraint instance.
|
* This constructor creates the constraint instance.
|
||||||
*
|
*
|
||||||
* @param constraintStructure
|
* @param constraintStructure
|
||||||
* the constraint's structure (bConstraint clss in blender 2.49).
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
* @param boneOMA
|
* @param ownerOMA
|
||||||
* the old memory address of the constraint owner
|
* the old memory address of the constraint owner
|
||||||
* @param influenceIpo
|
* @param influenceIpo
|
||||||
* the ipo curve of the influence factor
|
* the ipo curve of the influence factor
|
||||||
@ -32,52 +38,89 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
* this exception is thrown when the blender file is somehow
|
* this exception is thrown when the blender file is somehow
|
||||||
* corrupted
|
* corrupted
|
||||||
*/
|
*/
|
||||||
public ConstraintDistLimit(Structure constraintStructure, Long boneOMA,
|
public ConstraintDistLimit(Structure constraintStructure, Long ownerOMA,
|
||||||
Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
super(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
|
||||||
|
|
||||||
|
mode = ((Number) data.getFieldValue("mode")).intValue();
|
||||||
|
dist = ((Number) data.getFieldValue("dist")).floatValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void affectAnimation(Animation animation, int targetIndex) {
|
public void bakeDynamic() {
|
||||||
Vector3f targetLocation = this.getTargetLocation();
|
AnimData animData = blenderContext.getAnimData(this.owner.getOma());
|
||||||
BoneTrack boneTrack = (BoneTrack) this.getTrack(animation, targetIndex);
|
if(animData != null) {
|
||||||
if (boneTrack != null) {
|
Object owner = this.owner.getObject();
|
||||||
//TODO: target vertex group !!!
|
if(owner instanceof Spatial) {
|
||||||
float dist = ((Number) data.getFieldValue("dist")).floatValue();
|
Vector3f targetLocation = ((Spatial) owner).getWorldTranslation();
|
||||||
int mode = ((Number) data.getFieldValue("mode")).intValue();
|
for(Animation animation : animData.anims) {
|
||||||
|
BlenderTrack blenderTrack = this.getTrack(owner, animData.skeleton, animation);
|
||||||
int maxFrames = boneTrack.getTimes().length;
|
int maxFrames = blenderTrack.getTimes().length;
|
||||||
Vector3f[] translations = boneTrack.getTranslations();
|
Vector3f[] translations = blenderTrack.getTranslations();
|
||||||
for (int frame = 0; frame < maxFrames; ++frame) {
|
for (int frame = 0; frame < maxFrames; ++frame) {
|
||||||
Vector3f v = translations[frame].subtract(targetLocation);
|
Vector3f v = translations[frame].subtract(targetLocation);
|
||||||
|
this.distLimit(v, targetLocation, ipo.calculateValue(frame));
|
||||||
|
translations[frame].addLocal(v);
|
||||||
|
}
|
||||||
|
blenderTrack.setKeyframes(blenderTrack.getTimes(), translations, blenderTrack.getRotations(), blenderTrack.getScales());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public 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) {
|
||||||
|
((Spatial) owner).setLocalTranslation(m.mult(ownerLocation));
|
||||||
|
} else {
|
||||||
|
((Bone) owner).setBindTransforms(m.mult(ownerLocation), ((Bone) owner).getLocalRotation(), ((Bone) owner).getLocalScale());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param currentLocation
|
||||||
|
* @param targetLocation
|
||||||
|
* @param influence
|
||||||
|
*/
|
||||||
|
private void distLimit(Vector3f currentLocation, Vector3f targetLocation, float influence) {
|
||||||
|
Vector3f v = currentLocation.subtract(targetLocation);
|
||||||
float currentDistance = v.length();
|
float currentDistance = v.length();
|
||||||
float influence = ipo.calculateValue(frame);
|
|
||||||
float modifier = 0.0f;
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case LIMITDIST_INSIDE:
|
case LIMITDIST_INSIDE:
|
||||||
if (currentDistance >= dist) {
|
if (currentDistance >= dist) {
|
||||||
modifier = (dist - currentDistance) / currentDistance;
|
v.normalizeLocal();
|
||||||
|
v.multLocal(dist + (currentDistance - dist) * (1.0f - influence));
|
||||||
|
currentLocation.set(v.addLocal(targetLocation));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case LIMITDIST_ONSURFACE:
|
case LIMITDIST_ONSURFACE:
|
||||||
modifier = (dist - currentDistance) / currentDistance;
|
if (currentDistance > dist) {
|
||||||
|
v.normalizeLocal();
|
||||||
|
v.multLocal(dist + (currentDistance - dist) * (1.0f - influence));
|
||||||
|
currentLocation.set(v.addLocal(targetLocation));
|
||||||
|
} else if(currentDistance < dist) {
|
||||||
|
v.normalizeLocal().multLocal(dist * influence);
|
||||||
|
currentLocation.set(targetLocation.add(v));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case LIMITDIST_OUTSIDE:
|
case LIMITDIST_OUTSIDE:
|
||||||
if (currentDistance <= dist) {
|
if (currentDistance <= dist) {
|
||||||
modifier = (dist - currentDistance) / currentDistance;
|
v = targetLocation.subtract(currentLocation).normalizeLocal().multLocal(dist * influence);
|
||||||
|
currentLocation.set(targetLocation.add(v));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException("Unknown distance limit constraint mode: " + mode);
|
throw new IllegalStateException("Unknown distance limit constraint mode: " + mode);
|
||||||
}
|
}
|
||||||
translations[frame].addLocal(v.multLocal(modifier * influence));
|
|
||||||
}
|
|
||||||
boneTrack.setKeyframes(boneTrack.getTimes(), translations, boneTrack.getRotations(), boneTrack.getScales());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ConstraintType getType() {
|
|
||||||
return ConstraintType.CONSTRAINT_TYPE_DISTLIMIT;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,78 +0,0 @@
|
|||||||
package com.jme3.scene.plugins.blender.constraints;
|
|
||||||
|
|
||||||
import com.jme3.scene.plugins.blender.BlenderContext;
|
|
||||||
import com.jme3.scene.plugins.blender.animations.Ipo;
|
|
||||||
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
|
||||||
import com.jme3.scene.plugins.blender.file.Structure;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A factory class to create new instances of constraints depending on the type from the constraint's structure.
|
|
||||||
* This class has a package scope.
|
|
||||||
* @author Marcin Roguski (Kaelthas)
|
|
||||||
*/
|
|
||||||
/*package*/ final class ConstraintFactory {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method creates the constraint instance.
|
|
||||||
*
|
|
||||||
* @param constraintStructure
|
|
||||||
* the constraint's structure (bConstraint clss in blender 2.49).
|
|
||||||
* @param boneOMA
|
|
||||||
* the old memory address of the constraint owner
|
|
||||||
* @param influenceIpo
|
|
||||||
* the ipo curve of the influence factor
|
|
||||||
* @param blenderContext
|
|
||||||
* the blender context
|
|
||||||
* @throws BlenderFileException
|
|
||||||
* this exception is thrown when the blender file is somehow
|
|
||||||
* corrupted
|
|
||||||
*/
|
|
||||||
public static Constraint createConstraint(Structure constraintStructure, Long boneOMA, Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
|
||||||
int type = ((Number)constraintStructure.getFieldValue("type")).intValue();
|
|
||||||
ConstraintType constraintType = ConstraintType.valueOf(type);
|
|
||||||
switch(constraintType) {
|
|
||||||
case CONSTRAINT_TYPE_ACTION:
|
|
||||||
return new ConstraintAction(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
|
||||||
case CONSTRAINT_TYPE_CHILDOF:
|
|
||||||
return new ConstraintChildOf(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
|
||||||
case CONSTRAINT_TYPE_CLAMPTO:
|
|
||||||
return new ConstraintClampTo(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
|
||||||
case CONSTRAINT_TYPE_DISTLIMIT:
|
|
||||||
return new ConstraintDistLimit(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
|
||||||
case CONSTRAINT_TYPE_FOLLOWPATH:
|
|
||||||
return new ConstraintFollowPath(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
|
||||||
case CONSTRAINT_TYPE_KINEMATIC:
|
|
||||||
return new ConstraintInverseKinematics(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
|
||||||
case CONSTRAINT_TYPE_LOCKTRACK:
|
|
||||||
return new ConstraintLockTrack(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
|
||||||
case CONSTRAINT_TYPE_LOCLIKE:
|
|
||||||
return new ConstraintLocLike(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
|
||||||
case CONSTRAINT_TYPE_LOCLIMIT:
|
|
||||||
return new ConstraintLocLimit(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
|
||||||
case CONSTRAINT_TYPE_MINMAX:
|
|
||||||
return new ConstraintMinMax(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
|
||||||
case CONSTRAINT_TYPE_NULL:
|
|
||||||
return new ConstraintNull(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
|
||||||
case CONSTRAINT_TYPE_PYTHON:
|
|
||||||
return new ConstraintPython(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
|
||||||
case CONSTRAINT_TYPE_RIGIDBODYJOINT:
|
|
||||||
return new ConstraintRigidBodyJoint(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
|
||||||
case CONSTRAINT_TYPE_ROTLIKE:
|
|
||||||
return new ConstraintRotLike(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
|
||||||
case CONSTRAINT_TYPE_ROTLIMIT:
|
|
||||||
return new ConstraintRotLimit(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
|
||||||
case CONSTRAINT_TYPE_SHRINKWRAP:
|
|
||||||
return new ConstraintShrinkWrap(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
|
||||||
case CONSTRAINT_TYPE_SIZELIKE:
|
|
||||||
return new ConstraintSizeLike(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
|
||||||
case CONSTRAINT_TYPE_SIZELIMIT:
|
|
||||||
return new ConstraintSizeLimit(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
|
||||||
case CONSTRAINT_TYPE_STRETCHTO:
|
|
||||||
return new ConstraintStretchTo(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
|
||||||
case CONSTRAINT_TYPE_TRANSFORM:
|
|
||||||
return new ConstraintTransform(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
|
||||||
default:
|
|
||||||
throw new IllegalStateException("Unknown constraint type: " + constraintType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +1,5 @@
|
|||||||
package com.jme3.scene.plugins.blender.constraints;
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
import com.jme3.animation.Animation;
|
|
||||||
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;
|
||||||
@ -20,7 +19,7 @@ import java.util.logging.Logger;
|
|||||||
*
|
*
|
||||||
* @param constraintStructure
|
* @param constraintStructure
|
||||||
* the constraint's structure (bConstraint clss in blender 2.49).
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
* @param boneOMA
|
* @param ownerOMA
|
||||||
* the old memory address of the constraint owner
|
* the old memory address of the constraint owner
|
||||||
* @param influenceIpo
|
* @param influenceIpo
|
||||||
* the ipo curve of the influence factor
|
* the ipo curve of the influence factor
|
||||||
@ -30,19 +29,20 @@ import java.util.logging.Logger;
|
|||||||
* this exception is thrown when the blender file is somehow
|
* this exception is thrown when the blender file is somehow
|
||||||
* corrupted
|
* corrupted
|
||||||
*/
|
*/
|
||||||
public ConstraintFollowPath(Structure constraintStructure, Long boneOMA,
|
public ConstraintFollowPath(Structure constraintStructure, Long ownerOMA,
|
||||||
Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
super(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void affectAnimation(Animation animation, int targetIndex) {
|
public void bakeDynamic() {
|
||||||
//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!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConstraintType getType() {
|
public void bakeStatic() {
|
||||||
return ConstraintType.CONSTRAINT_TYPE_FOLLOWPATH;
|
//TODO: implement when curves are implemented
|
||||||
|
LOGGER.log(Level.INFO, "'Follow path' not implemented! Curves not yet implemented!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,12 @@
|
|||||||
package com.jme3.scene.plugins.blender.constraints;
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
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.animations.Ipo;
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
@ -7,19 +14,42 @@ 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.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 java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class should be used for constraint calculations.
|
* This class should be used for constraint calculations.
|
||||||
* @author Marcin Roguski
|
* @author Marcin Roguski (Kaelthas)
|
||||||
*/
|
*/
|
||||||
public class ConstraintHelper extends AbstractBlenderHelper {
|
public class ConstraintHelper extends AbstractBlenderHelper {
|
||||||
private static final Logger LOGGER = Logger.getLogger(ConstraintHelper.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(ConstraintHelper.class.getName());
|
||||||
|
|
||||||
|
private static final Map<String, Class<? extends Constraint>> constraintClasses = new HashMap<String, Class<? extends Constraint>>(22);
|
||||||
|
static {
|
||||||
|
constraintClasses.put("bActionConstraint", ConstraintAction.class);
|
||||||
|
constraintClasses.put("bChildOfConstraint", ConstraintChildOf.class);
|
||||||
|
constraintClasses.put("bClampToConstraint", ConstraintClampTo.class);
|
||||||
|
constraintClasses.put("bDistLimitConstraint", ConstraintDistLimit.class);
|
||||||
|
constraintClasses.put("bFollowPathConstraint", ConstraintFollowPath.class);
|
||||||
|
constraintClasses.put("bKinematicConstraint", ConstraintInverseKinematics.class);
|
||||||
|
constraintClasses.put("bLockTrackConstraint", ConstraintLockTrack.class);
|
||||||
|
constraintClasses.put("bLocateLikeConstraint", ConstraintLocLike.class);
|
||||||
|
constraintClasses.put("bLocLimitConstraint", ConstraintLocLimit.class);
|
||||||
|
constraintClasses.put("bMinMaxConstraint", ConstraintMinMax.class);
|
||||||
|
constraintClasses.put("bNullConstraint", ConstraintNull.class);
|
||||||
|
constraintClasses.put("bPythonConstraint", ConstraintPython.class);
|
||||||
|
constraintClasses.put("bRigidBodyJointConstraint", ConstraintRigidBodyJoint.class);
|
||||||
|
constraintClasses.put("bRotateLikeConstraint", ConstraintRotLike.class);
|
||||||
|
constraintClasses.put("bShrinkWrapConstraint", ConstraintShrinkWrap.class);
|
||||||
|
constraintClasses.put("bSizeLikeConstraint", ConstraintSizeLike.class);
|
||||||
|
constraintClasses.put("bSizeLimitConstraint", ConstraintSizeLimit.class);
|
||||||
|
constraintClasses.put("bStretchToConstraint", ConstraintStretchTo.class);
|
||||||
|
constraintClasses.put("bTransformConstraint", ConstraintTransform.class);
|
||||||
|
constraintClasses.put("bRotLimitConstraint", ConstraintRotLimit.class);
|
||||||
|
//Blender 2.50+
|
||||||
|
constraintClasses.put("bSplineIKConstraint", ConstraintSplineInverseKinematic.class);
|
||||||
|
constraintClasses.put("bDampTrackConstraint", ConstraintDampTrack.class);
|
||||||
|
constraintClasses.put("bPivotConstraint", ConstraintDampTrack.class);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper constructor. It's main task is to generate the affection functions. These functions are common to all
|
* Helper constructor. It's main task is to generate the affection functions. These functions are common to all
|
||||||
* ConstraintHelper instances. Unfortunately this constructor might grow large. If it becomes too large - I shall
|
* ConstraintHelper instances. Unfortunately this constructor might grow large. If it becomes too large - I shall
|
||||||
@ -27,27 +57,25 @@ public class ConstraintHelper extends AbstractBlenderHelper {
|
|||||||
* functionalities may differ in different blender versions.
|
* functionalities may differ in different blender versions.
|
||||||
* @param blenderVersion
|
* @param blenderVersion
|
||||||
* the version read from the blend file
|
* the version read from the blend file
|
||||||
|
* @param fixUpAxis
|
||||||
|
* a variable that indicates if the Y asxis is the UP axis or not
|
||||||
*/
|
*/
|
||||||
public ConstraintHelper(String blenderVersion, BlenderContext blenderContext) {
|
public ConstraintHelper(String blenderVersion, BlenderContext blenderContext, boolean fixUpAxis) {
|
||||||
super(blenderVersion);
|
super(blenderVersion, fixUpAxis);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method reads constraints for for the given structure. The constraints are loaded only once for object/bone.
|
* This method reads constraints for for the given structure. The
|
||||||
* @param ownerOMA
|
* constraints are loaded only once for object/bone.
|
||||||
* the owner's old memory address
|
*
|
||||||
* @param objectStructure
|
* @param objectStructure
|
||||||
* the structure we read constraint's for
|
* the structure we read constraint's for
|
||||||
* @param blenderContext
|
* @param blenderContext
|
||||||
* the blender context
|
* the blender context
|
||||||
* @throws BlenderFileException
|
* @throws BlenderFileException
|
||||||
*/
|
*/
|
||||||
public Map<Long, List<Constraint>> loadConstraints(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException {
|
public void loadConstraints(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
if (blenderVersion >= 250) {//TODO
|
LOGGER.fine("Loading constraints.");
|
||||||
LOGGER.warning("Loading of constraints not yet implemented for version 2.5x !");
|
|
||||||
return new HashMap<Long, List<Constraint>>(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// reading influence ipos for the constraints
|
// reading influence ipos for the constraints
|
||||||
IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class);
|
IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class);
|
||||||
Map<String, Map<String, Ipo>> constraintsIpos = new HashMap<String, Map<String, Ipo>>();
|
Map<String, Map<String, Ipo>> constraintsIpos = new HashMap<String, Map<String, Ipo>>();
|
||||||
@ -75,10 +103,8 @@ public class ConstraintHelper extends AbstractBlenderHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<Long, List<Constraint>> result = new HashMap<Long, List<Constraint>>();
|
|
||||||
|
|
||||||
//loading constraints connected with the object's bones
|
//loading constraints connected with the object's bones
|
||||||
Pointer pPose = (Pointer) objectStructure.getFieldValue("pose");//TODO: what if the object has two armatures ????
|
Pointer pPose = (Pointer) objectStructure.getFieldValue("pose");
|
||||||
if (pPose.isNotNull()) {
|
if (pPose.isNotNull()) {
|
||||||
List<Structure> poseChannels = ((Structure) pPose.fetchData(blenderContext.getInputStream()).get(0).getFieldValue("chanbase")).evaluateListBase(blenderContext);
|
List<Structure> poseChannels = ((Structure) pPose.fetchData(blenderContext.getInputStream()).get(0).getFieldValue("chanbase")).evaluateListBase(blenderContext);
|
||||||
for (Structure poseChannel : poseChannels) {
|
for (Structure poseChannel : poseChannels) {
|
||||||
@ -96,21 +122,13 @@ public class ConstraintHelper extends AbstractBlenderHelper {
|
|||||||
float enforce = ((Number) constraint.getFieldValue("enforce")).floatValue();
|
float enforce = ((Number) constraint.getFieldValue("enforce")).floatValue();
|
||||||
ipo = ipoHelper.createIpo(enforce);
|
ipo = ipoHelper.createIpo(enforce);
|
||||||
}
|
}
|
||||||
constraintsList.add(ConstraintFactory.createConstraint(constraint, boneOMA, ipo, blenderContext));
|
constraintsList.add(this.createConstraint(constraint, boneOMA, ipo, blenderContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
result.put(boneOMA, constraintsList);
|
|
||||||
blenderContext.addConstraints(boneOMA, constraintsList);
|
blenderContext.addConstraints(boneOMA, constraintsList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: reading constraints for objects (implement when object's animation will be available)
|
|
||||||
List<Structure> constraintChannels = ((Structure)objectStructure.getFieldValue("constraintChannels")).evaluateListBase(blenderContext);
|
|
||||||
for(Structure constraintChannel : constraintChannels) {
|
|
||||||
System.out.println(constraintChannel);
|
|
||||||
}
|
|
||||||
|
|
||||||
//loading constraints connected with the object itself (TODO: test this)
|
//loading constraints connected with the object itself
|
||||||
if(!result.containsKey(objectStructure.getOldMemoryAddress())) {
|
|
||||||
List<Structure> constraints = ((Structure)objectStructure.getFieldValue("constraints")).evaluateListBase(blenderContext);
|
List<Structure> constraints = ((Structure)objectStructure.getFieldValue("constraints")).evaluateListBase(blenderContext);
|
||||||
List<Constraint> constraintsList = new ArrayList<Constraint>(constraints.size());
|
List<Constraint> constraintsList = new ArrayList<Constraint>(constraints.size());
|
||||||
|
|
||||||
@ -124,12 +142,58 @@ public class ConstraintHelper extends AbstractBlenderHelper {
|
|||||||
float enforce = ((Number) constraint.getFieldValue("enforce")).floatValue();
|
float enforce = ((Number) constraint.getFieldValue("enforce")).floatValue();
|
||||||
ipo = ipoHelper.createIpo(enforce);
|
ipo = ipoHelper.createIpo(enforce);
|
||||||
}
|
}
|
||||||
constraintsList.add(ConstraintFactory.createConstraint(constraint, null, ipo, blenderContext));
|
constraintsList.add(this.createConstraint(constraint, objectStructure.getOldMemoryAddress(), ipo, blenderContext));
|
||||||
}
|
}
|
||||||
result.put(objectStructure.getOldMemoryAddress(), constraintsList);
|
|
||||||
blenderContext.addConstraints(objectStructure.getOldMemoryAddress(), constraintsList);
|
blenderContext.addConstraints(objectStructure.getOldMemoryAddress(), constraintsList);
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
|
/**
|
||||||
|
* This method creates the constraint instance.
|
||||||
|
*
|
||||||
|
* @param constraintStructure
|
||||||
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
|
* @param ownerOMA
|
||||||
|
* the old memory address of the constraint's owner
|
||||||
|
* @param influenceIpo
|
||||||
|
* the ipo curve of the influence factor
|
||||||
|
* @param blenderContext
|
||||||
|
* the blender context
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
protected Constraint createConstraint(Structure constraintStructure, Long ownerOMA, Ipo influenceIpo,
|
||||||
|
BlenderContext blenderContext) throws BlenderFileException {
|
||||||
|
String constraintClassName = this.getConstraintClassName(constraintStructure, blenderContext);
|
||||||
|
Class<? extends Constraint> constraintClass = constraintClasses.get(constraintClassName);
|
||||||
|
if(constraintClass != null) {
|
||||||
|
try {
|
||||||
|
return (Constraint) constraintClass.getDeclaredConstructors()[0].newInstance(constraintStructure, ownerOMA, influenceIpo,
|
||||||
|
blenderContext);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw new BlenderFileException(e.getLocalizedMessage(), e);
|
||||||
|
} catch (SecurityException e) {
|
||||||
|
throw new BlenderFileException(e.getLocalizedMessage(), e);
|
||||||
|
} catch (InstantiationException e) {
|
||||||
|
throw new BlenderFileException(e.getLocalizedMessage(), e);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new BlenderFileException(e.getLocalizedMessage(), e);
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
throw new BlenderFileException(e.getLocalizedMessage(), e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new BlenderFileException("Unknown constraint type: " + constraintClassName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getConstraintClassName(Structure constraintStructure, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
|
Pointer pData = (Pointer)constraintStructure.getFieldValue("data");
|
||||||
|
if(pData.isNotNull()) {
|
||||||
|
Structure data = pData.fetchData(blenderContext.getInputStream()).get(0);
|
||||||
|
return data.getType();
|
||||||
|
|
||||||
|
}
|
||||||
|
return constraintStructure.getType();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
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.Skeleton;
|
||||||
import com.jme3.scene.plugins.blender.BlenderContext;
|
import com.jme3.scene.plugins.blender.BlenderContext;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.CalculationBone;
|
||||||
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;
|
||||||
import com.jme3.scene.plugins.blender.file.Structure;
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
@ -20,7 +22,7 @@ import java.util.logging.Logger;
|
|||||||
*
|
*
|
||||||
* @param constraintStructure
|
* @param constraintStructure
|
||||||
* the constraint's structure (bConstraint clss in blender 2.49).
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
* @param boneOMA
|
* @param ownerOMA
|
||||||
* the old memory address of the constraint owner
|
* the old memory address of the constraint owner
|
||||||
* @param influenceIpo
|
* @param influenceIpo
|
||||||
* the ipo curve of the influence factor
|
* the ipo curve of the influence factor
|
||||||
@ -31,23 +33,30 @@ import java.util.logging.Logger;
|
|||||||
* corrupted
|
* corrupted
|
||||||
*/
|
*/
|
||||||
public ConstraintInverseKinematics(Structure constraintStructure,
|
public ConstraintInverseKinematics(Structure constraintStructure,
|
||||||
Long boneOMA, Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
Long ownerOMA, Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
super(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void affectAnimation(Animation animation, int targetIndex) {
|
public void bakeDynamic() {
|
||||||
// try {
|
// try {
|
||||||
// IK solver is only attached to bones
|
// IK solver is only attached to bones
|
||||||
// Bone ownerBone = (Bone) blenderContext.getLoadedFeature(boneOMA, LoadedFeatureDataType.LOADED_FEATURE);
|
// Bone ownerBone = (Bone) blenderContext.getLoadedFeature(ownerOMA, LoadedFeatureDataType.LOADED_FEATURE);
|
||||||
//
|
// AnimData animData = blenderContext.getAnimData(ownerOMA);
|
||||||
// // get the target point
|
// if(animData == null) {
|
||||||
|
//TODO: to nie mo¿e byæ null, utworzyæ dane bez ruchu, w zale¿noœci czy target siê rusza
|
||||||
|
// }
|
||||||
|
|
||||||
|
//prepare a list of all parents of this bone
|
||||||
|
// CalculationBone[] bones = this.getBonesToCalculate(skeleton, boneAnimation);
|
||||||
|
|
||||||
|
// get the target point
|
||||||
// Object targetObject = this.getTarget(LoadedFeatureDataType.LOADED_FEATURE);
|
// Object targetObject = this.getTarget(LoadedFeatureDataType.LOADED_FEATURE);
|
||||||
// Vector3f pt = null;// Point Target
|
// Vector3f pt = null;// Point Target
|
||||||
// if (targetObject instanceof Bone) {
|
// if (targetObject instanceof Bone) {
|
||||||
// pt = ((Bone) targetObject).getModelSpacePosition();
|
// pt = ((Bone) targetObject).getModelSpacePosition();
|
||||||
// } else if (targetObject instanceof Node) {
|
// } else if (targetObject instanceof Spatial) {
|
||||||
// pt = ((Node) targetObject).getWorldTranslation();
|
// pt = ((Spatial) targetObject).getWorldTranslation();
|
||||||
// } else if (targetObject instanceof Skeleton) {
|
// } else if (targetObject instanceof Skeleton) {
|
||||||
// Structure armatureNodeStructure = (Structure) this.getTarget(LoadedFeatureDataType.LOADED_STRUCTURE);
|
// Structure armatureNodeStructure = (Structure) this.getTarget(LoadedFeatureDataType.LOADED_STRUCTURE);
|
||||||
// ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
|
// ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
|
||||||
@ -106,7 +115,7 @@ import java.util.logging.Logger;
|
|||||||
// for (CalculationBone bone : bones) {
|
// for (CalculationBone bone : bones) {
|
||||||
// bone.applyCalculatedTracks();
|
// bone.applyCalculatedTracks();
|
||||||
// }
|
// }
|
||||||
|
//
|
||||||
// System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
|
// System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
|
||||||
// for (int i = 0; i < bones.length; ++i) {
|
// for (int i = 0; i < bones.length; ++i) {
|
||||||
// System.out.println(Arrays.toString(bones[i].track.getTranslations()));
|
// System.out.println(Arrays.toString(bones[i].track.getTranslations()));
|
||||||
@ -118,40 +127,42 @@ import java.util.logging.Logger;
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
@Override
|
||||||
// * This method returns bones used for rotation calculations.
|
public void bakeStatic() {
|
||||||
// * @param bone
|
// TODO Auto-generated method stub
|
||||||
// * the bone to which the constraint is applied
|
|
||||||
// * @param skeleton
|
}
|
||||||
// * the skeleton owning the bone and its ancestors
|
|
||||||
// * @param boneAnimation
|
/**
|
||||||
// * the bone animation data that stores the traces for the skeleton's bones
|
* This method returns bones used for rotation calculations.
|
||||||
// * @return a list of bones to imitate the bone's movement during IK solving
|
* @param bone
|
||||||
// */
|
* the bone to which the constraint is applied
|
||||||
// private CalculationBone[] getBonesToCalculate(Bone bone, Skeleton skeleton, Animation boneAnimation) {
|
* @param skeleton
|
||||||
|
* the skeleton owning the bone and its ancestors
|
||||||
|
* @param boneAnimation
|
||||||
|
* the bone animation data that stores the traces for the skeleton's bones
|
||||||
|
* @return a list of bones to imitate the bone's movement during IK solving
|
||||||
|
*/
|
||||||
|
private CalculationBone[] getBonesToCalculate(Skeleton skeleton, Animation boneAnimation) {
|
||||||
|
// Bone ownerBone = (Bone) blenderContext.getLoadedFeature(ownerOMA, LoadedFeatureDataType.LOADED_FEATURE);
|
||||||
// List<CalculationBone> bonesList = new ArrayList<CalculationBone>();
|
// List<CalculationBone> bonesList = new ArrayList<CalculationBone>();
|
||||||
// Bone currentBone = bone;
|
|
||||||
// do {
|
// do {
|
||||||
// bonesList.add(new CalculationBone(currentBone, 1));
|
// bonesList.add(new CalculationBone(ownerBone, 1));
|
||||||
// int boneIndex = skeleton.getBoneIndex(currentBone);
|
// int boneIndex = skeleton.getBoneIndex(ownerBone);
|
||||||
// for (int i = 0; i < boneAnimation.getTracks().length; ++i) {
|
// for (int i = 0; i < boneAnimation.getTracks().length; ++i) {
|
||||||
// if (boneAnimation.getTracks()[i].getTargetBoneIndex() == boneIndex) {
|
// if (((BoneTrack[])boneAnimation.getTracks())[i].getTargetBoneIndex() == boneIndex) {
|
||||||
// bonesList.add(new CalculationBone(currentBone, boneAnimation.getTracks()[i]));
|
// bonesList.add(new CalculationBone(ownerBone, (BoneTrack)boneAnimation.getTracks()[i]));
|
||||||
// break;
|
// break;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// currentBone = currentBone.getParent();
|
// ownerBone = ownerBone.getParent();
|
||||||
// } while (currentBone != null);
|
// } while (ownerBone != null);
|
||||||
// //attaching children
|
// //attaching children
|
||||||
// CalculationBone[] result = bonesList.toArray(new CalculationBone[bonesList.size()]);
|
// CalculationBone[] result = bonesList.toArray(new CalculationBone[bonesList.size()]);
|
||||||
// for (int i = result.length - 1; i > 0; --i) {
|
// for (int i = result.length - 1; i > 0; --i) {
|
||||||
// result[i].attachChild(result[i - 1]);
|
// result[i].attachChild(result[i - 1]);
|
||||||
// }
|
// }
|
||||||
// return result;
|
// return result;
|
||||||
// }
|
return null;
|
||||||
|
|
||||||
@Override
|
|
||||||
public ConstraintType getType() {
|
|
||||||
return ConstraintType.CONSTRAINT_TYPE_KINEMATIC;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
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.BoneTrack;
|
import com.jme3.math.Transform;
|
||||||
import com.jme3.math.Vector3f;
|
import com.jme3.math.Vector3f;
|
||||||
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;
|
||||||
import com.jme3.scene.plugins.blender.file.Structure;
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
import com.jme3.scene.plugins.ogre.AnimData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class represents 'Loc like' constraint type in blender.
|
* This class represents 'Loc like' constraint type in blender.
|
||||||
@ -16,19 +17,20 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
private static final int LOCLIKE_X = 0x01;
|
private static final int LOCLIKE_X = 0x01;
|
||||||
private static final int LOCLIKE_Y = 0x02;
|
private static final int LOCLIKE_Y = 0x02;
|
||||||
private static final int LOCLIKE_Z = 0x04;
|
private static final int LOCLIKE_Z = 0x04;
|
||||||
/* LOCLIKE_TIP is a depreceated option... use headtail=1.0f instead */
|
//protected static final int LOCLIKE_TIP = 0x08;//this is deprecated in blender
|
||||||
//protected static final int LOCLIKE_TIP = 0x08;
|
|
||||||
private static final int LOCLIKE_X_INVERT = 0x10;
|
private static final int LOCLIKE_X_INVERT = 0x10;
|
||||||
private static final int LOCLIKE_Y_INVERT = 0x20;
|
private static final int LOCLIKE_Y_INVERT = 0x20;
|
||||||
private static final int LOCLIKE_Z_INVERT = 0x40;
|
private static final int LOCLIKE_Z_INVERT = 0x40;
|
||||||
private static final int LOCLIKE_OFFSET = 0x80;
|
private static final int LOCLIKE_OFFSET = 0x80;
|
||||||
|
|
||||||
|
protected int flag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor creates the constraint instance.
|
* This constructor creates the constraint instance.
|
||||||
*
|
*
|
||||||
* @param constraintStructure
|
* @param constraintStructure
|
||||||
* the constraint's structure (bConstraint clss in blender 2.49).
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
* @param boneOMA
|
* @param ownerOMA
|
||||||
* the old memory address of the constraint owner
|
* the old memory address of the constraint owner
|
||||||
* @param influenceIpo
|
* @param influenceIpo
|
||||||
* the ipo curve of the influence factor
|
* the ipo curve of the influence factor
|
||||||
@ -38,49 +40,83 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
* this exception is thrown when the blender file is somehow
|
* this exception is thrown when the blender file is somehow
|
||||||
* corrupted
|
* corrupted
|
||||||
*/
|
*/
|
||||||
public ConstraintLocLike(Structure constraintStructure, Long boneOMA,
|
public ConstraintLocLike(Structure constraintStructure, Long ownerOMA,
|
||||||
Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
super(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
|
||||||
|
|
||||||
|
flag = ((Number) data.getFieldValue("flag")).intValue();
|
||||||
|
|
||||||
|
if(blenderContext.getBlenderKey().isFixUpAxis()) {
|
||||||
|
//swapping Y and X limits flag in the bitwise flag
|
||||||
|
int y = flag & LOCLIKE_Y;
|
||||||
|
int invY = flag & LOCLIKE_Y_INVERT;
|
||||||
|
int z = flag & LOCLIKE_Z;
|
||||||
|
int invZ = flag & LOCLIKE_Z_INVERT;
|
||||||
|
flag &= LOCLIKE_X | LOCLIKE_X_INVERT | LOCLIKE_OFFSET;//clear the other flags to swap them
|
||||||
|
flag |= y << 2;
|
||||||
|
flag |= invY << 2;
|
||||||
|
flag |= z >> 2;
|
||||||
|
flag |= invZ >> 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void affectAnimation(Animation animation, int targetIndex) {
|
public void bakeDynamic() {
|
||||||
BoneTrack track = (BoneTrack) this.getTrack(animation, targetIndex);
|
AnimData animData = blenderContext.getAnimData(owner.getOma());
|
||||||
if (track != null) {
|
if(animData != null) {
|
||||||
Vector3f targetLocation = this.getTargetLocation();
|
Object owner = this.owner.getObject();
|
||||||
int flag = ((Number) data.getFieldValue("flag")).intValue();
|
Transform targetTransform = this.target.getTransform();
|
||||||
Vector3f[] translations = track.getTranslations();
|
for(Animation animation : animData.anims) {
|
||||||
|
BlenderTrack blenderTrack = this.getTrack(owner, animData.skeleton, animation);
|
||||||
|
Vector3f[] translations = blenderTrack.getTranslations();
|
||||||
int maxFrames = translations.length;
|
int maxFrames = translations.length;
|
||||||
for (int frame = 0; frame < maxFrames; ++frame) {
|
for (int frame = 0; frame < maxFrames; ++frame) {
|
||||||
|
this.locLike(translations[frame], targetTransform.getTranslation(), ipo.calculateValue(frame));
|
||||||
|
}
|
||||||
|
blenderTrack.setKeyframes(blenderTrack.getTimes(), translations, blenderTrack.getRotations(), blenderTrack.getScales());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bakeStatic() {
|
||||||
|
Transform targetTransform = this.target.getTransform();
|
||||||
|
Transform ownerTransform = this.owner.getTransform();
|
||||||
|
Vector3f ownerLocation = ownerTransform.getTranslation();
|
||||||
|
this.locLike(ownerLocation, targetTransform.getTranslation(), ipo.calculateValue(0));
|
||||||
|
this.owner.applyTransform(ownerTransform);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void locLike(Vector3f ownerLocation, Vector3f targetLocation, float influence) {
|
||||||
|
Vector3f startLocation = ownerLocation.clone();
|
||||||
Vector3f offset = Vector3f.ZERO;
|
Vector3f offset = Vector3f.ZERO;
|
||||||
if ((flag & LOCLIKE_OFFSET) != 0) {//we add the original location to the copied location
|
if ((flag & LOCLIKE_OFFSET) != 0) {//we add the original location to the copied location
|
||||||
offset = translations[frame].clone();
|
offset = startLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((flag & LOCLIKE_X) != 0) {
|
if ((flag & LOCLIKE_X) != 0) {
|
||||||
translations[frame].x = targetLocation.x;
|
ownerLocation.x = targetLocation.x;
|
||||||
if ((flag & LOCLIKE_X_INVERT) != 0) {
|
if ((flag & LOCLIKE_X_INVERT) != 0) {
|
||||||
translations[frame].x = -translations[frame].x;
|
ownerLocation.x = -ownerLocation.x;
|
||||||
}
|
}
|
||||||
} else if ((flag & LOCLIKE_Y) != 0) {
|
}
|
||||||
translations[frame].y = targetLocation.y;
|
if ((flag & LOCLIKE_Y) != 0) {
|
||||||
|
ownerLocation.y = targetLocation.y;
|
||||||
if ((flag & LOCLIKE_Y_INVERT) != 0) {
|
if ((flag & LOCLIKE_Y_INVERT) != 0) {
|
||||||
translations[frame].y = -translations[frame].y;
|
ownerLocation.y = -ownerLocation.y;
|
||||||
}
|
}
|
||||||
} else if ((flag & LOCLIKE_Z) != 0) {
|
}
|
||||||
translations[frame].z = targetLocation.z;
|
if ((flag & LOCLIKE_Z) != 0) {
|
||||||
|
ownerLocation.z = targetLocation.z;
|
||||||
if ((flag & LOCLIKE_Z_INVERT) != 0) {
|
if ((flag & LOCLIKE_Z_INVERT) != 0) {
|
||||||
translations[frame].z = -translations[frame].z;
|
ownerLocation.z = -ownerLocation.z;
|
||||||
}
|
|
||||||
}
|
|
||||||
translations[frame].addLocal(offset);//TODO: ipo influence
|
|
||||||
}
|
|
||||||
track.setKeyframes(track.getTimes(), translations, track.getRotations(), track.getScales());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ownerLocation.addLocal(offset);
|
||||||
|
|
||||||
@Override
|
if(influence < 1.0f) {
|
||||||
public ConstraintType getType() {
|
startLocation.subtractLocal(ownerLocation).normalizeLocal().mult(influence);
|
||||||
return ConstraintType.CONSTRAINT_TYPE_LOCLIKE;
|
ownerLocation.addLocal(startLocation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
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.BoneTrack;
|
import com.jme3.animation.Track;
|
||||||
|
import com.jme3.math.Transform;
|
||||||
import com.jme3.math.Vector3f;
|
import com.jme3.math.Vector3f;
|
||||||
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;
|
||||||
import com.jme3.scene.plugins.blender.file.Structure;
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
import com.jme3.scene.plugins.ogre.AnimData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class represents 'Loc limit' constraint type in blender.
|
* This class represents 'Loc limit' constraint type in blender.
|
||||||
@ -20,12 +22,15 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
private static final int LIMIT_ZMIN = 0x10;
|
private static final int LIMIT_ZMIN = 0x10;
|
||||||
private static final int LIMIT_ZMAX = 0x20;
|
private static final int LIMIT_ZMAX = 0x20;
|
||||||
|
|
||||||
|
protected float[][] limits = new float[3][2];
|
||||||
|
protected int flag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor creates the constraint instance.
|
* This constructor creates the constraint instance.
|
||||||
*
|
*
|
||||||
* @param constraintStructure
|
* @param constraintStructure
|
||||||
* the constraint's structure (bConstraint clss in blender 2.49).
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
* @param boneOMA
|
* @param ownerOMA
|
||||||
* the old memory address of the constraint owner
|
* the old memory address of the constraint owner
|
||||||
* @param influenceIpo
|
* @param influenceIpo
|
||||||
* the ipo curve of the influence factor
|
* the ipo curve of the influence factor
|
||||||
@ -35,63 +40,101 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
* this exception is thrown when the blender file is somehow
|
* this exception is thrown when the blender file is somehow
|
||||||
* corrupted
|
* corrupted
|
||||||
*/
|
*/
|
||||||
public ConstraintLocLimit(Structure constraintStructure, Long boneOMA,
|
public ConstraintLocLimit(Structure constraintStructure, Long ownerOMA,
|
||||||
Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
super(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
|
||||||
|
|
||||||
|
flag = ((Number) data.getFieldValue("flag")).intValue();
|
||||||
|
if(blenderContext.getBlenderKey().isFixUpAxis()) {
|
||||||
|
limits[0][0] = ((Number) data.getFieldValue("xmin")).floatValue();
|
||||||
|
limits[0][1] = ((Number) data.getFieldValue("xmax")).floatValue();
|
||||||
|
limits[2][0] = -((Number) data.getFieldValue("ymin")).floatValue();
|
||||||
|
limits[2][1] = -((Number) data.getFieldValue("ymax")).floatValue();
|
||||||
|
limits[1][0] = ((Number) data.getFieldValue("zmin")).floatValue();
|
||||||
|
limits[1][1] = ((Number) data.getFieldValue("zmax")).floatValue();
|
||||||
|
|
||||||
|
//swapping Y and X limits flag in the bitwise flag
|
||||||
|
int ymin = flag & LIMIT_YMIN;
|
||||||
|
int ymax = flag & LIMIT_YMAX;
|
||||||
|
int zmin = flag & LIMIT_ZMIN;
|
||||||
|
int zmax = flag & LIMIT_ZMAX;
|
||||||
|
flag &= LIMIT_XMIN | LIMIT_XMAX;//clear the other flags to swap them
|
||||||
|
flag |= ymin << 2;
|
||||||
|
flag |= ymax << 2;
|
||||||
|
flag |= zmin >> 2;
|
||||||
|
flag |= zmax >> 2;
|
||||||
|
} else {
|
||||||
|
limits[0][0] = ((Number) data.getFieldValue("xmin")).floatValue();
|
||||||
|
limits[0][1] = ((Number) data.getFieldValue("xmax")).floatValue();
|
||||||
|
limits[1][0] = ((Number) data.getFieldValue("ymin")).floatValue();
|
||||||
|
limits[1][1] = ((Number) data.getFieldValue("ymax")).floatValue();
|
||||||
|
limits[2][0] = ((Number) data.getFieldValue("zmin")).floatValue();
|
||||||
|
limits[2][1] = ((Number) data.getFieldValue("zmax")).floatValue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void affectAnimation(Animation animation, int targetIndex) {
|
public void bakeDynamic() {
|
||||||
BoneTrack track = (BoneTrack) this.getTrack(animation, targetIndex);
|
Object owner = this.owner.getObject();
|
||||||
if (track != null) {
|
AnimData animData = blenderContext.getAnimData(this.owner.getOma());
|
||||||
int flag = ((Number) data.getFieldValue("flag")).intValue();
|
if(animData != null) {
|
||||||
|
for(Animation animation : animData.anims) {
|
||||||
|
BlenderTrack track = this.getTrack(owner, animData.skeleton, animation);
|
||||||
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) {
|
||||||
float influence = ipo.calculateValue(frame);
|
this.locLimit(translations[frame], ipo.calculateValue(frame));
|
||||||
if ((flag & LIMIT_XMIN) != 0) {
|
|
||||||
float xmin = ((Number) data.getFieldValue("xmin")).floatValue();
|
|
||||||
if (translations[frame].x < xmin) {
|
|
||||||
translations[frame].x -= (translations[frame].x - xmin) * influence;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((flag & LIMIT_XMAX) != 0) {
|
|
||||||
float xmax = ((Number) data.getFieldValue("xmax")).floatValue();
|
|
||||||
if (translations[frame].x > xmax) {
|
|
||||||
translations[frame].x -= (translations[frame].x - xmax) * influence;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((flag & LIMIT_YMIN) != 0) {
|
|
||||||
float ymin = ((Number) data.getFieldValue("ymin")).floatValue();
|
|
||||||
if (translations[frame].y < ymin) {
|
|
||||||
translations[frame].y -= (translations[frame].y - ymin) * influence;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((flag & LIMIT_YMAX) != 0) {
|
|
||||||
float ymax = ((Number) data.getFieldValue("ymax")).floatValue();
|
|
||||||
if (translations[frame].y > ymax) {
|
|
||||||
translations[frame].y -= (translations[frame].y - ymax) * influence;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((flag & LIMIT_ZMIN) != 0) {
|
|
||||||
float zmin = ((Number) data.getFieldValue("zmin")).floatValue();
|
|
||||||
if (translations[frame].z < zmin) {
|
|
||||||
translations[frame].z -= (translations[frame].z - zmin) * influence;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((flag & LIMIT_ZMAX) != 0) {
|
|
||||||
float zmax = ((Number) data.getFieldValue("zmax")).floatValue();
|
|
||||||
if (translations[frame].z > zmax) {
|
|
||||||
translations[frame].z -= (translations[frame].z - zmax) * influence;
|
|
||||||
}
|
|
||||||
}//TODO: consider constraint space !!!
|
|
||||||
}
|
}
|
||||||
track.setKeyframes(track.getTimes(), translations, track.getRotations(), track.getScales());
|
track.setKeyframes(track.getTimes(), translations, track.getRotations(), track.getScales());
|
||||||
|
translations = track.getTranslations();
|
||||||
|
animation.setTracks(new Track[] {track.getTrack()});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConstraintType getType() {
|
public void bakeStatic() {
|
||||||
return ConstraintType.CONSTRAINT_TYPE_LOCLIMIT;
|
Transform ownerTransform = this.owner.getTransform();
|
||||||
|
Vector3f ownerLocation = ownerTransform.getTranslation();
|
||||||
|
this.locLimit(ownerLocation, ipo.calculateValue(0));
|
||||||
|
this.owner.applyTransform(ownerTransform);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method modifies the given translation.
|
||||||
|
* @param translation the translation to be modified.
|
||||||
|
* @param influence the influence value
|
||||||
|
*/
|
||||||
|
private void locLimit(Vector3f translation, float influence) {
|
||||||
|
if ((flag & LIMIT_XMIN) != 0) {
|
||||||
|
if (translation.x < limits[0][0]) {
|
||||||
|
translation.x -= (translation.x - limits[0][0]) * influence;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((flag & LIMIT_XMAX) != 0) {
|
||||||
|
if (translation.x > limits[0][1]) {
|
||||||
|
translation.x -= (translation.x - limits[0][1]) * influence;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((flag & LIMIT_YMIN) != 0) {
|
||||||
|
if (translation.y < limits[1][0]) {
|
||||||
|
translation.y -= (translation.y - limits[1][0]) * influence;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((flag & LIMIT_YMAX) != 0) {
|
||||||
|
if (translation.y > limits[1][1]) {
|
||||||
|
translation.y -= (translation.y - limits[1][1]) * influence;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((flag & LIMIT_ZMIN) != 0) {
|
||||||
|
if (translation.z < limits[2][0]) {
|
||||||
|
translation.z -= (translation.z - limits[2][0]) * influence;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((flag & LIMIT_ZMAX) != 0) {
|
||||||
|
if (translation.z > limits[2][1]) {
|
||||||
|
translation.z -= (translation.z - limits[2][1]) * influence;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package com.jme3.scene.plugins.blender.constraints;
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
import com.jme3.animation.Animation;
|
|
||||||
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;
|
||||||
@ -20,7 +19,7 @@ import java.util.logging.Logger;
|
|||||||
*
|
*
|
||||||
* @param constraintStructure
|
* @param constraintStructure
|
||||||
* the constraint's structure (bConstraint clss in blender 2.49).
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
* @param boneOMA
|
* @param ownerOMA
|
||||||
* the old memory address of the constraint owner
|
* the old memory address of the constraint owner
|
||||||
* @param influenceIpo
|
* @param influenceIpo
|
||||||
* the ipo curve of the influence factor
|
* the ipo curve of the influence factor
|
||||||
@ -30,20 +29,21 @@ import java.util.logging.Logger;
|
|||||||
* this exception is thrown when the blender file is somehow
|
* this exception is thrown when the blender file is somehow
|
||||||
* corrupted
|
* corrupted
|
||||||
*/
|
*/
|
||||||
public ConstraintLockTrack(Structure constraintStructure, Long boneOMA,
|
public ConstraintLockTrack(Structure constraintStructure, Long ownerOMA,
|
||||||
Ipo influenceIpo, BlenderContext blenderContext)
|
Ipo influenceIpo, BlenderContext blenderContext)
|
||||||
throws BlenderFileException {
|
throws BlenderFileException {
|
||||||
super(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void affectAnimation(Animation animation, int targetIndex) {
|
public void bakeDynamic() {
|
||||||
// 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!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConstraintType getType() {
|
public void bakeStatic() {
|
||||||
return ConstraintType.CONSTRAINT_TYPE_LOCKTRACK;
|
// TODO: implement 'Lock track' constraint
|
||||||
|
LOGGER.log(Level.WARNING, "'Lock track' constraint NOT implemented!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package com.jme3.scene.plugins.blender.constraints;
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
import com.jme3.animation.Animation;
|
|
||||||
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;
|
||||||
@ -20,7 +19,7 @@ import java.util.logging.Logger;
|
|||||||
*
|
*
|
||||||
* @param constraintStructure
|
* @param constraintStructure
|
||||||
* the constraint's structure (bConstraint clss in blender 2.49).
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
* @param boneOMA
|
* @param ownerOMA
|
||||||
* the old memory address of the constraint owner
|
* the old memory address of the constraint owner
|
||||||
* @param influenceIpo
|
* @param influenceIpo
|
||||||
* the ipo curve of the influence factor
|
* the ipo curve of the influence factor
|
||||||
@ -30,19 +29,20 @@ import java.util.logging.Logger;
|
|||||||
* this exception is thrown when the blender file is somehow
|
* this exception is thrown when the blender file is somehow
|
||||||
* corrupted
|
* corrupted
|
||||||
*/
|
*/
|
||||||
public ConstraintMinMax(Structure constraintStructure, Long boneOMA,
|
public ConstraintMinMax(Structure constraintStructure, Long ownerOMA,
|
||||||
Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
super(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void affectAnimation(Animation animation, int targetIndex) {
|
public void bakeDynamic() {
|
||||||
// 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!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConstraintType getType() {
|
public void bakeStatic() {
|
||||||
return ConstraintType.CONSTRAINT_TYPE_MINMAX;
|
// TODO: implement 'Min max' constraint
|
||||||
|
LOGGER.log(Level.WARNING, "'Min max' constraint NOT implemented!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package com.jme3.scene.plugins.blender.constraints;
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
import com.jme3.animation.Animation;
|
|
||||||
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;
|
||||||
@ -17,7 +16,7 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
*
|
*
|
||||||
* @param constraintStructure
|
* @param constraintStructure
|
||||||
* the constraint's structure (bConstraint clss in blender 2.49).
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
* @param boneOMA
|
* @param ownerOMA
|
||||||
* the old memory address of the constraint owner
|
* the old memory address of the constraint owner
|
||||||
* @param influenceIpo
|
* @param influenceIpo
|
||||||
* the ipo curve of the influence factor
|
* the ipo curve of the influence factor
|
||||||
@ -27,17 +26,15 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
* this exception is thrown when the blender file is somehow
|
* this exception is thrown when the blender file is somehow
|
||||||
* corrupted
|
* corrupted
|
||||||
*/
|
*/
|
||||||
public ConstraintNull(Structure constraintStructure, Long boneOMA,
|
public ConstraintNull(Structure constraintStructure, Long ownerOMA,
|
||||||
Ipo influenceIpo, BlenderContext blenderContext)
|
Ipo influenceIpo, BlenderContext blenderContext)
|
||||||
throws BlenderFileException {
|
throws BlenderFileException {
|
||||||
super(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void affectAnimation(Animation animation, int targetIndex) {}
|
public void bakeDynamic() {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConstraintType getType() {
|
public void bakeStatic() {}
|
||||||
return ConstraintType.CONSTRAINT_TYPE_NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,50 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import com.jme3.scene.plugins.blender.BlenderContext;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The pivot constraint. Available for blender 2.50+.
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
/*package*/ class ConstraintPivot extends Constraint {
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(ConstraintPivot.class.getName());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor creates the constraint instance.
|
||||||
|
*
|
||||||
|
* @param constraintStructure
|
||||||
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
|
* @param ownerOMA
|
||||||
|
* the old memory address of the constraint owner
|
||||||
|
* @param influenceIpo
|
||||||
|
* the ipo curve of the influence factor
|
||||||
|
* @param blenderContext
|
||||||
|
* the blender context
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
public ConstraintPivot(Structure constraintStructure, Long ownerOMA, Ipo influenceIpo,
|
||||||
|
BlenderContext blenderContext) throws BlenderFileException {
|
||||||
|
super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
|
||||||
|
// TODO Auto-generated constructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bakeDynamic() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
LOGGER.log(Level.WARNING, "'Pivot' constraint NOT implemented!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bakeStatic() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
LOGGER.log(Level.WARNING, "'Pivot' constraint NOT implemented!");
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,5 @@
|
|||||||
package com.jme3.scene.plugins.blender.constraints;
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
import com.jme3.animation.Animation;
|
|
||||||
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;
|
||||||
@ -20,7 +19,7 @@ import java.util.logging.Logger;
|
|||||||
*
|
*
|
||||||
* @param constraintStructure
|
* @param constraintStructure
|
||||||
* the constraint's structure (bConstraint clss in blender 2.49).
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
* @param boneOMA
|
* @param ownerOMA
|
||||||
* the old memory address of the constraint owner
|
* the old memory address of the constraint owner
|
||||||
* @param influenceIpo
|
* @param influenceIpo
|
||||||
* the ipo curve of the influence factor
|
* the ipo curve of the influence factor
|
||||||
@ -30,19 +29,20 @@ import java.util.logging.Logger;
|
|||||||
* this exception is thrown when the blender file is somehow
|
* this exception is thrown when the blender file is somehow
|
||||||
* corrupted
|
* corrupted
|
||||||
*/
|
*/
|
||||||
public ConstraintPython(Structure constraintStructure, Long boneOMA,
|
public ConstraintPython(Structure constraintStructure, Long ownerOMA,
|
||||||
Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
super(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void affectAnimation(Animation animation, int targetIndex) {
|
public void bakeDynamic() {
|
||||||
// TODO: implement 'Python' constraint
|
// TODO: implement 'Python' constraint
|
||||||
LOGGER.log(Level.WARNING, "'Python' constraint NOT implemented!");
|
LOGGER.log(Level.WARNING, "'Python' constraint NOT implemented!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConstraintType getType() {
|
public void bakeStatic() {
|
||||||
return ConstraintType.CONSTRAINT_TYPE_PYTHON;
|
// TODO: implement 'Python' constraint
|
||||||
|
LOGGER.log(Level.WARNING, "'Python' constraint NOT implemented!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package com.jme3.scene.plugins.blender.constraints;
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
import com.jme3.animation.Animation;
|
|
||||||
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;
|
||||||
@ -20,7 +19,7 @@ import java.util.logging.Logger;
|
|||||||
*
|
*
|
||||||
* @param constraintStructure
|
* @param constraintStructure
|
||||||
* the constraint's structure (bConstraint clss in blender 2.49).
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
* @param boneOMA
|
* @param ownerOMA
|
||||||
* the old memory address of the constraint owner
|
* the old memory address of the constraint owner
|
||||||
* @param influenceIpo
|
* @param influenceIpo
|
||||||
* the ipo curve of the influence factor
|
* the ipo curve of the influence factor
|
||||||
@ -31,18 +30,19 @@ import java.util.logging.Logger;
|
|||||||
* corrupted
|
* corrupted
|
||||||
*/
|
*/
|
||||||
public ConstraintRigidBodyJoint(Structure constraintStructure,
|
public ConstraintRigidBodyJoint(Structure constraintStructure,
|
||||||
Long boneOMA, Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
Long ownerOMA, Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
super(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void affectAnimation(Animation animation, int targetIndex) {
|
public void bakeDynamic() {
|
||||||
// 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!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConstraintType getType() {
|
public void bakeStatic() {
|
||||||
return ConstraintType.CONSTRAINT_TYPE_RIGIDBODYJOINT;
|
// TODO: implement 'Rigid body joint' constraint
|
||||||
|
LOGGER.log(Level.WARNING, "'Rigid body joint' constraint NOT implemented!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
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.BoneTrack;
|
|
||||||
import com.jme3.math.Quaternion;
|
import com.jme3.math.Quaternion;
|
||||||
|
import com.jme3.math.Transform;
|
||||||
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;
|
||||||
import com.jme3.scene.plugins.blender.file.Structure;
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
import com.jme3.scene.plugins.ogre.AnimData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class represents 'Rot like' constraint type in blender.
|
* This class represents 'Rot like' constraint type in blender.
|
||||||
@ -21,12 +22,14 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
private static final int ROTLIKE_Z_INVERT = 0x40;
|
private static final int ROTLIKE_Z_INVERT = 0x40;
|
||||||
private static final int ROTLIKE_OFFSET = 0x80;
|
private static final int ROTLIKE_OFFSET = 0x80;
|
||||||
|
|
||||||
|
protected int flag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor creates the constraint instance.
|
* This constructor creates the constraint instance.
|
||||||
*
|
*
|
||||||
* @param constraintStructure
|
* @param constraintStructure
|
||||||
* the constraint's structure (bConstraint clss in blender 2.49).
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
* @param boneOMA
|
* @param ownerOMA
|
||||||
* the old memory address of the constraint owner
|
* the old memory address of the constraint owner
|
||||||
* @param influenceIpo
|
* @param influenceIpo
|
||||||
* the ipo curve of the influence factor
|
* the ipo curve of the influence factor
|
||||||
@ -36,52 +39,76 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
* this exception is thrown when the blender file is somehow
|
* this exception is thrown when the blender file is somehow
|
||||||
* corrupted
|
* corrupted
|
||||||
*/
|
*/
|
||||||
public ConstraintRotLike(Structure constraintStructure, Long boneOMA,
|
public ConstraintRotLike(Structure constraintStructure, Long ownerOMA,
|
||||||
Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
super(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
|
||||||
|
|
||||||
|
flag = ((Number) data.getFieldValue("flag")).intValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void affectAnimation(Animation animation, int targetIndex) {
|
public void bakeDynamic() {
|
||||||
BoneTrack track = (BoneTrack) this.getTrack(animation, targetIndex);
|
AnimData animData = blenderContext.getAnimData(this.owner.getOma());
|
||||||
if (track != null) {
|
if(animData != null) {
|
||||||
Quaternion targetRotation = this.getTargetRotation();
|
Object owner = this.owner.getObject();
|
||||||
int flag = ((Number) data.getFieldValue("flag")).intValue();
|
Transform targetTransform = this.target.getTransform();
|
||||||
|
Quaternion targetRotation = targetTransform.getRotation();
|
||||||
|
for(Animation animation : animData.anims) {
|
||||||
|
BlenderTrack track = this.getTrack(owner, animData.skeleton, animation);
|
||||||
float[] targetAngles = targetRotation.toAngles(null);
|
float[] targetAngles = targetRotation.toAngles(null);
|
||||||
Quaternion[] rotations = track.getRotations();
|
Quaternion[] rotations = track.getRotations();
|
||||||
int maxFrames = rotations.length;
|
int maxFrames = rotations.length;
|
||||||
|
float[] angles = new float[3];
|
||||||
for (int frame = 0; frame < maxFrames; ++frame) {
|
for (int frame = 0; frame < maxFrames; ++frame) {
|
||||||
float[] angles = rotations[frame].toAngles(null);
|
rotations[frame].toAngles(angles);
|
||||||
|
this.rotLike(rotations[frame], angles, targetAngles, ipo.calculateValue(frame));
|
||||||
Quaternion offset = Quaternion.IDENTITY;
|
|
||||||
if ((flag & ROTLIKE_OFFSET) != 0) {//we add the original rotation to the copied rotation
|
|
||||||
offset = rotations[frame].clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((flag & ROTLIKE_X) != 0) {
|
|
||||||
angles[0] = targetAngles[0];
|
|
||||||
if ((flag & ROTLIKE_X_INVERT) != 0) {
|
|
||||||
angles[0] = -angles[0];
|
|
||||||
}
|
|
||||||
} else if ((flag & ROTLIKE_Y) != 0) {
|
|
||||||
angles[1] = targetAngles[1];
|
|
||||||
if ((flag & ROTLIKE_Y_INVERT) != 0) {
|
|
||||||
angles[1] = -angles[1];
|
|
||||||
}
|
|
||||||
} else if ((flag & ROTLIKE_Z) != 0) {
|
|
||||||
angles[2] = targetAngles[2];
|
|
||||||
if ((flag & ROTLIKE_Z_INVERT) != 0) {
|
|
||||||
angles[2] = -angles[2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rotations[frame].fromAngles(angles).multLocal(offset);//TODO: ipo influence
|
|
||||||
}
|
}
|
||||||
track.setKeyframes(track.getTimes(), track.getTranslations(), rotations, track.getScales());
|
track.setKeyframes(track.getTimes(), track.getTranslations(), rotations, track.getScales());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConstraintType getType() {
|
public void bakeStatic() {
|
||||||
return ConstraintType.CONSTRAINT_TYPE_ROTLIKE;
|
Transform targetTransform = this.target.getTransform();
|
||||||
|
Transform ownerTransform = this.owner.getTransform();
|
||||||
|
Quaternion ownerRotation = ownerTransform.getRotation();
|
||||||
|
this.rotLike(ownerRotation, ownerRotation.toAngles(null), targetTransform.getRotation().toAngles(null), ipo.calculateValue(0));
|
||||||
|
this.owner.applyTransform(ownerTransform);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void rotLike(Quaternion ownerRotation, float[] ownerAngles, float[] targetAngles, float influence) {
|
||||||
|
Quaternion startRotation = ownerRotation.clone();
|
||||||
|
Quaternion offset = Quaternion.IDENTITY;
|
||||||
|
if ((flag & ROTLIKE_OFFSET) != 0) {//we add the original rotation to the copied rotation
|
||||||
|
offset = startRotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((flag & ROTLIKE_X) != 0) {
|
||||||
|
ownerAngles[0] = targetAngles[0];
|
||||||
|
if ((flag & ROTLIKE_X_INVERT) != 0) {
|
||||||
|
ownerAngles[0] = -ownerAngles[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((flag & ROTLIKE_Y) != 0) {
|
||||||
|
ownerAngles[1] = targetAngles[1];
|
||||||
|
if ((flag & ROTLIKE_Y_INVERT) != 0) {
|
||||||
|
ownerAngles[1] = -ownerAngles[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((flag & ROTLIKE_Z) != 0) {
|
||||||
|
ownerAngles[2] = targetAngles[2];
|
||||||
|
if ((flag & ROTLIKE_Z_INVERT) != 0) {
|
||||||
|
ownerAngles[2] = -ownerAngles[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ownerRotation.fromAngles(ownerAngles).multLocal(offset);
|
||||||
|
|
||||||
|
if(influence < 1.0f) {
|
||||||
|
|
||||||
|
// startLocation.subtractLocal(ownerLocation).normalizeLocal().mult(influence);
|
||||||
|
// ownerLocation.addLocal(startLocation);
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
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.BoneTrack;
|
|
||||||
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.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;
|
||||||
import com.jme3.scene.plugins.blender.file.Structure;
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
import com.jme3.scene.plugins.ogre.AnimData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class represents 'Rot limit' constraint type in blender.
|
* This class represents 'Rot limit' constraint type in blender.
|
||||||
@ -18,12 +19,15 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
private static final int LIMIT_YROT = 0x02;
|
private static final int LIMIT_YROT = 0x02;
|
||||||
private static final int LIMIT_ZROT = 0x04;
|
private static final int LIMIT_ZROT = 0x04;
|
||||||
|
|
||||||
|
protected float[][] limits = new float[3][2];
|
||||||
|
protected int flag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor creates the constraint instance.
|
* This constructor creates the constraint instance.
|
||||||
*
|
*
|
||||||
* @param constraintStructure
|
* @param constraintStructure
|
||||||
* the constraint's structure (bConstraint clss in blender 2.49).
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
* @param boneOMA
|
* @param ownerOMA
|
||||||
* the old memory address of the constraint owner
|
* the old memory address of the constraint owner
|
||||||
* @param influenceIpo
|
* @param influenceIpo
|
||||||
* the ipo curve of the influence factor
|
* the ipo curve of the influence factor
|
||||||
@ -33,62 +37,100 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
* this exception is thrown when the blender file is somehow
|
* this exception is thrown when the blender file is somehow
|
||||||
* corrupted
|
* corrupted
|
||||||
*/
|
*/
|
||||||
public ConstraintRotLimit(Structure constraintStructure, Long boneOMA,
|
public ConstraintRotLimit(Structure constraintStructure, Long ownerOMA,
|
||||||
Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
super(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
|
||||||
|
|
||||||
|
if(blenderContext.getBlenderKey().isFixUpAxis()) {
|
||||||
|
limits[0][0] = ((Number) data.getFieldValue("xmin")).floatValue() * FastMath.DEG_TO_RAD;
|
||||||
|
limits[0][1] = ((Number) data.getFieldValue("xmax")).floatValue() * FastMath.DEG_TO_RAD;
|
||||||
|
limits[2][0] = -((Number) data.getFieldValue("ymin")).floatValue() * FastMath.DEG_TO_RAD;
|
||||||
|
limits[2][1] = -((Number) data.getFieldValue("ymax")).floatValue() * FastMath.DEG_TO_RAD;
|
||||||
|
limits[1][0] = ((Number) data.getFieldValue("zmin")).floatValue() * FastMath.DEG_TO_RAD;
|
||||||
|
limits[1][1] = ((Number) data.getFieldValue("zmax")).floatValue() * FastMath.DEG_TO_RAD;
|
||||||
|
} else {
|
||||||
|
limits[0][0] = ((Number) data.getFieldValue("xmin")).floatValue() * FastMath.DEG_TO_RAD;
|
||||||
|
limits[0][1] = ((Number) data.getFieldValue("xmax")).floatValue() * FastMath.DEG_TO_RAD;
|
||||||
|
limits[1][0] = ((Number) data.getFieldValue("ymin")).floatValue() * FastMath.DEG_TO_RAD;
|
||||||
|
limits[1][1] = ((Number) data.getFieldValue("ymax")).floatValue() * FastMath.DEG_TO_RAD;
|
||||||
|
limits[2][0] = ((Number) data.getFieldValue("zmin")).floatValue() * FastMath.DEG_TO_RAD;
|
||||||
|
limits[2][1] = ((Number) data.getFieldValue("zmax")).floatValue() * FastMath.DEG_TO_RAD;
|
||||||
|
}
|
||||||
|
flag = ((Number) data.getFieldValue("flag")).intValue();
|
||||||
|
if(blenderContext.getBlenderKey().isFixUpAxis()) {
|
||||||
|
//swapping Y and X limits flag in the bitwise flag
|
||||||
|
int limitY = flag & LIMIT_YROT;
|
||||||
|
int limitZ = flag & LIMIT_ZROT;
|
||||||
|
flag &= LIMIT_XROT;//clear the other flags to swap them
|
||||||
|
flag |= limitY << 1;
|
||||||
|
flag |= limitZ >> 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void affectAnimation(Animation animation, int targetIndex) {
|
public void bakeDynamic() {
|
||||||
BoneTrack track = (BoneTrack) this.getTrack(animation, targetIndex);
|
AnimData animData = blenderContext.getAnimData(owner.getOma());
|
||||||
if (track != null) {
|
if(animData != null) {
|
||||||
int flag = ((Number) data.getFieldValue("flag")).intValue();
|
Object owner = this.owner.getObject();
|
||||||
|
for(Animation animation : animData.anims) {
|
||||||
|
BlenderTrack track = this.getTrack(owner, animData.skeleton, animation);
|
||||||
Quaternion[] rotations = track.getRotations();
|
Quaternion[] rotations = track.getRotations();
|
||||||
|
float[] angles = new float[3];
|
||||||
int maxFrames = rotations.length;
|
int maxFrames = rotations.length;
|
||||||
for (int frame = 0; frame < maxFrames; ++frame) {
|
for (int frame = 0; frame < maxFrames; ++frame) {
|
||||||
float[] angles = rotations[frame].toAngles(null);
|
rotations[frame].toAngles(angles);
|
||||||
float influence = ipo.calculateValue(frame);
|
this.rotLimit(angles, ipo.calculateValue(frame));
|
||||||
if ((flag & LIMIT_XROT) != 0) {
|
rotations[frame].fromAngles(angles);
|
||||||
float xmin = ((Number) data.getFieldValue("xmin")).floatValue() * FastMath.DEG_TO_RAD;
|
|
||||||
float xmax = ((Number) data.getFieldValue("xmax")).floatValue() * FastMath.DEG_TO_RAD;
|
|
||||||
float difference = 0.0f;
|
|
||||||
if (angles[0] < xmin) {
|
|
||||||
difference = (angles[0] - xmin) * influence;
|
|
||||||
} else if (angles[0] > xmax) {
|
|
||||||
difference = (angles[0] - xmax) * influence;
|
|
||||||
}
|
|
||||||
angles[0] -= difference;
|
|
||||||
}
|
|
||||||
if ((flag & LIMIT_YROT) != 0) {
|
|
||||||
float ymin = ((Number) data.getFieldValue("ymin")).floatValue() * FastMath.DEG_TO_RAD;
|
|
||||||
float ymax = ((Number) data.getFieldValue("ymax")).floatValue() * FastMath.DEG_TO_RAD;
|
|
||||||
float difference = 0.0f;
|
|
||||||
if (angles[1] < ymin) {
|
|
||||||
difference = (angles[1] - ymin) * influence;
|
|
||||||
} else if (angles[1] > ymax) {
|
|
||||||
difference = (angles[1] - ymax) * influence;
|
|
||||||
}
|
|
||||||
angles[1] -= difference;
|
|
||||||
}
|
|
||||||
if ((flag & LIMIT_ZROT) != 0) {
|
|
||||||
float zmin = ((Number) data.getFieldValue("zmin")).floatValue() * FastMath.DEG_TO_RAD;
|
|
||||||
float zmax = ((Number) data.getFieldValue("zmax")).floatValue() * FastMath.DEG_TO_RAD;
|
|
||||||
float difference = 0.0f;
|
|
||||||
if (angles[2] < zmin) {
|
|
||||||
difference = (angles[2] - zmin) * influence;
|
|
||||||
} else if (angles[2] > zmax) {
|
|
||||||
difference = (angles[2] - zmax) * influence;
|
|
||||||
}
|
|
||||||
angles[2] -= difference;
|
|
||||||
}
|
|
||||||
rotations[frame].fromAngles(angles);//TODO: consider constraint space !!!
|
|
||||||
}
|
}
|
||||||
track.setKeyframes(track.getTimes(), track.getTranslations(), rotations, track.getScales());
|
track.setKeyframes(track.getTimes(), track.getTranslations(), rotations, track.getScales());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConstraintType getType() {
|
public void bakeStatic() {
|
||||||
return ConstraintType.CONSTRAINT_TYPE_ROTLIMIT;
|
Transform ownerTransform = this.owner.getTransform();
|
||||||
|
float[] angles = ownerTransform.getRotation().toAngles(null);
|
||||||
|
this.rotLimit(angles, ipo.calculateValue(0));
|
||||||
|
ownerTransform.getRotation().fromAngles(angles);
|
||||||
|
this.owner.applyTransform(ownerTransform);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method computes new constrained angles.
|
||||||
|
*
|
||||||
|
* @param angles
|
||||||
|
* angles to be altered
|
||||||
|
* @param influence
|
||||||
|
* the alteration influence
|
||||||
|
*/
|
||||||
|
private void rotLimit(float[] angles, float influence) {
|
||||||
|
if ((flag & LIMIT_XROT) != 0) {
|
||||||
|
float difference = 0.0f;
|
||||||
|
if (angles[0] < limits[0][0]) {
|
||||||
|
difference = (angles[0] - limits[0][0]) * influence;
|
||||||
|
} else if (angles[0] > limits[0][1]) {
|
||||||
|
difference = (angles[0] - limits[0][1]) * influence;
|
||||||
|
}
|
||||||
|
angles[0] -= difference;
|
||||||
|
}
|
||||||
|
if ((flag & LIMIT_YROT) != 0) {
|
||||||
|
float difference = 0.0f;
|
||||||
|
if (angles[1] < limits[1][0]) {
|
||||||
|
difference = (angles[1] - limits[1][0]) * influence;
|
||||||
|
} else if (angles[1] > limits[1][1]) {
|
||||||
|
difference = (angles[1] - limits[1][1]) * influence;
|
||||||
|
}
|
||||||
|
angles[1] -= difference;
|
||||||
|
}
|
||||||
|
if ((flag & LIMIT_ZROT) != 0) {
|
||||||
|
float difference = 0.0f;
|
||||||
|
if (angles[2] < limits[2][0]) {
|
||||||
|
difference = (angles[2] - limits[2][0]) * influence;
|
||||||
|
} else if (angles[2] > limits[2][1]) {
|
||||||
|
difference = (angles[2] - limits[2][1]) * influence;
|
||||||
|
}
|
||||||
|
angles[2] -= difference;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
package com.jme3.scene.plugins.blender.constraints;
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import com.jme3.animation.Animation;
|
import com.jme3.animation.Animation;
|
||||||
import com.jme3.animation.BoneTrack;
|
|
||||||
import com.jme3.math.Quaternion;
|
import com.jme3.math.Quaternion;
|
||||||
import com.jme3.math.Vector3f;
|
import com.jme3.math.Vector3f;
|
||||||
import com.jme3.scene.Geometry;
|
import com.jme3.scene.Geometry;
|
||||||
@ -10,28 +13,23 @@ import com.jme3.scene.Node;
|
|||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.scene.VertexBuffer.Type;
|
import com.jme3.scene.VertexBuffer.Type;
|
||||||
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.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;
|
||||||
import com.jme3.scene.plugins.blender.file.Structure;
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
import java.nio.FloatBuffer;
|
import com.jme3.scene.plugins.ogre.AnimData;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class represents 'Shrink wrap' constraint type in blender.
|
* This class represents 'Shrink wrap' constraint type in blender.
|
||||||
* @author Marcin Roguski (Kaelthas)
|
* @author Marcin Roguski (Kaelthas)
|
||||||
*/
|
*/
|
||||||
/*package*/ class ConstraintShrinkWrap extends Constraint {
|
/*package*/ class ConstraintShrinkWrap extends Constraint {
|
||||||
private static final Logger LOGGER = Logger.getLogger(ConstraintShrinkWrap.class.getName());
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor creates the constraint instance.
|
* This constructor creates the constraint instance.
|
||||||
*
|
*
|
||||||
* @param constraintStructure
|
* @param constraintStructure
|
||||||
* the constraint's structure (bConstraint clss in blender 2.49).
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
* @param boneOMA
|
* @param ownerOMA
|
||||||
* the old memory address of the constraint owner
|
* the old memory address of the constraint owner
|
||||||
* @param influenceIpo
|
* @param influenceIpo
|
||||||
* the ipo curve of the influence factor
|
* the ipo curve of the influence factor
|
||||||
@ -41,18 +39,17 @@ import java.util.logging.Logger;
|
|||||||
* this exception is thrown when the blender file is somehow
|
* this exception is thrown when the blender file is somehow
|
||||||
* corrupted
|
* corrupted
|
||||||
*/
|
*/
|
||||||
public ConstraintShrinkWrap(Structure constraintStructure, Long boneOMA,
|
public ConstraintShrinkWrap(Structure constraintStructure, Long ownerOMA,
|
||||||
Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
super(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void affectAnimation(Animation animation, int targetIndex) {
|
public void bakeDynamic() {
|
||||||
//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>();
|
||||||
try {
|
Node target = (Node) this.target.getObject();
|
||||||
Node node = (Node)this.getTarget(LoadedFeatureDataType.LOADED_FEATURE);
|
for(Spatial spatial : target.getChildren()) {
|
||||||
for(Spatial spatial : node.getChildren()) {
|
|
||||||
if(spatial instanceof Geometry) {
|
if(spatial instanceof Geometry) {
|
||||||
Mesh mesh = ((Geometry) spatial).getMesh();
|
Mesh mesh = ((Geometry) spatial).getMesh();
|
||||||
FloatBuffer floatBuffer = mesh.getFloatBuffer(Type.Position);
|
FloatBuffer floatBuffer = mesh.getFloatBuffer(Type.Position);
|
||||||
@ -62,9 +59,11 @@ import java.util.logging.Logger;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//modifying traces
|
AnimData animData = blenderContext.getAnimData(this.owner.getOma());
|
||||||
BoneTrack track = (BoneTrack) this.getTrack(animation, targetIndex);
|
if(animData != null) {
|
||||||
if (track != null) {
|
Object owner = this.owner.getObject();
|
||||||
|
for(Animation animation : animData.anims) {
|
||||||
|
BlenderTrack track = this.getTrack(owner, animData.skeleton, animation);
|
||||||
Vector3f[] translations = track.getTranslations();
|
Vector3f[] translations = track.getTranslations();
|
||||||
Quaternion[] rotations = track.getRotations();
|
Quaternion[] rotations = track.getRotations();
|
||||||
int maxFrames = translations.length;
|
int maxFrames = translations.length;
|
||||||
@ -86,13 +85,12 @@ import java.util.logging.Logger;
|
|||||||
|
|
||||||
track.setKeyframes(track.getTimes(), translations, rotations, track.getScales());
|
track.setKeyframes(track.getTimes(), translations, rotations, track.getScales());
|
||||||
}
|
}
|
||||||
} catch (BlenderFileException e) {
|
|
||||||
LOGGER.severe(e.getLocalizedMessage());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConstraintType getType() {
|
public void bakeStatic() {
|
||||||
return ConstraintType.CONSTRAINT_TYPE_SHRINKWRAP;
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
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.BoneTrack;
|
import com.jme3.math.Transform;
|
||||||
import com.jme3.math.Vector3f;
|
import com.jme3.math.Vector3f;
|
||||||
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;
|
||||||
import com.jme3.scene.plugins.blender.file.Structure;
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
import com.jme3.scene.plugins.ogre.AnimData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class represents 'Size like' constraint type in blender.
|
* This class represents 'Size like' constraint type in blender.
|
||||||
@ -18,12 +19,14 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
private static final int SIZELIKE_Z = 0x04;
|
private static final int SIZELIKE_Z = 0x04;
|
||||||
private static final int LOCLIKE_OFFSET = 0x80;
|
private static final int LOCLIKE_OFFSET = 0x80;
|
||||||
|
|
||||||
|
protected int flag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor creates the constraint instance.
|
* This constructor creates the constraint instance.
|
||||||
*
|
*
|
||||||
* @param constraintStructure
|
* @param constraintStructure
|
||||||
* the constraint's structure (bConstraint clss in blender 2.49).
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
* @param boneOMA
|
* @param ownerOMA
|
||||||
* the old memory address of the constraint owner
|
* the old memory address of the constraint owner
|
||||||
* @param influenceIpo
|
* @param influenceIpo
|
||||||
* the ipo curve of the influence factor
|
* the ipo curve of the influence factor
|
||||||
@ -33,41 +36,63 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
* this exception is thrown when the blender file is somehow
|
* this exception is thrown when the blender file is somehow
|
||||||
* corrupted
|
* corrupted
|
||||||
*/
|
*/
|
||||||
public ConstraintSizeLike(Structure constraintStructure, Long boneOMA,
|
public ConstraintSizeLike(Structure constraintStructure, Long ownerOMA,
|
||||||
Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
super(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
|
||||||
|
|
||||||
|
flag = ((Number) data.getFieldValue("flag")).intValue();
|
||||||
|
if(blenderContext.getBlenderKey().isFixUpAxis()) {
|
||||||
|
//swapping Y and X limits flag in the bitwise flag
|
||||||
|
int y = flag & SIZELIKE_Y;
|
||||||
|
int z = flag & SIZELIKE_Z;
|
||||||
|
flag &= SIZELIKE_X | LOCLIKE_OFFSET;//clear the other flags to swap them
|
||||||
|
flag |= y << 1;
|
||||||
|
flag |= z >> 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void affectAnimation(Animation animation, int targetIndex) {
|
public void bakeDynamic() {
|
||||||
Vector3f targetScale = this.getTargetLocation();
|
AnimData animData = blenderContext.getAnimData(this.owner.getOma());
|
||||||
BoneTrack track = (BoneTrack) this.getTrack(animation, targetIndex);
|
if(animData != null) {
|
||||||
if (track != null) {
|
Object owner = this.owner.getObject();
|
||||||
int flag = ((Number) data.getFieldValue("flag")).intValue();
|
Transform targetTransform = this.target.getTransform();
|
||||||
|
Vector3f targetScale = targetTransform.getScale();
|
||||||
|
for(Animation animation : animData.anims) {
|
||||||
|
BlenderTrack track = this.getTrack(owner, animData.skeleton, animation);
|
||||||
Vector3f[] scales = track.getScales();
|
Vector3f[] scales = track.getScales();
|
||||||
int maxFrames = scales.length;
|
int maxFrames = scales.length;
|
||||||
for (int frame = 0; frame < maxFrames; ++frame) {
|
for (int frame = 0; frame < maxFrames; ++frame) {
|
||||||
Vector3f offset = Vector3f.ZERO;
|
this.sizeLike(scales[frame], targetScale, ipo.calculateValue(frame));
|
||||||
if ((flag & LOCLIKE_OFFSET) != 0) {//we add the original scale to the copied scale
|
|
||||||
offset = scales[frame].clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((flag & SIZELIKE_X) != 0) {
|
|
||||||
scales[frame].x = targetScale.x;
|
|
||||||
} else if ((flag & SIZELIKE_Y) != 0) {
|
|
||||||
scales[frame].y = targetScale.y;
|
|
||||||
} else if ((flag & SIZELIKE_Z) != 0) {
|
|
||||||
scales[frame].z = targetScale.z;
|
|
||||||
}
|
|
||||||
scales[frame].addLocal(offset);//TODO: ipo influence
|
|
||||||
//TODO: add or multiply???
|
|
||||||
}
|
}
|
||||||
track.setKeyframes(track.getTimes(), track.getTranslations(), track.getRotations(), scales);
|
track.setKeyframes(track.getTimes(), track.getTranslations(), track.getRotations(), scales);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConstraintType getType() {
|
public void bakeStatic() {
|
||||||
return ConstraintType.CONSTRAINT_TYPE_SIZELIKE;
|
Transform targetTransform = this.target.getTransform();
|
||||||
|
Transform ownerTransform = this.owner.getTransform();
|
||||||
|
this.sizeLike(ownerTransform.getScale(), targetTransform.getScale(), ipo.calculateValue(0));
|
||||||
|
this.owner.applyTransform(ownerTransform);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sizeLike(Vector3f ownerScale, Vector3f targetScale, float influence) {
|
||||||
|
Vector3f offset = Vector3f.ZERO;
|
||||||
|
if ((flag & LOCLIKE_OFFSET) != 0) {//we add the original scale to the copied scale
|
||||||
|
offset = ownerScale.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((flag & SIZELIKE_X) != 0) {
|
||||||
|
ownerScale.x = targetScale.x * influence + (1.0f - influence) * ownerScale.x;
|
||||||
|
}
|
||||||
|
if ((flag & SIZELIKE_Y) != 0) {
|
||||||
|
ownerScale.y = targetScale.y * influence + (1.0f - influence) * ownerScale.y;
|
||||||
|
}
|
||||||
|
if ((flag & SIZELIKE_Z) != 0) {
|
||||||
|
ownerScale.z = targetScale.z * influence + (1.0f - influence) * ownerScale.z;
|
||||||
|
}
|
||||||
|
ownerScale.addLocal(offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
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.BoneTrack;
|
import com.jme3.math.Transform;
|
||||||
import com.jme3.math.Vector3f;
|
import com.jme3.math.Vector3f;
|
||||||
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;
|
||||||
import com.jme3.scene.plugins.blender.file.Structure;
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
import com.jme3.scene.plugins.ogre.AnimData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class represents 'Size limit' constraint type in blender.
|
* This class represents 'Size limit' constraint type in blender.
|
||||||
@ -20,12 +21,15 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
private static final int LIMIT_ZMIN = 0x10;
|
private static final int LIMIT_ZMIN = 0x10;
|
||||||
private static final int LIMIT_ZMAX = 0x20;
|
private static final int LIMIT_ZMAX = 0x20;
|
||||||
|
|
||||||
|
protected float[][] limits = new float[3][2];
|
||||||
|
protected int flag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor creates the constraint instance.
|
* This constructor creates the constraint instance.
|
||||||
*
|
*
|
||||||
* @param constraintStructure
|
* @param constraintStructure
|
||||||
* the constraint's structure (bConstraint clss in blender 2.49).
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
* @param boneOMA
|
* @param ownerOMA
|
||||||
* the old memory address of the constraint owner
|
* the old memory address of the constraint owner
|
||||||
* @param influenceIpo
|
* @param influenceIpo
|
||||||
* the ipo curve of the influence factor
|
* the ipo curve of the influence factor
|
||||||
@ -35,63 +39,93 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
* this exception is thrown when the blender file is somehow
|
* this exception is thrown when the blender file is somehow
|
||||||
* corrupted
|
* corrupted
|
||||||
*/
|
*/
|
||||||
public ConstraintSizeLimit(Structure constraintStructure, Long boneOMA,
|
public ConstraintSizeLimit(Structure constraintStructure, Long ownerOMA,
|
||||||
Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
super(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
|
||||||
|
|
||||||
|
flag = ((Number) data.getFieldValue("flag")).intValue();
|
||||||
|
if(blenderContext.getBlenderKey().isFixUpAxis()) {
|
||||||
|
limits[0][0] = ((Number) data.getFieldValue("xmin")).floatValue();
|
||||||
|
limits[0][1] = ((Number) data.getFieldValue("xmax")).floatValue();
|
||||||
|
limits[2][0] = -((Number) data.getFieldValue("ymin")).floatValue();
|
||||||
|
limits[2][1] = -((Number) data.getFieldValue("ymax")).floatValue();
|
||||||
|
limits[1][0] = ((Number) data.getFieldValue("zmin")).floatValue();
|
||||||
|
limits[1][1] = ((Number) data.getFieldValue("zmax")).floatValue();
|
||||||
|
|
||||||
|
//swapping Y and X limits flag in the bitwise flag
|
||||||
|
int ymin = flag & LIMIT_YMIN;
|
||||||
|
int ymax = flag & LIMIT_YMAX;
|
||||||
|
int zmin = flag & LIMIT_ZMIN;
|
||||||
|
int zmax = flag & LIMIT_ZMAX;
|
||||||
|
flag &= LIMIT_XMIN | LIMIT_XMAX;//clear the other flags to swap them
|
||||||
|
flag |= ymin << 2;
|
||||||
|
flag |= ymax << 2;
|
||||||
|
flag |= zmin >> 2;
|
||||||
|
flag |= zmax >> 2;
|
||||||
|
} else {
|
||||||
|
limits[0][0] = ((Number) data.getFieldValue("xmin")).floatValue();
|
||||||
|
limits[0][1] = ((Number) data.getFieldValue("xmax")).floatValue();
|
||||||
|
limits[1][0] = ((Number) data.getFieldValue("ymin")).floatValue();
|
||||||
|
limits[1][1] = ((Number) data.getFieldValue("ymax")).floatValue();
|
||||||
|
limits[2][0] = ((Number) data.getFieldValue("zmin")).floatValue();
|
||||||
|
limits[2][1] = ((Number) data.getFieldValue("zmax")).floatValue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void affectAnimation(Animation animation, int targetIndex) {
|
public void bakeDynamic() {
|
||||||
BoneTrack track = (BoneTrack) this.getTrack(animation, targetIndex);
|
AnimData animData = blenderContext.getAnimData(this.owner.getOma());
|
||||||
if (track != null) {
|
if(animData != null) {
|
||||||
int flag = ((Number) data.getFieldValue("flag")).intValue();
|
Object owner = this.owner.getObject();
|
||||||
|
for(Animation animation : animData.anims) {
|
||||||
|
BlenderTrack track = this.getTrack(owner, animData.skeleton, animation);
|
||||||
Vector3f[] scales = track.getScales();
|
Vector3f[] scales = track.getScales();
|
||||||
int maxFrames = scales.length;
|
int maxFrames = scales.length;
|
||||||
for (int frame = 0; frame < maxFrames; ++frame) {
|
for (int frame = 0; frame < maxFrames; ++frame) {
|
||||||
float influence = ipo.calculateValue(frame);
|
this.sizeLimit(scales[frame], ipo.calculateValue(frame));
|
||||||
if ((flag & LIMIT_XMIN) != 0) {
|
|
||||||
float xmin = ((Number) data.getFieldValue("xmin")).floatValue();
|
|
||||||
if (scales[frame].x < xmin) {
|
|
||||||
scales[frame].x -= (scales[frame].x - xmin) * influence;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((flag & LIMIT_XMAX) != 0) {
|
|
||||||
float xmax = ((Number) data.getFieldValue("xmax")).floatValue();
|
|
||||||
if (scales[frame].x > xmax) {
|
|
||||||
scales[frame].x -= (scales[frame].x - xmax) * influence;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((flag & LIMIT_YMIN) != 0) {
|
|
||||||
float ymin = ((Number) data.getFieldValue("ymin")).floatValue();
|
|
||||||
if (scales[frame].y < ymin) {
|
|
||||||
scales[frame].y -= (scales[frame].y - ymin) * influence;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((flag & LIMIT_YMAX) != 0) {
|
|
||||||
float ymax = ((Number) data.getFieldValue("ymax")).floatValue();
|
|
||||||
if (scales[frame].y > ymax) {
|
|
||||||
scales[frame].y -= (scales[frame].y - ymax) * influence;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((flag & LIMIT_ZMIN) != 0) {
|
|
||||||
float zmin = ((Number) data.getFieldValue("zmin")).floatValue();
|
|
||||||
if (scales[frame].z < zmin) {
|
|
||||||
scales[frame].z -= (scales[frame].z - zmin) * influence;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((flag & LIMIT_ZMAX) != 0) {
|
|
||||||
float zmax = ((Number) data.getFieldValue("zmax")).floatValue();
|
|
||||||
if (scales[frame].z > zmax) {
|
|
||||||
scales[frame].z -= (scales[frame].z - zmax) * influence;
|
|
||||||
}
|
|
||||||
}//TODO: consider constraint space !!!
|
|
||||||
}
|
}
|
||||||
track.setKeyframes(track.getTimes(), track.getTranslations(), track.getRotations(), scales);
|
track.setKeyframes(track.getTimes(), track.getTranslations(), track.getRotations(), scales);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConstraintType getType() {
|
public void bakeStatic() {
|
||||||
return ConstraintType.CONSTRAINT_TYPE_SIZELIMIT;
|
Transform ownerTransform = this.owner.getTransform();
|
||||||
|
this.sizeLimit(ownerTransform.getScale(), ipo.calculateValue(0));
|
||||||
|
this.owner.applyTransform(ownerTransform);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sizeLimit(Vector3f scale, float influence) {
|
||||||
|
if ((flag & LIMIT_XMIN) != 0) {
|
||||||
|
if (scale.x < limits[0][0]) {
|
||||||
|
scale.x -= (scale.x - limits[0][0]) * influence;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((flag & LIMIT_XMAX) != 0) {
|
||||||
|
if (scale.x > limits[0][1]) {
|
||||||
|
scale.x -= (scale.x - limits[0][1]) * influence;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((flag & LIMIT_YMIN) != 0) {
|
||||||
|
if (scale.y < limits[1][0]) {
|
||||||
|
scale.y -= (scale.y - limits[1][0]) * influence;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((flag & LIMIT_YMAX) != 0) {
|
||||||
|
if (scale.y > limits[1][1]) {
|
||||||
|
scale.y -= (scale.y - limits[1][1]) * influence;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((flag & LIMIT_ZMIN) != 0) {
|
||||||
|
if (scale.z < limits[2][0]) {
|
||||||
|
scale.z -= (scale.z - limits[2][0]) * influence;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((flag & LIMIT_ZMAX) != 0) {
|
||||||
|
if (scale.z > limits[2][1]) {
|
||||||
|
scale.z -= (scale.z - limits[2][1]) * influence;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,50 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import com.jme3.scene.plugins.blender.BlenderContext;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The spline inverse kinematic constraint. Available for blender 2.50+.
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
/*package*/ class ConstraintSplineInverseKinematic extends Constraint {
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(ConstraintSplineInverseKinematic.class.getName());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor creates the constraint instance.
|
||||||
|
*
|
||||||
|
* @param constraintStructure
|
||||||
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
|
* @param ownerOMA
|
||||||
|
* the old memory address of the constraint owner
|
||||||
|
* @param influenceIpo
|
||||||
|
* the ipo curve of the influence factor
|
||||||
|
* @param blenderContext
|
||||||
|
* the blender context
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
public ConstraintSplineInverseKinematic(Structure constraintStructure, Long ownerOMA, Ipo influenceIpo,
|
||||||
|
BlenderContext blenderContext) throws BlenderFileException {
|
||||||
|
super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
|
||||||
|
// TODO Auto-generated constructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bakeDynamic() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
LOGGER.log(Level.WARNING, "'Splie IK' constraint NOT implemented!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bakeStatic() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
LOGGER.log(Level.WARNING, "'Spline IK' constraint NOT implemented!");
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,5 @@
|
|||||||
package com.jme3.scene.plugins.blender.constraints;
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
import com.jme3.animation.Animation;
|
|
||||||
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;
|
||||||
@ -19,8 +18,8 @@ import java.util.logging.Logger;
|
|||||||
* This constructor creates the constraint instance.
|
* This constructor creates the constraint instance.
|
||||||
*
|
*
|
||||||
* @param constraintStructure
|
* @param constraintStructure
|
||||||
* the constraint's structure (bConstraint clss in blender 2.49).
|
* the constraint's structure
|
||||||
* @param boneOMA
|
* @param ownerOMA
|
||||||
* the old memory address of the constraint owner
|
* the old memory address of the constraint owner
|
||||||
* @param influenceIpo
|
* @param influenceIpo
|
||||||
* the ipo curve of the influence factor
|
* the ipo curve of the influence factor
|
||||||
@ -30,20 +29,20 @@ import java.util.logging.Logger;
|
|||||||
* this exception is thrown when the blender file is somehow
|
* this exception is thrown when the blender file is somehow
|
||||||
* corrupted
|
* corrupted
|
||||||
*/
|
*/
|
||||||
public ConstraintStretchTo(Structure constraintStructure, Long boneOMA,
|
public ConstraintStretchTo(Structure constraintStructure, Long ownerOMA,
|
||||||
Ipo influenceIpo, BlenderContext blenderContext)
|
Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
throws BlenderFileException {
|
super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
|
||||||
super(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void affectAnimation(Animation animation, int targetIndex) {
|
public void bakeDynamic() {
|
||||||
// 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!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConstraintType getType() {
|
public void bakeStatic() {
|
||||||
return ConstraintType.CONSTRAINT_TYPE_STRETCHTO;
|
// TODO: implement 'Stretch to' constraint
|
||||||
|
LOGGER.log(Level.WARNING, "'Stretch to' constraint NOT implemented!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package com.jme3.scene.plugins.blender.constraints;
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
import com.jme3.animation.Animation;
|
|
||||||
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;
|
||||||
@ -19,8 +18,8 @@ import java.util.logging.Logger;
|
|||||||
* This constructor creates the constraint instance.
|
* This constructor creates the constraint instance.
|
||||||
*
|
*
|
||||||
* @param constraintStructure
|
* @param constraintStructure
|
||||||
* the constraint's structure (bConstraint clss in blender 2.49).
|
* the constraint's structure
|
||||||
* @param boneOMA
|
* @param ownerOMA
|
||||||
* the old memory address of the constraint owner
|
* the old memory address of the constraint owner
|
||||||
* @param influenceIpo
|
* @param influenceIpo
|
||||||
* the ipo curve of the influence factor
|
* the ipo curve of the influence factor
|
||||||
@ -30,19 +29,20 @@ import java.util.logging.Logger;
|
|||||||
* this exception is thrown when the blender file is somehow
|
* this exception is thrown when the blender file is somehow
|
||||||
* corrupted
|
* corrupted
|
||||||
*/
|
*/
|
||||||
public ConstraintTransform(Structure constraintStructure, Long boneOMA,
|
public ConstraintTransform(Structure constraintStructure, Long ownerOMA,
|
||||||
Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
super(constraintStructure, boneOMA, influenceIpo, blenderContext);
|
super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void affectAnimation(Animation animation, int targetIndex) {
|
public void bakeDynamic() {
|
||||||
// TODO: implement 'Transform' constraint
|
// TODO: implement 'Transform' constraint
|
||||||
LOGGER.log(Level.WARNING, "'Transform' constraint NOT implemented!");
|
LOGGER.log(Level.WARNING, "'Transform' constraint NOT implemented!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConstraintType getType() {
|
public void bakeStatic() {
|
||||||
return ConstraintType.CONSTRAINT_TYPE_TRANSFORM;
|
// TODO: implement 'Transform' constraint
|
||||||
|
LOGGER.log(Level.WARNING, "'Transform' constraint NOT implemented!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,145 +0,0 @@
|
|||||||
package com.jme3.scene.plugins.blender.constraints;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constraint types. Definitions taken from blender sources, file: DNA_constraint_types.h. Constraint id's the same as
|
|
||||||
* used in blender. The constraints might have duplicated type ids, depending on the blender version. The purpose of
|
|
||||||
* this enum is to combine class name and the constraint type (id).
|
|
||||||
* @author Marcin Roguski
|
|
||||||
*/
|
|
||||||
public enum ConstraintType {
|
|
||||||
/* Invalid/legacy constraint */
|
|
||||||
|
|
||||||
CONSTRAINT_TYPE_NULL(0, "bNullConstraint"),
|
|
||||||
/* Unimplemented non longer :) - during constraints recode, Aligorith */
|
|
||||||
CONSTRAINT_TYPE_CHILDOF(1, "bChildOfConstraint"),
|
|
||||||
CONSTRAINT_TYPE_KINEMATIC(3, "bKinematicConstraint"),
|
|
||||||
CONSTRAINT_TYPE_FOLLOWPATH(4, "bFollowPathConstraint"),
|
|
||||||
/* Unimplemented no longer :) - Aligorith */
|
|
||||||
CONSTRAINT_TYPE_ROTLIMIT(5, "bRotLimitConstraint"),
|
|
||||||
/* Unimplemented no longer :) - Aligorith */
|
|
||||||
CONSTRAINT_TYPE_LOCLIMIT(6, "bLocLimitConstraint"),
|
|
||||||
/* Unimplemented no longer :) - Aligorith */
|
|
||||||
CONSTRAINT_TYPE_SIZELIMIT(7, "bSizeLimitConstraint"),
|
|
||||||
CONSTRAINT_TYPE_ROTLIKE(8, "bRotateLikeConstraint"),
|
|
||||||
CONSTRAINT_TYPE_LOCLIKE(9, "bLocateLikeConstraint"),
|
|
||||||
CONSTRAINT_TYPE_SIZELIKE(10, "bSizeLikeConstraint"),
|
|
||||||
/* Unimplemented no longer :) - Aligorith. Scripts */
|
|
||||||
CONSTRAINT_TYPE_PYTHON(11, "bPythonConstraint"),
|
|
||||||
CONSTRAINT_TYPE_ACTION(12, "bActionConstraint"),
|
|
||||||
/* New Tracking constraint that locks an axis in place - theeth */
|
|
||||||
CONSTRAINT_TYPE_LOCKTRACK(13, "bLockTrackConstraint"),
|
|
||||||
/* limit distance */
|
|
||||||
CONSTRAINT_TYPE_DISTLIMIT(14, "bDistLimitConstraint"),
|
|
||||||
/* claiming this to be mine :) is in tuhopuu bjornmose */
|
|
||||||
CONSTRAINT_TYPE_STRETCHTO(15, "bStretchToConstraint"),
|
|
||||||
/* floor constraint */
|
|
||||||
CONSTRAINT_TYPE_MINMAX(16, "bMinMaxConstraint"),
|
|
||||||
/* rigidbody constraint */
|
|
||||||
CONSTRAINT_TYPE_RIGIDBODYJOINT(17, "bRigidBodyConstraint"),
|
|
||||||
/* clampto constraint */
|
|
||||||
CONSTRAINT_TYPE_CLAMPTO(18, "bClampToConstraint"),
|
|
||||||
/* transformation (loc/rot/size -> loc/rot/size) constraint */
|
|
||||||
CONSTRAINT_TYPE_TRANSFORM(19, "bTransformConstraint"),
|
|
||||||
/* shrinkwrap (loc/rot) constraint */
|
|
||||||
CONSTRAINT_TYPE_SHRINKWRAP(20, "bShrinkwrapConstraint");
|
|
||||||
/** The constraint's id (in blender known as 'type'). */
|
|
||||||
private int constraintId;
|
|
||||||
/** The name of constraint class used by blender. */
|
|
||||||
private String className;
|
|
||||||
/** The map containing class names and types of constraints. */
|
|
||||||
private static final Map<String, ConstraintType> typesMap = new HashMap<String, ConstraintType>(ConstraintType.values().length);
|
|
||||||
/** The map containing class names and types of constraints. */
|
|
||||||
private static final Map<Integer, ConstraintType> idsMap = new HashMap<Integer, ConstraintType>(ConstraintType.values().length);
|
|
||||||
|
|
||||||
static {
|
|
||||||
idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_NULL.constraintId), CONSTRAINT_TYPE_NULL);
|
|
||||||
idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_CHILDOF.constraintId), CONSTRAINT_TYPE_CHILDOF);
|
|
||||||
idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_KINEMATIC.constraintId), CONSTRAINT_TYPE_KINEMATIC);
|
|
||||||
idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_FOLLOWPATH.constraintId), CONSTRAINT_TYPE_FOLLOWPATH);
|
|
||||||
idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_ROTLIMIT.constraintId), CONSTRAINT_TYPE_ROTLIMIT);
|
|
||||||
idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_LOCLIMIT.constraintId), CONSTRAINT_TYPE_LOCLIMIT);
|
|
||||||
idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_SIZELIMIT.constraintId), CONSTRAINT_TYPE_SIZELIMIT);
|
|
||||||
idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_ROTLIKE.constraintId), CONSTRAINT_TYPE_ROTLIKE);
|
|
||||||
idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_LOCLIKE.constraintId), CONSTRAINT_TYPE_LOCLIKE);
|
|
||||||
idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_SIZELIKE.constraintId), CONSTRAINT_TYPE_SIZELIKE);
|
|
||||||
idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_PYTHON.constraintId), CONSTRAINT_TYPE_PYTHON);
|
|
||||||
idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_ACTION.constraintId), CONSTRAINT_TYPE_ACTION);
|
|
||||||
idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_LOCKTRACK.constraintId), CONSTRAINT_TYPE_LOCKTRACK);
|
|
||||||
idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_DISTLIMIT.constraintId), CONSTRAINT_TYPE_DISTLIMIT);
|
|
||||||
idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_STRETCHTO.constraintId), CONSTRAINT_TYPE_STRETCHTO);
|
|
||||||
idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_MINMAX.constraintId), CONSTRAINT_TYPE_MINMAX);
|
|
||||||
idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_RIGIDBODYJOINT.constraintId), CONSTRAINT_TYPE_RIGIDBODYJOINT);
|
|
||||||
idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_CLAMPTO.constraintId), CONSTRAINT_TYPE_CLAMPTO);
|
|
||||||
idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_TRANSFORM.constraintId), CONSTRAINT_TYPE_TRANSFORM);
|
|
||||||
idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_SHRINKWRAP.constraintId), CONSTRAINT_TYPE_SHRINKWRAP);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor. Stores constraint type and class name.
|
|
||||||
* @param constraintId
|
|
||||||
* the constraint's type
|
|
||||||
* @param className
|
|
||||||
* the constraint's type name
|
|
||||||
*/
|
|
||||||
private ConstraintType(int constraintId, String className) {
|
|
||||||
this.constraintId = constraintId;
|
|
||||||
this.className = className;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns the type by given constraint id.
|
|
||||||
* @param constraintId
|
|
||||||
* the id of the constraint
|
|
||||||
* @return the constraint type enum value
|
|
||||||
*/
|
|
||||||
public static ConstraintType valueOf(int constraintId) {
|
|
||||||
return idsMap.get(Integer.valueOf(constraintId));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns the constraint's id (type).
|
|
||||||
* @return the constraint's id (type)
|
|
||||||
*/
|
|
||||||
public int getConstraintId() {
|
|
||||||
return constraintId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns the constraint's class name.
|
|
||||||
* @return the constraint's class name
|
|
||||||
*/
|
|
||||||
public String getClassName() {
|
|
||||||
return className;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns constraint enum type by the given class name.
|
|
||||||
* @param className
|
|
||||||
* the blender's constraint class name
|
|
||||||
* @return the constraint enum type of the specified class name
|
|
||||||
*/
|
|
||||||
public static ConstraintType getByBlenderClassName(String className) {
|
|
||||||
ConstraintType result = typesMap.get(className);
|
|
||||||
if (result == null) {
|
|
||||||
ConstraintType[] constraints = ConstraintType.values();
|
|
||||||
for (ConstraintType constraint : constraints) {
|
|
||||||
if (constraint.className.equals(className)) {
|
|
||||||
return constraint;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns the type value of the last defined constraint. It can be used for allocating tables for
|
|
||||||
* storing constraint procedures since not all type values from 0 to the last value are used.
|
|
||||||
* @return the type value of the last defined constraint
|
|
||||||
*/
|
|
||||||
public static int getLastDefinedTypeValue() {
|
|
||||||
return CONSTRAINT_TYPE_SHRINKWRAP.getConstraintId();
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,274 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
|
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.Spatial;
|
||||||
|
import com.jme3.scene.plugins.blender.BlenderContext;
|
||||||
|
import com.jme3.scene.plugins.blender.BlenderContext.LoadedFeatureDataType;
|
||||||
|
import com.jme3.scene.plugins.blender.constraints.Constraint.Space;
|
||||||
|
import com.jme3.scene.plugins.blender.file.DynamicArray;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents either owner or target of the constraint. It has the
|
||||||
|
* common methods that take the evalueation space of the feature.
|
||||||
|
*
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
/* package */class Feature {
|
||||||
|
/** The evalueation space. */
|
||||||
|
protected Space space;
|
||||||
|
/** Old memory address of the feature. */
|
||||||
|
protected Long oma;
|
||||||
|
/** The spatial that is hold by the Feature. */
|
||||||
|
protected Spatial spatial;
|
||||||
|
/** The bone that is hold by the Feature. */
|
||||||
|
protected Bone bone;
|
||||||
|
/** The blender context. */
|
||||||
|
protected BlenderContext blenderContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs the feature based on spatial.
|
||||||
|
*
|
||||||
|
* @param spatial
|
||||||
|
* the spatial
|
||||||
|
* @param space
|
||||||
|
* the spatial's evaluation space
|
||||||
|
* @param oma
|
||||||
|
* the spatial's old memory address
|
||||||
|
* @param blenderContext
|
||||||
|
* the blender context
|
||||||
|
*/
|
||||||
|
public Feature(Spatial spatial, Space space, Long oma, BlenderContext blenderContext) {
|
||||||
|
this.space = space;
|
||||||
|
this.oma = oma;
|
||||||
|
this.spatial = spatial;
|
||||||
|
this.blenderContext = blenderContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs the feature based on bone.
|
||||||
|
*
|
||||||
|
* @param bone
|
||||||
|
* the bone
|
||||||
|
* @param space
|
||||||
|
* the bone evaluation space
|
||||||
|
* @param oma
|
||||||
|
* the bone old memory address
|
||||||
|
* @param blenderContext
|
||||||
|
* the blender context
|
||||||
|
*/
|
||||||
|
public Feature(Bone bone, Space space, Long oma, BlenderContext blenderContext) {
|
||||||
|
this.space = space;
|
||||||
|
this.oma = oma;
|
||||||
|
this.blenderContext = blenderContext;
|
||||||
|
this.bone = bone;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the feature's old memory address
|
||||||
|
*/
|
||||||
|
public Long getOma() {
|
||||||
|
return oma;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the object held by the feature (either bone or spatial)
|
||||||
|
*/
|
||||||
|
public Object getObject() {
|
||||||
|
if (spatial != null) {
|
||||||
|
return spatial;
|
||||||
|
}
|
||||||
|
return bone;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the feature's transform depending on the evaluation space
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public Transform getTransform() {
|
||||||
|
if (spatial != null) {
|
||||||
|
switch (space) {
|
||||||
|
case CONSTRAINT_SPACE_LOCAL:
|
||||||
|
Structure targetStructure = (Structure) blenderContext.getLoadedFeature(oma, LoadedFeatureDataType.LOADED_STRUCTURE);
|
||||||
|
|
||||||
|
DynamicArray<Number> locArray = ((DynamicArray<Number>) targetStructure.getFieldValue("loc"));
|
||||||
|
Vector3f loc = new Vector3f(locArray.get(0).floatValue(), locArray.get(1).floatValue(), locArray.get(2).floatValue());
|
||||||
|
DynamicArray<Number> rotArray = ((DynamicArray<Number>) targetStructure.getFieldValue("rot"));
|
||||||
|
Quaternion rot = new Quaternion(new float[] { rotArray.get(0).floatValue(), rotArray.get(1).floatValue(), rotArray.get(2).floatValue() });
|
||||||
|
DynamicArray<Number> sizeArray = ((DynamicArray<Number>) targetStructure.getFieldValue("size"));
|
||||||
|
Vector3f size = new Vector3f(sizeArray.get(0).floatValue(), sizeArray.get(1).floatValue(), sizeArray.get(2).floatValue());
|
||||||
|
|
||||||
|
if (blenderContext.getBlenderKey().isFixUpAxis()) {
|
||||||
|
float y = loc.y;
|
||||||
|
loc.y = loc.z;
|
||||||
|
loc.z = -y;
|
||||||
|
|
||||||
|
y = rot.getY();
|
||||||
|
float z = rot.getZ();
|
||||||
|
rot.set(rot.getX(), z, -y, rot.getW());
|
||||||
|
|
||||||
|
y = size.y;
|
||||||
|
size.y = size.z;
|
||||||
|
size.z = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
Transform result = new Transform(loc, rot);
|
||||||
|
result.setScale(size);
|
||||||
|
return result;
|
||||||
|
case CONSTRAINT_SPACE_WORLD:
|
||||||
|
return spatial.getWorldTransform();
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Invalid space type for target object: " + space.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Bone
|
||||||
|
switch (space) {
|
||||||
|
case CONSTRAINT_SPACE_LOCAL:
|
||||||
|
Transform localTransform = new Transform(bone.getLocalPosition(), bone.getLocalRotation());
|
||||||
|
localTransform.setScale(bone.getLocalScale());
|
||||||
|
return localTransform;
|
||||||
|
case CONSTRAINT_SPACE_WORLD:
|
||||||
|
if(bone.getParent()!=null) {
|
||||||
|
System.out.println(bone.getParent().getLocalRotation());
|
||||||
|
System.out.println(bone.getParent().getWorldBindRotation());
|
||||||
|
System.out.println(bone.getParent().getModelSpaceRotation());
|
||||||
|
System.out.println(bone.getParent().getWorldBindInverseRotation());
|
||||||
|
}
|
||||||
|
|
||||||
|
Transform worldTransform = new Transform(bone.getWorldBindPosition(), bone.getWorldBindRotation());
|
||||||
|
worldTransform.setScale(bone.getWorldBindScale());
|
||||||
|
return worldTransform;
|
||||||
|
case CONSTRAINT_SPACE_POSE:
|
||||||
|
// TODO
|
||||||
|
return null;
|
||||||
|
case CONSTRAINT_SPACE_PARLOCAL:
|
||||||
|
Transform parentLocalTransform = new Transform(bone.getLocalPosition(), bone.getLocalRotation());
|
||||||
|
parentLocalTransform.setScale(bone.getLocalScale());
|
||||||
|
return parentLocalTransform;
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Invalid space type for target object: " + space.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method applies the given transform to the feature in the proper
|
||||||
|
* evaluation space.
|
||||||
|
*
|
||||||
|
* @param transform
|
||||||
|
* the transform to be applied
|
||||||
|
*/
|
||||||
|
public void applyTransform(Transform transform) {
|
||||||
|
if (spatial != null) {
|
||||||
|
switch (space) {
|
||||||
|
case CONSTRAINT_SPACE_LOCAL:
|
||||||
|
Transform ownerLocalTransform = spatial.getLocalTransform();
|
||||||
|
ownerLocalTransform.getTranslation().addLocal(transform.getTranslation());
|
||||||
|
ownerLocalTransform.getRotation().multLocal(transform.getRotation());
|
||||||
|
ownerLocalTransform.getScale().multLocal(transform.getScale());
|
||||||
|
break;
|
||||||
|
case CONSTRAINT_SPACE_WORLD:
|
||||||
|
Matrix4f m = this.getParentWorldTransformMatrix();
|
||||||
|
m.invertLocal();
|
||||||
|
Matrix4f matrix = this.toMatrix(transform);
|
||||||
|
m.multLocal(matrix);
|
||||||
|
|
||||||
|
float scaleX = (float) Math.sqrt(m.m00 * m.m00 + m.m10 * m.m10 + m.m20 * m.m20);
|
||||||
|
float scaleY = (float) Math.sqrt(m.m01 * m.m01 + m.m11 * m.m11 + m.m21 * m.m21);
|
||||||
|
float scaleZ = (float) Math.sqrt(m.m02 * m.m02 + m.m12 * m.m12 + m.m22 * m.m22);
|
||||||
|
|
||||||
|
transform.setTranslation(m.toTranslationVector());
|
||||||
|
transform.setRotation(m.toRotationQuat());
|
||||||
|
transform.setScale(scaleX, scaleY, scaleZ);
|
||||||
|
spatial.setLocalTransform(transform);
|
||||||
|
break;
|
||||||
|
case CONSTRAINT_SPACE_PARLOCAL:
|
||||||
|
case CONSTRAINT_SPACE_POSE:
|
||||||
|
throw new IllegalStateException("Invalid space type (" + space.toString() + ") for owner object.");
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Invalid space type for target object: " + space.toString());
|
||||||
|
}
|
||||||
|
} else {// Bone
|
||||||
|
switch (space) {
|
||||||
|
case CONSTRAINT_SPACE_LOCAL:
|
||||||
|
bone.setBindTransforms(transform.getTranslation(), transform.getRotation(), transform.getScale());
|
||||||
|
break;
|
||||||
|
case CONSTRAINT_SPACE_WORLD:
|
||||||
|
Matrix4f m = this.getParentWorldTransformMatrix();
|
||||||
|
m.invertLocal();
|
||||||
|
transform.setTranslation(m.mult(transform.getTranslation()));
|
||||||
|
transform.setRotation(m.mult(transform.getRotation(), null));
|
||||||
|
transform.setScale(transform.getScale());
|
||||||
|
bone.setBindTransforms(transform.getTranslation(), transform.getRotation(), transform.getScale());
|
||||||
|
break;
|
||||||
|
case CONSTRAINT_SPACE_PARLOCAL:
|
||||||
|
Vector3f parentLocalTranslation = bone.getLocalPosition().add(transform.getTranslation());
|
||||||
|
Quaternion parentLocalRotation = bone.getLocalRotation().mult(transform.getRotation());
|
||||||
|
bone.setBindTransforms(parentLocalTranslation, parentLocalRotation, transform.getScale());
|
||||||
|
break;
|
||||||
|
case CONSTRAINT_SPACE_POSE:
|
||||||
|
// TODO:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Invalid space type for target object: " + space.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return world transform matrix of the feature
|
||||||
|
*/
|
||||||
|
public Matrix4f getWorldTransformMatrix() {
|
||||||
|
if (spatial != null) {
|
||||||
|
Matrix4f result = new Matrix4f();
|
||||||
|
Transform t = spatial.getWorldTransform();
|
||||||
|
result.setTransform(t.getTranslation(), t.getScale(), t.getRotation().toRotationMatrix());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
// Bone
|
||||||
|
Matrix4f result = new Matrix4f();
|
||||||
|
result.setTransform(bone.getWorldBindPosition(), bone.getWorldBindScale(), bone.getWorldBindRotation().toRotationMatrix());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return world transform matrix of the feature's parent or identity matrix
|
||||||
|
* if the feature has no parent
|
||||||
|
*/
|
||||||
|
public Matrix4f getParentWorldTransformMatrix() {
|
||||||
|
Matrix4f result = new Matrix4f();
|
||||||
|
if (spatial != null) {
|
||||||
|
if (spatial.getParent() != null) {
|
||||||
|
Transform t = spatial.getParent().getWorldTransform();
|
||||||
|
result.setTransform(t.getTranslation(), t.getScale(), t.getRotation().toRotationMatrix());
|
||||||
|
}
|
||||||
|
} else {// Bone
|
||||||
|
Bone parent = bone.getParent();
|
||||||
|
if (parent != null) {
|
||||||
|
result.setTransform(parent.getWorldBindPosition(), parent.getWorldBindScale(), parent.getWorldBindRotation().toRotationMatrix());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts given transform to the matrix.
|
||||||
|
*
|
||||||
|
* @param transform
|
||||||
|
* the transform to be converted
|
||||||
|
* @return 4x4 matri that represents the given transform
|
||||||
|
*/
|
||||||
|
protected Matrix4f toMatrix(Transform transform) {
|
||||||
|
Matrix4f result = Matrix4f.IDENTITY;
|
||||||
|
if (transform != null) {
|
||||||
|
result = new Matrix4f();
|
||||||
|
result.setTranslation(transform.getTranslation());
|
||||||
|
result.setRotationQuaternion(transform.getRotation());
|
||||||
|
result.setScale(transform.getScale());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -43,9 +43,11 @@ public class CurvesHelper extends AbstractBlenderHelper {
|
|||||||
* different blender versions.
|
* different blender versions.
|
||||||
* @param blenderVersion
|
* @param blenderVersion
|
||||||
* the version read from the blend file
|
* the version read from the blend file
|
||||||
|
* @param fixUpAxis
|
||||||
|
* a variable that indicates if the Y asxis is the UP axis or not
|
||||||
*/
|
*/
|
||||||
public CurvesHelper(String blenderVersion) {
|
public CurvesHelper(String blenderVersion, boolean fixUpAxis) {
|
||||||
super(blenderVersion);
|
super(blenderVersion, fixUpAxis);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -457,7 +459,7 @@ public class CurvesHelper extends AbstractBlenderHelper {
|
|||||||
temp[1] = vertices[j * 3 + 1] * taperScale;
|
temp[1] = vertices[j * 3 + 1] * taperScale;
|
||||||
temp[2] = 0;
|
temp[2] = 0;
|
||||||
m.mult(temp);//the result is stored in the array
|
m.mult(temp);//the result is stored in the array
|
||||||
if (fixUpAxis) {
|
if (fixUpAxis) {//TODO: not the other way ???
|
||||||
verts[j] = new Vector3f(temp[0], temp[1], temp[2]);
|
verts[j] = new Vector3f(temp[0], temp[1], temp[2]);
|
||||||
} else {
|
} else {
|
||||||
verts[j] = new Vector3f(temp[0], temp[2], -temp[1]);
|
verts[j] = new Vector3f(temp[0], temp[2], -temp[1]);
|
||||||
|
@ -59,9 +59,11 @@ public class LightHelper extends AbstractBlenderHelper {
|
|||||||
* different blender versions.
|
* different blender versions.
|
||||||
* @param blenderVersion
|
* @param blenderVersion
|
||||||
* the version read from the blend file
|
* the version read from the blend file
|
||||||
|
* @param fixUpAxis
|
||||||
|
* a variable that indicates if the Y asxis is the UP axis or not
|
||||||
*/
|
*/
|
||||||
public LightHelper(String blenderVersion) {
|
public LightHelper(String blenderVersion, boolean fixUpAxis) {
|
||||||
super(blenderVersion);
|
super(blenderVersion, fixUpAxis);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Light toLight(Structure structure, BlenderContext blenderContext) throws BlenderFileException {
|
public Light toLight(Structure structure, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
|
@ -45,7 +45,6 @@ import com.jme3.scene.plugins.blender.BlenderContext.LoadedFeatureDataType;
|
|||||||
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
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.textures.TextureHelper;
|
|
||||||
import com.jme3.shader.VarType;
|
import com.jme3.shader.VarType;
|
||||||
import com.jme3.texture.Image;
|
import com.jme3.texture.Image;
|
||||||
import com.jme3.texture.Image.Format;
|
import com.jme3.texture.Image.Format;
|
||||||
@ -101,9 +100,11 @@ public class MaterialHelper extends AbstractBlenderHelper {
|
|||||||
*
|
*
|
||||||
* @param blenderVersion
|
* @param blenderVersion
|
||||||
* the version read from the blend file
|
* the version read from the blend file
|
||||||
|
* @param fixUpAxis
|
||||||
|
* a variable that indicates if the Y asxis is the UP axis or not
|
||||||
*/
|
*/
|
||||||
public MaterialHelper(String blenderVersion) {
|
public MaterialHelper(String blenderVersion, boolean fixUpAxis) {
|
||||||
super(blenderVersion);
|
super(blenderVersion, false);
|
||||||
// setting alpha masks
|
// setting alpha masks
|
||||||
alphaMasks.put(ALPHA_MASK_NONE, new IAlphaMask() {
|
alphaMasks.put(ALPHA_MASK_NONE, new IAlphaMask() {
|
||||||
@Override
|
@Override
|
||||||
@ -204,7 +205,6 @@ public class MaterialHelper extends AbstractBlenderHelper {
|
|||||||
// texture
|
// texture
|
||||||
Type colorTextureType = null;
|
Type colorTextureType = null;
|
||||||
Map<String, Texture> texturesMap = new HashMap<String, Texture>();
|
Map<String, Texture> texturesMap = new HashMap<String, Texture>();
|
||||||
TextureHelper textureHelper = blenderContext.getHelper(TextureHelper.class);
|
|
||||||
for(Entry<Number, Texture> textureEntry : materialContext.loadedTextures.entrySet()) {
|
for(Entry<Number, Texture> textureEntry : materialContext.loadedTextures.entrySet()) {
|
||||||
int mapto = textureEntry.getKey().intValue();
|
int mapto = textureEntry.getKey().intValue();
|
||||||
Texture texture = textureEntry.getValue();
|
Texture texture = textureEntry.getValue();
|
||||||
|
@ -74,9 +74,11 @@ public class MeshHelper extends AbstractBlenderHelper {
|
|||||||
*
|
*
|
||||||
* @param blenderVersion
|
* @param blenderVersion
|
||||||
* the version read from the blend file
|
* the version read from the blend file
|
||||||
|
* @param fixUpAxis
|
||||||
|
* a variable that indicates if the Y asxis is the UP axis or not
|
||||||
*/
|
*/
|
||||||
public MeshHelper(String blenderVersion) {
|
public MeshHelper(String blenderVersion, boolean fixUpAxis) {
|
||||||
super(blenderVersion);
|
super(blenderVersion,fixUpAxis);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,6 +1,20 @@
|
|||||||
package com.jme3.scene.plugins.blender.modifiers;
|
package com.jme3.scene.plugins.blender.modifiers;
|
||||||
|
|
||||||
import com.jme3.animation.*;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import com.jme3.animation.AnimControl;
|
||||||
|
import com.jme3.animation.Animation;
|
||||||
|
import com.jme3.animation.Bone;
|
||||||
|
import com.jme3.animation.BoneTrack;
|
||||||
|
import com.jme3.animation.Skeleton;
|
||||||
|
import com.jme3.animation.SkeletonControl;
|
||||||
import com.jme3.math.Matrix4f;
|
import com.jme3.math.Matrix4f;
|
||||||
import com.jme3.scene.Geometry;
|
import com.jme3.scene.Geometry;
|
||||||
import com.jme3.scene.Mesh;
|
import com.jme3.scene.Mesh;
|
||||||
@ -12,8 +26,8 @@ import com.jme3.scene.VertexBuffer.Usage;
|
|||||||
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.ArmatureHelper;
|
import com.jme3.scene.plugins.blender.animations.ArmatureHelper;
|
||||||
import com.jme3.scene.plugins.blender.animations.ArmatureHelper.BoneTransformationData;
|
|
||||||
import com.jme3.scene.plugins.blender.constraints.Constraint;
|
import com.jme3.scene.plugins.blender.constraints.Constraint;
|
||||||
|
import com.jme3.scene.plugins.blender.constraints.ConstraintHelper;
|
||||||
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.FileBlockHeader;
|
||||||
import com.jme3.scene.plugins.blender.file.Pointer;
|
import com.jme3.scene.plugins.blender.file.Pointer;
|
||||||
@ -22,14 +36,6 @@ import com.jme3.scene.plugins.blender.meshes.MeshContext;
|
|||||||
import com.jme3.scene.plugins.blender.objects.ObjectHelper;
|
import com.jme3.scene.plugins.blender.objects.ObjectHelper;
|
||||||
import com.jme3.scene.plugins.ogre.AnimData;
|
import com.jme3.scene.plugins.ogre.AnimData;
|
||||||
import com.jme3.util.BufferUtils;
|
import com.jme3.util.BufferUtils;
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.FloatBuffer;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This modifier allows to add bone animation to the object.
|
* This modifier allows to add bone animation to the object.
|
||||||
@ -38,34 +44,30 @@ import java.util.logging.Logger;
|
|||||||
*/
|
*/
|
||||||
/* 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; // have no idea why 4, could someone please explain ?
|
private static final int MAXIMUM_WEIGHTS_PER_VERTEX = 4;
|
||||||
//@Marcin it was an Ogre limitation, but as long as we use a MaxNumWeight variable in mesh,
|
// @Marcin it was an Ogre limitation, but as long as we use a MaxNumWeight
|
||||||
//i guess this limitation has no sense for the blender loader...so i guess it's up to you. You'll have to deternine the max weight according to the provided blend file
|
// variable in mesh,
|
||||||
//I added a check to avoid crash when loading a model that has more than 4 weight per vertex on line 258
|
// i guess this limitation has no sense for the blender loader...so i guess
|
||||||
//If you decide to remove this limitation, remove this code.
|
// it's up to you. You'll have to deternine the max weight according to the
|
||||||
//Rémy
|
// provided blend file
|
||||||
|
// I added a check to avoid crash when loading a model that has more than 4
|
||||||
|
// weight per vertex on line 258
|
||||||
|
// If you decide to remove this limitation, remove this code.
|
||||||
|
// Rémy
|
||||||
|
|
||||||
/** Loaded animation data. */
|
/** Loaded animation data. */
|
||||||
private AnimData animData;
|
private AnimData animData;
|
||||||
/** Old memory address of the armature's object. */
|
|
||||||
private Long armatureObjectOMA;
|
|
||||||
/** 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 is only temporary. It will be removed when object
|
|
||||||
* animation is implemented in jme. TODO!!!!!!!
|
|
||||||
*/
|
|
||||||
/* package */ArmatureModifier() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor reads animation data from the object structore. The
|
* This constructor reads animation data from the object structore. The
|
||||||
* stored data is the AnimData and additional data is armature's OMA.
|
* stored data is the AnimData and additional data is armature's OMA.
|
||||||
@ -81,48 +83,58 @@ import java.util.logging.Logger;
|
|||||||
* corrupted
|
* corrupted
|
||||||
*/
|
*/
|
||||||
public ArmatureModifier(Structure objectStructure, Structure modifierStructure, BlenderContext blenderContext) throws BlenderFileException {
|
public ArmatureModifier(Structure objectStructure, Structure modifierStructure, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
if(this.validate(modifierStructure, blenderContext)) {
|
if (this.validate(modifierStructure, blenderContext)) {
|
||||||
Pointer pArmatureObject = (Pointer) modifierStructure.getFieldValue("object");
|
Pointer pArmatureObject = (Pointer) modifierStructure.getFieldValue("object");
|
||||||
if (pArmatureObject.isNotNull()) {
|
if (pArmatureObject.isNotNull()) {
|
||||||
ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
|
|
||||||
ArmatureHelper armatureHelper = blenderContext.getHelper(ArmatureHelper.class);
|
ArmatureHelper armatureHelper = blenderContext.getHelper(ArmatureHelper.class);
|
||||||
|
|
||||||
Structure armatureObject = pArmatureObject.fetchData(blenderContext.getInputStream()).get(0);
|
Structure armatureObject = pArmatureObject.fetchData(blenderContext.getInputStream()).get(0);
|
||||||
this.armatureObjectOMA = armatureObject.getOldMemoryAddress();
|
|
||||||
|
|
||||||
//read skeleton
|
// load skeleton
|
||||||
// changing bones matrices so that they fit the current object
|
Structure armatureStructure = ((Pointer) armatureObject.getFieldValue("data")).fetchData(blenderContext.getInputStream()).get(0);
|
||||||
Structure armatureStructure = ((Pointer)armatureObject.getFieldValue("data")).fetchData(blenderContext.getInputStream()).get(0);
|
|
||||||
Structure bonebase = (Structure) armatureStructure.getFieldValue("bonebase");
|
Structure pose = ((Pointer) armatureObject.getFieldValue("pose")).fetchData(blenderContext.getInputStream()).get(0);
|
||||||
List<Structure> bonesStructures = bonebase.evaluateListBase(blenderContext);
|
List<Structure> chanbase = ((Structure) pose.getFieldValue("chanbase")).evaluateListBase(blenderContext);
|
||||||
for (Structure boneStructure : bonesStructures) {
|
|
||||||
BoneTransformationData rootBoneTransformationData = armatureHelper.readBoneAndItsChildren(boneStructure, null, blenderContext);
|
Map<Long, Structure> bonesPoseChannels = new HashMap<Long, Structure>(chanbase.size());
|
||||||
armatureHelper.addBoneDataRoot(rootBoneTransformationData);
|
for (Structure poseChannel : chanbase) {
|
||||||
|
Pointer pBone = (Pointer) poseChannel.getFieldValue("bone");
|
||||||
|
bonesPoseChannels.put(pBone.getOldMemoryAddress(), poseChannel);
|
||||||
}
|
}
|
||||||
Matrix4f armatureObjectMatrix = objectHelper.getTransformationMatrix(armatureObject);
|
|
||||||
Matrix4f inverseMeshObjectMatrix = objectHelper.getTransformationMatrix(objectStructure).invert();
|
|
||||||
Matrix4f additionalRootBoneTransformation = inverseMeshObjectMatrix.multLocal(armatureObjectMatrix);
|
|
||||||
Bone[] bones = armatureHelper.buildBonesStructure(Long.valueOf(0L), additionalRootBoneTransformation);
|
|
||||||
|
|
||||||
//read mesh indexes
|
ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
|
||||||
Structure meshStructure = ((Pointer)objectStructure.getFieldValue("data")).fetchData(blenderContext.getInputStream()).get(0);
|
Matrix4f armatureObjectMatrix = objectHelper.getMatrix(armatureObject, "obmat", true);//TODO: fixupaxis ???
|
||||||
|
Matrix4f inverseMeshObjectMatrix = objectHelper.getMatrix(objectStructure, "obmat", true).invertLocal();
|
||||||
|
Matrix4f objectToArmatureTransformation = armatureObjectMatrix.multLocal(inverseMeshObjectMatrix);
|
||||||
|
|
||||||
|
List<Structure> bonebase = ((Structure) armatureStructure.getFieldValue("bonebase")).evaluateListBase(blenderContext);
|
||||||
|
List<Bone> bonesList = new ArrayList<Bone>();
|
||||||
|
for (int i = 0; i < bonebase.size(); ++i) {
|
||||||
|
armatureHelper.buildBones(bonebase.get(i), null, bonesList, objectToArmatureTransformation, bonesPoseChannels, blenderContext);
|
||||||
|
}
|
||||||
|
bonesList.add(0, new Bone(""));
|
||||||
|
Skeleton skeleton = new Skeleton(bonesList.toArray(new Bone[bonesList.size()]));
|
||||||
|
|
||||||
|
// read mesh indexes
|
||||||
|
Structure meshStructure = ((Pointer) objectStructure.getFieldValue("data")).fetchData(blenderContext.getInputStream()).get(0);
|
||||||
this.meshOMA = meshStructure.getOldMemoryAddress();
|
this.meshOMA = meshStructure.getOldMemoryAddress();
|
||||||
this.readVerticesWeightsData(objectStructure, meshStructure, blenderContext);
|
this.readVerticesWeightsData(objectStructure, meshStructure, skeleton, blenderContext);
|
||||||
|
|
||||||
//read animations
|
// read animations
|
||||||
ArrayList<Animation> animations = new ArrayList<Animation>();
|
ArrayList<Animation> animations = new ArrayList<Animation>();
|
||||||
List<FileBlockHeader> actionHeaders = blenderContext.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00));
|
List<FileBlockHeader> actionHeaders = blenderContext.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00));
|
||||||
if(actionHeaders != null) {//it may happen that the model has armature with no actions
|
if (actionHeaders != null) {// it may happen that the model has
|
||||||
|
// armature with no actions
|
||||||
for (FileBlockHeader header : actionHeaders) {
|
for (FileBlockHeader header : actionHeaders) {
|
||||||
Structure actionStructure = header.getStructure(blenderContext);
|
Structure actionStructure = header.getStructure(blenderContext);
|
||||||
String actionName = actionStructure.getName();
|
String actionName = actionStructure.getName();
|
||||||
|
|
||||||
BoneTrack[] tracks = armatureHelper.getTracks(actionStructure, blenderContext);
|
BoneTrack[] tracks = armatureHelper.getTracks(actionStructure, skeleton, blenderContext);
|
||||||
//determining the animation time
|
// determining the animation time
|
||||||
float maximumTrackLength = 0;
|
float maximumTrackLength = 0;
|
||||||
for(BoneTrack track : tracks) {
|
for (BoneTrack track : tracks) {
|
||||||
float length = track.getLength();
|
float length = track.getLength();
|
||||||
if(length > maximumTrackLength) {
|
if (length > maximumTrackLength) {
|
||||||
maximumTrackLength = length;
|
maximumTrackLength = length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -132,7 +144,16 @@ import java.util.logging.Logger;
|
|||||||
animations.add(boneAnimation);
|
animations.add(boneAnimation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
animData = new AnimData(new Skeleton(bones), animations);
|
animData = new AnimData(skeleton, animations);
|
||||||
|
|
||||||
|
// store the animation data for each bone
|
||||||
|
for (Structure boneStructure : bonebase) {
|
||||||
|
blenderContext.setAnimData(boneStructure.getOldMemoryAddress(), animData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// loading constraints connected with this object
|
||||||
|
ConstraintHelper constraintHelper = blenderContext.getHelper(ConstraintHelper.class);
|
||||||
|
constraintHelper.loadConstraints(armatureObject, blenderContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -140,16 +161,16 @@ import java.util.logging.Logger;
|
|||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
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) {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
// setting weights for bones
|
// setting weights for bones
|
||||||
List<Geometry> geomList = (List<Geometry>) blenderContext.getLoadedFeature(this.meshOMA, LoadedFeatureDataType.LOADED_FEATURE);
|
List<Geometry> geomList = (List<Geometry>) blenderContext.getLoadedFeature(this.meshOMA, LoadedFeatureDataType.LOADED_FEATURE);
|
||||||
for(Geometry geom : geomList) {
|
for (Geometry geom : geomList) {
|
||||||
Mesh mesh = geom.getMesh();
|
Mesh mesh = geom.getMesh();
|
||||||
if (this.verticesWeights != null) {
|
if (this.verticesWeights != null) {
|
||||||
mesh.setMaxNumWeights(this.boneGroups);
|
mesh.setMaxNumWeights(this.boneGroups);
|
||||||
@ -158,84 +179,108 @@ import java.util.logging.Logger;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayList<Animation> animList = animData.anims;
|
// applying bone transforms before constraints are baked
|
||||||
if (animList != null && animList.size() > 0) {
|
ArmatureHelper armatureHelper = blenderContext.getHelper(ArmatureHelper.class);
|
||||||
List<Constraint> constraints = blenderContext.getConstraints(this.armatureObjectOMA);
|
//TODO: should we apply static bone poses ??? (this breaks the animation)
|
||||||
HashMap<String, Animation> anims = new HashMap<String, Animation>();
|
// for (int i = 0; i < animData.skeleton.getBoneCount(); ++i) {
|
||||||
for (int i = 0; i < animList.size(); ++i) {
|
// Bone bone = animData.skeleton.getBone(i);
|
||||||
Animation animation = (Animation) animList.get(i).clone();
|
// 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()));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
// baking constraints into animations
|
// applying constraints to Bones (and only to bones, object constraints
|
||||||
|
// are applied in the ObjectHelper)
|
||||||
|
for (int i = 0; i < animData.skeleton.getBoneCount(); ++i) {
|
||||||
|
Long boneOMA = armatureHelper.getBoneOMA(animData.skeleton.getBone(i));
|
||||||
|
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) {
|
||||||
Long boneOMA = constraint.getBoneOMA();
|
constraint.bakeDynamic();
|
||||||
Bone bone = (Bone) blenderContext.getLoadedFeature(boneOMA, LoadedFeatureDataType.LOADED_FEATURE);
|
constraint.bakeStatic();
|
||||||
int targetIndex = bone==null ? 0 : animData.skeleton.getBoneIndex(bone);//bone==null may mean the object animation
|
}
|
||||||
constraint.affectAnimation(animation, targetIndex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// applying animations
|
||||||
|
ArrayList<Animation> animList = animData.anims;
|
||||||
|
if (animList != null && animList.size() > 0) {
|
||||||
|
HashMap<String, Animation> anims = new HashMap<String, Animation>(animList.size());
|
||||||
|
for (int i = 0; i < animList.size(); ++i) {
|
||||||
|
Animation animation = animList.get(i);
|
||||||
anims.put(animation.getName(), animation);
|
anims.put(animation.getName(), animation);
|
||||||
}
|
}
|
||||||
|
|
||||||
// applying the control to the node
|
|
||||||
SkeletonControl skeletonControl = new SkeletonControl(animData.skeleton);
|
|
||||||
AnimControl control = new AnimControl(animData.skeleton);
|
AnimControl control = new AnimControl(animData.skeleton);
|
||||||
|
|
||||||
control.setAnimations(anims);
|
control.setAnimations(anims);
|
||||||
node.addControl(control);
|
node.addControl(control);
|
||||||
node.addControl(skeletonControl);
|
node.addControl(new SkeletonControl(animData.skeleton));
|
||||||
}
|
}
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method reads mesh indexes
|
* This method reads mesh indexes
|
||||||
* @param objectStructure structure of the object that has the armature modifier applied
|
*
|
||||||
* @param meshStructure the structure of the object's mesh
|
* @param objectStructure
|
||||||
* @param blenderContext the blender context
|
* structure of the object that has the armature modifier applied
|
||||||
|
* @param meshStructure
|
||||||
|
* the structure of the object's mesh
|
||||||
|
* @param blenderContext
|
||||||
|
* the blender context
|
||||||
* @throws BlenderFileException
|
* @throws BlenderFileException
|
||||||
* this exception is thrown when the blend file structure is somehow invalid or corrupted
|
* this exception is thrown when the blend file structure is
|
||||||
|
* somehow invalid or corrupted
|
||||||
*/
|
*/
|
||||||
private void readVerticesWeightsData(Structure objectStructure, Structure meshStructure, BlenderContext blenderContext) throws BlenderFileException {
|
private void readVerticesWeightsData(Structure objectStructure, Structure meshStructure, Skeleton skeleton, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
ArmatureHelper armatureHelper = blenderContext.getHelper(ArmatureHelper.class);
|
ArmatureHelper armatureHelper = blenderContext.getHelper(ArmatureHelper.class);
|
||||||
Structure defBase = (Structure) objectStructure.getFieldValue("defbase");
|
Structure defBase = (Structure) objectStructure.getFieldValue("defbase");
|
||||||
Map<Integer, Integer> groupToBoneIndexMap = armatureHelper.getGroupToBoneIndexMap(defBase, blenderContext);
|
Map<Integer, Integer> groupToBoneIndexMap = armatureHelper.getGroupToBoneIndexMap(defBase, skeleton, blenderContext);
|
||||||
|
|
||||||
int[] bonesGroups = new int[] { 0 };
|
int[] bonesGroups = new int[] { 0 };
|
||||||
MeshContext meshContext = blenderContext.getMeshContext(meshStructure.getOldMemoryAddress());
|
MeshContext meshContext = blenderContext.getMeshContext(meshStructure.getOldMemoryAddress());
|
||||||
|
|
||||||
VertexBuffer[] boneWeightsAndIndex = this.getBoneWeightAndIndexBuffer(meshStructure, meshContext.getVertexList().size(), bonesGroups,
|
VertexBuffer[] boneWeightsAndIndex = this.getBoneWeightAndIndexBuffer(meshStructure, meshContext.getVertexList().size(), bonesGroups, meshContext.getVertexReferenceMap(), groupToBoneIndexMap, blenderContext);
|
||||||
meshContext.getVertexReferenceMap(), groupToBoneIndexMap, blenderContext);
|
|
||||||
this.verticesWeights = boneWeightsAndIndex[0];
|
this.verticesWeights = boneWeightsAndIndex[0];
|
||||||
this.verticesWeightsIndices = boneWeightsAndIndex[1];
|
this.verticesWeightsIndices = boneWeightsAndIndex[1];
|
||||||
this.boneGroups = bonesGroups[0];
|
this.boneGroups = bonesGroups[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns an array of size 2. The first element is a vertex buffer holding bone weights for every vertex in the model. The
|
* This method returns an array of size 2. The first element is a vertex
|
||||||
* second element is a vertex buffer holding bone indices for vertices (the indices of bones the vertices are assigned to).
|
* buffer holding bone weights for every vertex in the model. The second
|
||||||
|
* element is a vertex buffer holding bone indices for vertices (the indices
|
||||||
|
* of bones the vertices are assigned to).
|
||||||
*
|
*
|
||||||
* @param meshStructure
|
* @param meshStructure
|
||||||
* the mesh structure object
|
* the mesh structure object
|
||||||
* @param vertexListSize
|
* @param vertexListSize
|
||||||
* a number of vertices in the model
|
* a number of vertices in the model
|
||||||
* @param bonesGroups
|
* @param bonesGroups
|
||||||
* this is an output parameter, it should be a one-sized array; the maximum amount of weights per vertex (up to
|
* this is an output parameter, it should be a one-sized array;
|
||||||
|
* the maximum amount of weights per vertex (up to
|
||||||
* MAXIMUM_WEIGHTS_PER_VERTEX) is stored there
|
* MAXIMUM_WEIGHTS_PER_VERTEX) is stored there
|
||||||
* @param vertexReferenceMap
|
* @param vertexReferenceMap
|
||||||
* this reference map allows to map the original vertices read from blender to vertices that are really in the model; one
|
* this reference map allows to map the original vertices read
|
||||||
|
* from blender to vertices that are really in the model; one
|
||||||
* vertex may appear several times in the result model
|
* vertex may appear several times in the result model
|
||||||
* @param groupToBoneIndexMap
|
* @param groupToBoneIndexMap
|
||||||
* this object maps the group index (to which a vertices in blender belong) to bone index of the model
|
* this object maps the group index (to which a vertices in
|
||||||
|
* blender belong) to bone index of the model
|
||||||
* @param blenderContext
|
* @param blenderContext
|
||||||
* the blender context
|
* the blender context
|
||||||
* @return arrays of vertices weights and their bone indices and (as an output parameter) the maximum amount of weights for a vertex
|
* @return arrays of vertices weights and their bone indices and (as an
|
||||||
|
* output parameter) the maximum amount of weights for a vertex
|
||||||
* @throws BlenderFileException
|
* @throws BlenderFileException
|
||||||
* this exception is thrown when the blend file structure is somehow invalid or corrupted
|
* this exception is thrown when the blend file structure is
|
||||||
|
* somehow invalid or corrupted
|
||||||
*/
|
*/
|
||||||
private VertexBuffer[] getBoneWeightAndIndexBuffer(Structure meshStructure, int vertexListSize, int[] bonesGroups,
|
private VertexBuffer[] getBoneWeightAndIndexBuffer(Structure meshStructure, int vertexListSize, int[] bonesGroups, Map<Integer, List<Integer>> vertexReferenceMap, Map<Integer, Integer> groupToBoneIndexMap, BlenderContext blenderContext)
|
||||||
Map<Integer, List<Integer>> vertexReferenceMap, Map<Integer, Integer> groupToBoneIndexMap, BlenderContext blenderContext)
|
|
||||||
throws BlenderFileException {
|
throws BlenderFileException {
|
||||||
Pointer pDvert = (Pointer) meshStructure.getFieldValue("dvert");// dvert = DeformVERTices
|
Pointer pDvert = (Pointer) meshStructure.getFieldValue("dvert");// dvert = DeformVERTices
|
||||||
FloatBuffer weightsFloatData = BufferUtils.createFloatBuffer(vertexListSize * MAXIMUM_WEIGHTS_PER_VERTEX);
|
FloatBuffer weightsFloatData = BufferUtils.createFloatBuffer(vertexListSize * MAXIMUM_WEIGHTS_PER_VERTEX);
|
||||||
@ -255,13 +300,14 @@ import java.util.logging.Logger;
|
|||||||
for (Structure deformWeight : dw) {
|
for (Structure deformWeight : dw) {
|
||||||
Integer boneIndex = groupToBoneIndexMap.get(((Number) deformWeight.getFieldValue("def_nr")).intValue());
|
Integer boneIndex = groupToBoneIndexMap.get(((Number) deformWeight.getFieldValue("def_nr")).intValue());
|
||||||
|
|
||||||
//Remove this code if 4 weights limitation is removed
|
// Remove this code if 4 weights limitation is removed
|
||||||
if(weightIndex==4){
|
if (weightIndex == 4) {
|
||||||
LOGGER.log(Level.WARNING,"{0} has more than 4 weight on bone index {1}",new Object[]{meshStructure.getName(),boneIndex});
|
LOGGER.log(Level.WARNING, "{0} has more than 4 weight on bone index {1}", new Object[] { meshStructure.getName(), boneIndex });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (boneIndex != null) {// null here means that we came accross group that has no bone attached to
|
// null here means that we came accross group that has no bone attached to
|
||||||
|
if (boneIndex != null) {
|
||||||
float weight = ((Number) deformWeight.getFieldValue("weight")).floatValue();
|
float weight = ((Number) deformWeight.getFieldValue("weight")).floatValue();
|
||||||
if (weight == 0.0f) {
|
if (weight == 0.0f) {
|
||||||
weight = 1;
|
weight = 1;
|
||||||
@ -285,8 +331,10 @@ import java.util.logging.Logger;
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// always bind all vertices to 0-indexed bone
|
// always bind all vertices to 0-indexed bone
|
||||||
// this bone makes the model look normally if vertices have no bone assigned
|
// this bone makes the model look normally if vertices have no bone
|
||||||
// and it is used in object animation, so if we come accross object animation
|
// assigned
|
||||||
|
// and it is used in object animation, so if we come accross object
|
||||||
|
// animation
|
||||||
// we can use the 0-indexed bone for this
|
// we can use the 0-indexed bone for this
|
||||||
for (List<Integer> vertexIndexList : vertexReferenceMap.values()) {
|
for (List<Integer> vertexIndexList : vertexReferenceMap.values()) {
|
||||||
// we apply the weight to all referenced vertices
|
// we apply the weight to all referenced vertices
|
||||||
@ -307,9 +355,13 @@ import java.util.logging.Logger;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normalizes weights if needed and finds largest amount of weights used for all vertices in the buffer.
|
* Normalizes weights if needed and finds largest amount of weights used for
|
||||||
* @param vertCount amount of vertices
|
* all vertices in the buffer.
|
||||||
* @param weightsFloatData weights for vertices
|
*
|
||||||
|
* @param vertCount
|
||||||
|
* amount of vertices
|
||||||
|
* @param weightsFloatData
|
||||||
|
* weights for vertices
|
||||||
*/
|
*/
|
||||||
private int endBoneAssigns(int vertCount, FloatBuffer weightsFloatData) {
|
private int endBoneAssigns(int vertCount, FloatBuffer weightsFloatData) {
|
||||||
int maxWeightsPerVert = 0;
|
int maxWeightsPerVert = 0;
|
||||||
@ -339,8 +391,6 @@ import java.util.logging.Logger;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
weightsFloatData.rewind();
|
weightsFloatData.rewind();
|
||||||
|
|
||||||
// mesh.setMaxNumWeights(maxWeightsPerVert);
|
|
||||||
return maxWeightsPerVert;
|
return maxWeightsPerVert;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,9 +55,11 @@ public class ModifierHelper extends AbstractBlenderHelper {
|
|||||||
* different blender versions.
|
* different blender versions.
|
||||||
* @param blenderVersion
|
* @param blenderVersion
|
||||||
* the version read from the blend file
|
* the version read from the blend file
|
||||||
|
* @param fixUpAxis
|
||||||
|
* a variable that indicates if the Y asxis is the UP axis or not
|
||||||
*/
|
*/
|
||||||
public ModifierHelper(String blenderVersion) {
|
public ModifierHelper(String blenderVersion, boolean fixUpAxis) {
|
||||||
super(blenderVersion);
|
super(blenderVersion, fixUpAxis);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
package com.jme3.scene.plugins.blender.modifiers;
|
package com.jme3.scene.plugins.blender.modifiers;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import com.jme3.animation.AnimControl;
|
import com.jme3.animation.AnimControl;
|
||||||
import com.jme3.animation.Animation;
|
import com.jme3.animation.Animation;
|
||||||
import com.jme3.animation.SpatialTrack;
|
import com.jme3.animation.SpatialTrack;
|
||||||
@ -7,17 +13,11 @@ 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.animations.IpoHelper;
|
||||||
import com.jme3.scene.plugins.blender.constraints.Constraint;
|
|
||||||
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.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.ogre.AnimData;
|
import com.jme3.scene.plugins.ogre.AnimData;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This modifier allows to add animation to the object.
|
* This modifier allows to add animation to the object.
|
||||||
@ -51,13 +51,13 @@ import java.util.logging.Logger;
|
|||||||
* corrupted
|
* corrupted
|
||||||
*/
|
*/
|
||||||
public ObjectAnimationModifier(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException {
|
public ObjectAnimationModifier(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
LOGGER.warning("Object animation modifier not yet implemented!");
|
objectOMA = objectStructure.getOldMemoryAddress();
|
||||||
|
|
||||||
Pointer pIpo = (Pointer) objectStructure.getFieldValue("ipo");
|
Pointer pIpo = (Pointer) objectStructure.getFieldValue("ipo");
|
||||||
if (pIpo.isNotNull()) {
|
if (pIpo.isNotNull()) {
|
||||||
// check if there is an action name connected with this ipo
|
// check if there is an action name connected with this ipo
|
||||||
String objectAnimationName = null;
|
String objectAnimationName = null;
|
||||||
List<FileBlockHeader> actionBlocks = blenderContext.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00));
|
List<FileBlockHeader> actionBlocks = blenderContext.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00));
|
||||||
|
if(actionBlocks != null) {
|
||||||
for (FileBlockHeader actionBlock : actionBlocks) {
|
for (FileBlockHeader actionBlock : actionBlocks) {
|
||||||
Structure action = actionBlock.getStructure(blenderContext);
|
Structure action = actionBlock.getStructure(blenderContext);
|
||||||
List<Structure> actionChannels = ((Structure) action.getFieldValue("chanbase")).evaluateListBase(blenderContext);
|
List<Structure> actionChannels = ((Structure) action.getFieldValue("chanbase")).evaluateListBase(blenderContext);
|
||||||
@ -69,6 +69,7 @@ import java.util.logging.Logger;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String objectName = objectStructure.getName();
|
String objectName = objectStructure.getName();
|
||||||
if (objectAnimationName == null) {// set the object's animation name to object's name
|
if (objectAnimationName == null) {// set the object's animation name to object's name
|
||||||
@ -89,7 +90,7 @@ import java.util.logging.Logger;
|
|||||||
animations.add(animation);
|
animations.add(animation);
|
||||||
|
|
||||||
animData = new AnimData(null, animations);
|
animData = new AnimData(null, animations);
|
||||||
objectOMA = objectStructure.getOldMemoryAddress();
|
blenderContext.setAnimData(objectOMA, animData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,24 +99,13 @@ import java.util.logging.Logger;
|
|||||||
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) {
|
||||||
return node;
|
//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) {
|
||||||
List<Constraint> constraints = blenderContext.getConstraints(this.objectOMA);
|
|
||||||
HashMap<String, Animation> anims = new HashMap<String, Animation>();
|
HashMap<String, Animation> anims = new HashMap<String, Animation>();
|
||||||
for (int i = 0; i < animList.size(); ++i) {
|
for (int i = 0; i < animList.size(); ++i) {
|
||||||
Animation animation = (Animation) animList.get(i).clone();
|
Animation animation = animList.get(i);
|
||||||
|
|
||||||
// baking constraints into animations
|
|
||||||
if (constraints != null && constraints.size() > 0) {
|
|
||||||
for (Constraint constraint : constraints) {
|
|
||||||
constraint.affectAnimation(animation, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
anims.put(animation.getName(), animation);
|
anims.put(animation.getName(), animation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,6 +113,7 @@ import java.util.logging.Logger;
|
|||||||
control.setAnimations(anims);
|
control.setAnimations(anims);
|
||||||
node.addControl(control);
|
node.addControl(control);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,6 +49,7 @@ 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.BlenderContext.LoadedFeatureDataType;
|
import com.jme3.scene.plugins.blender.BlenderContext.LoadedFeatureDataType;
|
||||||
import com.jme3.scene.plugins.blender.cameras.CameraHelper;
|
import com.jme3.scene.plugins.blender.cameras.CameraHelper;
|
||||||
|
import com.jme3.scene.plugins.blender.constraints.Constraint;
|
||||||
import com.jme3.scene.plugins.blender.constraints.ConstraintHelper;
|
import com.jme3.scene.plugins.blender.constraints.ConstraintHelper;
|
||||||
import com.jme3.scene.plugins.blender.curves.CurvesHelper;
|
import com.jme3.scene.plugins.blender.curves.CurvesHelper;
|
||||||
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
@ -99,9 +100,11 @@ public class ObjectHelper extends AbstractBlenderHelper {
|
|||||||
* different blender versions.
|
* different blender versions.
|
||||||
* @param blenderVersion
|
* @param blenderVersion
|
||||||
* the version read from the blend file
|
* the version read from the blend file
|
||||||
|
* @param fixUpAxis
|
||||||
|
* a variable that indicates if the Y asxis is the UP axis or not
|
||||||
*/
|
*/
|
||||||
public ObjectHelper(String blenderVersion) {
|
public ObjectHelper(String blenderVersion, boolean fixUpAxis) {
|
||||||
super(blenderVersion);
|
super(blenderVersion, fixUpAxis);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -121,17 +124,12 @@ public class ObjectHelper extends AbstractBlenderHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
blenderContext.pushParent(objectStructure);
|
blenderContext.pushParent(objectStructure);
|
||||||
ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
|
|
||||||
|
|
||||||
//get object data
|
//get object data
|
||||||
int type = ((Number)objectStructure.getFieldValue("type")).intValue();
|
int type = ((Number)objectStructure.getFieldValue("type")).intValue();
|
||||||
String name = objectStructure.getName();
|
String name = objectStructure.getName();
|
||||||
LOGGER.log(Level.INFO, "Loading obejct: {0}", name);
|
LOGGER.log(Level.INFO, "Loading obejct: {0}", name);
|
||||||
|
|
||||||
//loading constraints connected with this object
|
|
||||||
ConstraintHelper constraintHelper = blenderContext.getHelper(ConstraintHelper.class);
|
|
||||||
constraintHelper.loadConstraints(objectStructure, blenderContext);
|
|
||||||
|
|
||||||
int restrictflag = ((Number)objectStructure.getFieldValue("restrictflag")).intValue();
|
int restrictflag = ((Number)objectStructure.getFieldValue("restrictflag")).intValue();
|
||||||
boolean visible = (restrictflag & 0x01) != 0;
|
boolean visible = (restrictflag & 0x01) != 0;
|
||||||
Object result = null;
|
Object result = null;
|
||||||
@ -143,7 +141,7 @@ public class ObjectHelper extends AbstractBlenderHelper {
|
|||||||
parent = this.toObject(parentStructure, blenderContext);
|
parent = this.toObject(parentStructure, blenderContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
Transform t = objectHelper.getTransformation(objectStructure, blenderContext);
|
Transform t = this.getTransformation(objectStructure, blenderContext);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
switch(type) {
|
switch(type) {
|
||||||
@ -245,7 +243,7 @@ public class ObjectHelper extends AbstractBlenderHelper {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OBJECT_TYPE_ARMATURE:
|
case OBJECT_TYPE_ARMATURE:
|
||||||
//Do not do anything, the object with all needed data is loaded when armature modifier loads
|
//Do nothing, the object with all needed data is loaded when armature modifier loads
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOGGER.log(Level.WARNING, "Unknown object type: {0}", type);
|
LOGGER.log(Level.WARNING, "Unknown object type: {0}", type);
|
||||||
@ -255,13 +253,25 @@ public class ObjectHelper extends AbstractBlenderHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(result != null) {
|
if(result != null) {
|
||||||
|
blenderContext.addLoadedFeatures(objectStructure.getOldMemoryAddress(), name, objectStructure, result);
|
||||||
|
|
||||||
|
//loading constraints connected with this object
|
||||||
|
ConstraintHelper constraintHelper = blenderContext.getHelper(ConstraintHelper.class);
|
||||||
|
constraintHelper.loadConstraints(objectStructure, blenderContext);
|
||||||
|
|
||||||
|
//baking constraints
|
||||||
|
List<Constraint> objectConstraints = blenderContext.getConstraints(objectStructure.getOldMemoryAddress());
|
||||||
|
if(objectConstraints!=null) {
|
||||||
|
for(Constraint objectConstraint : objectConstraints) {
|
||||||
|
objectConstraint.bakeStatic();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//reading custom properties
|
//reading custom properties
|
||||||
Properties properties = this.loadProperties(objectStructure, blenderContext);
|
Properties properties = this.loadProperties(objectStructure, blenderContext);
|
||||||
if(result instanceof Spatial && properties != null && properties.getValue() != null) {
|
if(result instanceof Spatial && properties != null && properties.getValue() != null) {
|
||||||
((Spatial)result).setUserData("properties", properties);
|
((Spatial)result).setUserData("properties", properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
blenderContext.addLoadedFeatures(objectStructure.getOldMemoryAddress(), name, objectStructure, result);
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -292,13 +302,7 @@ public class ObjectHelper extends AbstractBlenderHelper {
|
|||||||
|
|
||||||
Vector3f translation = localMatrix.toTranslationVector();
|
Vector3f translation = localMatrix.toTranslationVector();
|
||||||
Quaternion rotation = localMatrix.toRotationQuat();
|
Quaternion rotation = localMatrix.toRotationQuat();
|
||||||
//getting the scale
|
Vector3f scale = this.getScale(parentInv).multLocal(size.get(0).floatValue(), size.get(1).floatValue(), size.get(2).floatValue());
|
||||||
float scaleX = (float) Math.sqrt(parentInv.m00 * parentInv.m00 + parentInv.m10 * parentInv.m10 + parentInv.m20 * parentInv.m20);
|
|
||||||
float scaleY = (float) Math.sqrt(parentInv.m01 * parentInv.m01 + parentInv.m11 * parentInv.m11 + parentInv.m21 * parentInv.m21);
|
|
||||||
float scaleZ = (float) Math.sqrt(parentInv.m02 * parentInv.m02 + parentInv.m12 * parentInv.m12 + parentInv.m22 * parentInv.m22);
|
|
||||||
Vector3f scale = new Vector3f(size.get(0).floatValue() * scaleX,
|
|
||||||
size.get(1).floatValue() * scaleY,
|
|
||||||
size.get(2).floatValue() * scaleZ);
|
|
||||||
|
|
||||||
if(fixUpAxis) {
|
if(fixUpAxis) {
|
||||||
float y = translation.y;
|
float y = translation.y;
|
||||||
@ -321,35 +325,76 @@ public class ObjectHelper extends AbstractBlenderHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns the transformation matrix of the given object structure.
|
* This method returns the matrix of a given name for the given structure.
|
||||||
* @param objectStructure
|
* The matrix is NOT transformed if Y axis is up - the raw data is loaded from the blender file.
|
||||||
* the structure with object's data
|
* @param structure
|
||||||
* @return object's transformation matrix
|
* the structure with matrix data
|
||||||
|
* @param matrixName
|
||||||
|
* the name of the matrix
|
||||||
|
* @return the required matrix
|
||||||
*/
|
*/
|
||||||
public Matrix4f getTransformationMatrix(Structure objectStructure) {
|
public Matrix4f getMatrix(Structure structure, String matrixName) {
|
||||||
return this.getMatrix(objectStructure, "obmat");
|
return this.getMatrix(structure, matrixName, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns the matrix of a given name for the given object structure.
|
* This method returns the matrix of a given name for the given structure.
|
||||||
* @param objectStructure
|
* It takes up axis into consideration.
|
||||||
* the structure with object's data
|
* @param structure
|
||||||
|
* the structure with matrix data
|
||||||
* @param matrixName
|
* @param matrixName
|
||||||
* the name of the matrix structure
|
* the name of the matrix
|
||||||
* @return object's matrix
|
* @return the required matrix
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected Matrix4f getMatrix(Structure objectStructure, String matrixName) {
|
public Matrix4f getMatrix(Structure structure, String matrixName, boolean applyFixUpAxis) {
|
||||||
Matrix4f result = new Matrix4f();
|
Matrix4f result = new Matrix4f();
|
||||||
DynamicArray<Number> obmat = (DynamicArray<Number>)objectStructure.getFieldValue(matrixName);
|
DynamicArray<Number> obmat = (DynamicArray<Number>)structure.getFieldValue(matrixName);
|
||||||
for(int i = 0; i < 4; ++i) {
|
int rowAndColumnSize = Math.abs((int)Math.sqrt(obmat.getTotalSize()));//the matrix must be square
|
||||||
for(int j = 0; j < 4; ++j) {
|
for(int i = 0; i < rowAndColumnSize; ++i) {
|
||||||
|
for(int j = 0; j < rowAndColumnSize; ++j) {
|
||||||
result.set(i, j, obmat.get(j, i).floatValue());
|
result.set(i, j, obmat.get(j, i).floatValue());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if(applyFixUpAxis && fixUpAxis) {
|
||||||
|
Vector3f translation = result.toTranslationVector();
|
||||||
|
Quaternion rotation = result.toRotationQuat();
|
||||||
|
Vector3f scale = this.getScale(result);
|
||||||
|
|
||||||
|
float y = translation.y;
|
||||||
|
translation.y = translation.z;
|
||||||
|
translation.z = -y;
|
||||||
|
|
||||||
|
y = rotation.getY();
|
||||||
|
float z = rotation.getZ();
|
||||||
|
rotation.set(rotation.getX(), z, -y, rotation.getW());
|
||||||
|
|
||||||
|
y=scale.y;
|
||||||
|
scale.y = scale.z;
|
||||||
|
scale.z = y;
|
||||||
|
|
||||||
|
result.loadIdentity();
|
||||||
|
result.setTranslation(translation);
|
||||||
|
result.setRotationQuaternion(rotation);
|
||||||
|
result.setScale(scale);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the scale from the given matrix.
|
||||||
|
*
|
||||||
|
* @param matrix
|
||||||
|
* the transformation matrix
|
||||||
|
* @return the scale from the given matrix
|
||||||
|
*/
|
||||||
|
public Vector3f getScale(Matrix4f matrix) {
|
||||||
|
float scaleX = (float) Math.sqrt(matrix.m00 * matrix.m00 + matrix.m10 * matrix.m10 + matrix.m20 * matrix.m20);
|
||||||
|
float scaleY = (float) Math.sqrt(matrix.m01 * matrix.m01 + matrix.m11 * matrix.m11 + matrix.m21 * matrix.m21);
|
||||||
|
float scaleZ = (float) Math.sqrt(matrix.m02 * matrix.m02 + matrix.m12 * matrix.m12 + matrix.m22 * matrix.m22);
|
||||||
|
return new Vector3f(scaleX, scaleY, scaleZ);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clearState() {
|
public void clearState() {
|
||||||
fixUpAxis = false;
|
fixUpAxis = false;
|
||||||
|
@ -86,9 +86,11 @@ public class ParticlesHelper extends AbstractBlenderHelper {
|
|||||||
* different blender versions.
|
* different blender versions.
|
||||||
* @param blenderVersion
|
* @param blenderVersion
|
||||||
* the version read from the blend file
|
* the version read from the blend file
|
||||||
|
* @param fixUpAxis
|
||||||
|
* a variable that indicates if the Y asxis is the UP axis or not
|
||||||
*/
|
*/
|
||||||
public ParticlesHelper(String blenderVersion) {
|
public ParticlesHelper(String blenderVersion, boolean fixUpAxis) {
|
||||||
super(blenderVersion);
|
super(blenderVersion, fixUpAxis);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@ -96,7 +96,7 @@ import java.util.logging.Logger;
|
|||||||
* the number of blender version
|
* the number of blender version
|
||||||
*/
|
*/
|
||||||
public NoiseGenerator(String blenderVersion) {
|
public NoiseGenerator(String blenderVersion) {
|
||||||
super(blenderVersion);
|
super(blenderVersion, false);
|
||||||
this.loadConstants();
|
this.loadConstants();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,9 +135,11 @@ public class TextureHelper extends AbstractBlenderHelper {
|
|||||||
*
|
*
|
||||||
* @param blenderVersion
|
* @param blenderVersion
|
||||||
* the version read from the blend file
|
* the version read from the blend file
|
||||||
|
* @param fixUpAxis
|
||||||
|
* a variable that indicates if the Y asxis is the UP axis or not
|
||||||
*/
|
*/
|
||||||
public TextureHelper(String blenderVersion) {
|
public TextureHelper(String blenderVersion, boolean fixUpAxis) {
|
||||||
super(blenderVersion);
|
super(blenderVersion, false);
|
||||||
noiseGenerator = new NoiseGenerator(blenderVersion);
|
noiseGenerator = new NoiseGenerator(blenderVersion);
|
||||||
textureGenerators.put(Integer.valueOf(TEX_BLEND), new TextureGeneratorBlend(noiseGenerator));
|
textureGenerators.put(Integer.valueOf(TEX_BLEND), new TextureGeneratorBlend(noiseGenerator));
|
||||||
textureGenerators.put(Integer.valueOf(TEX_CLOUDS), new TextureGeneratorClouds(noiseGenerator));
|
textureGenerators.put(Integer.valueOf(TEX_CLOUDS), new TextureGeneratorClouds(noiseGenerator));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user