From 44a7b1f098ca58d7df2a9ea06f2f2491d731f319 Mon Sep 17 00:00:00 2001 From: "Kae..pl" Date: Sun, 3 Nov 2013 17:32:43 +0000 Subject: [PATCH] Feature: applying static pose transformations for bones. git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10872 75d07b2b-3a1a-0410-a2c5-0572b91ccdca --- .../blender/animations/BoneContext.java | 6 +- .../blender/constraints/SimulationNode.java | 12 +-- .../blender/modifiers/ArmatureModifier.java | 80 +++++++++++++++---- 3 files changed, 68 insertions(+), 30 deletions(-) diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/animations/BoneContext.java b/engine/src/blender/com/jme3/scene/plugins/blender/animations/BoneContext.java index 2e46fd77d..8f2b6dc82 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/animations/BoneContext.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/animations/BoneContext.java @@ -29,7 +29,7 @@ public class BoneContext { * The bones' matrices have, unlike objects', the coordinate system identical to JME's (Y axis is UP, X to the right and Z toward us). * So in order to have them loaded properly we need to transform their armature matrix (which blender sees as rotated) to make sure we get identical results. */ - private static final Matrix4f BONE_ARMATURE_TRANSFORMATION_MATRIX = new Matrix4f(1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1); + public static final Matrix4f BONE_ARMATURE_TRANSFORMATION_MATRIX = new Matrix4f(1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1); private BlenderContext blenderContext; /** The OMA of the bone's armature object. */ @@ -102,7 +102,7 @@ public class BoneContext { // then make sure it is rotated in a proper way to fit the jme bone transformation conventions globalBoneMatrix.multLocal(BONE_ARMATURE_TRANSFORMATION_MATRIX); - Spatial armature = (Spatial) blenderContext.getLoadedFeature(armatureObjectOMA, LoadedFeatureDataType.LOADED_FEATURE); + Spatial armature = (Spatial) objectHelper.toObject(blenderContext.getFileBlock(armatureObjectOMA).getStructure(blenderContext), blenderContext); ConstraintHelper constraintHelper = blenderContext.getHelper(ConstraintHelper.class); Matrix4f armatureWorldMatrix = constraintHelper.toMatrix(armature.getWorldTransform()); @@ -177,7 +177,7 @@ public class BoneContext { * @return the length of the bone */ public float getLength() { - return length; + return length * bone.getModelSpaceScale().y; } /** diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/SimulationNode.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/SimulationNode.java index bf7480adf..f656150fa 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/SimulationNode.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/SimulationNode.java @@ -250,7 +250,6 @@ public class SimulationNode { */ private void simulateSkeleton() { if (constraints != null && constraints.size() > 0) { - boolean applyStaticConstraints = true; Set alteredOmas = new HashSet(); if (animations != null) { @@ -335,22 +334,12 @@ public class SimulationNode { animation.addTrack(newTrack); } } - applyStaticConstraints = false; } } vars.release(); animControl.clearChannels(); this.reset(); } - - // if there are no animations then just constraint the static - // object's transformation - if (applyStaticConstraints) { - for (Constraint constraint : constraints) { - constraint.apply(0); - } - skeleton.updateWorldVectors(); - } } } @@ -373,6 +362,7 @@ public class SimulationNode { if (constraint.getAlteredOmas() != null) { alteredOmas.addAll(constraint.getAlteredOmas()); } + alteredOmas.add(boneContext.getBoneOma()); } } for (Bone child : bone.getChildren()) { diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ArmatureModifier.java b/engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ArmatureModifier.java index 93e15ab5d..c6b8a36c6 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ArmatureModifier.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ArmatureModifier.java @@ -17,6 +17,8 @@ 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.Transform; import com.jme3.scene.Geometry; import com.jme3.scene.Mesh; import com.jme3.scene.Node; @@ -29,12 +31,16 @@ import com.jme3.scene.plugins.blender.BlenderContext.LoadedFeatureDataType; import com.jme3.scene.plugins.blender.animations.AnimationData; import com.jme3.scene.plugins.blender.animations.ArmatureHelper; import com.jme3.scene.plugins.blender.animations.BoneContext; +import com.jme3.scene.plugins.blender.constraints.ConstraintHelper; +import com.jme3.scene.plugins.blender.constraints.ConstraintHelper.Space; import com.jme3.scene.plugins.blender.file.BlenderFileException; import com.jme3.scene.plugins.blender.file.FileBlockHeader; import com.jme3.scene.plugins.blender.file.Pointer; import com.jme3.scene.plugins.blender.file.Structure; import com.jme3.scene.plugins.blender.meshes.MeshContext; +import com.jme3.scene.plugins.blender.objects.ObjectHelper; import com.jme3.util.BufferUtils; +import com.jme3.util.TempVars; /** * This modifier allows to add bone animation to the object. @@ -45,6 +51,7 @@ import com.jme3.util.BufferUtils; private static final Logger LOGGER = Logger.getLogger(ArmatureModifier.class.getName()); private static final int MAXIMUM_WEIGHTS_PER_VERTEX = 4; // JME + private Structure armatureObject; private Skeleton skeleton; private Structure objectStructure; private Structure meshStructure; @@ -75,7 +82,7 @@ import com.jme3.util.BufferUtils; if (pArmatureObject.isNotNull()) { ArmatureHelper armatureHelper = blenderContext.getHelper(ArmatureHelper.class); - Structure armatureObject = pArmatureObject.fetchData(blenderContext.getInputStream()).get(0); + armatureObject = pArmatureObject.fetchData(blenderContext.getInputStream()).get(0); // load skeleton Structure armatureStructure = ((Pointer) armatureObject.getFieldValue("data")).fetchData(blenderContext.getInputStream()).get(0); @@ -147,7 +154,7 @@ import com.jme3.util.BufferUtils; // store the animation data for each bone for (Bone bone : bones) { - if(bone.getName().length() > 0) { + if (bone.getName().length() > 0) { BoneContext boneContext = blenderContext.getBoneContext(bone); Long boneOma = boneContext.getBoneOma(); if (boneOma != null) { @@ -167,7 +174,7 @@ import com.jme3.util.BufferUtils; if (invalid) { LOGGER.log(Level.WARNING, "Armature modifier is invalid! Cannot be applied to: {0}", node.getName()); }// if invalid, animData will be null - if(animationData != null && skeleton != null) { + if (animationData != null && skeleton != null) { // setting weights for bones List geomList = (List) blenderContext.getLoadedFeature(meshOMA, LoadedFeatureDataType.LOADED_FEATURE); MeshContext meshContext = blenderContext.getMeshContext(meshOMA); @@ -175,25 +182,24 @@ import com.jme3.util.BufferUtils; for (Geometry geom : geomList) { int materialIndex = meshContext.getMaterialIndex(geom); Mesh mesh = geom.getMesh(); - + try { VertexBuffer[] buffers = this.readVerticesWeightsData(objectStructure, meshStructure, skeleton, materialIndex, bonesGroups, blenderContext); if (buffers != null) { mesh.setMaxNumWeights(bonesGroups[0]); mesh.setBuffer(buffers[0]); mesh.setBuffer(buffers[1]); - + LOGGER.fine("Generating bind pose and normal buffers."); mesh.generateBindPose(true); - + // change the usage type of vertex and normal buffers from // Static to Stream mesh.getBuffer(Type.Position).setUsage(Usage.Stream); mesh.getBuffer(Type.Normal).setUsage(Usage.Stream); - - - //creating empty buffers for HW skinning - //the buffers will be setup if ever used. + + // creating empty buffers for HW skinning + // the buffers will be setup if ever used. VertexBuffer verticesWeightsHW = new VertexBuffer(Type.HWBoneWeight); VertexBuffer verticesWeightsIndicesHW = new VertexBuffer(Type.HWBoneIndex); mesh.setBuffer(verticesWeightsHW); @@ -204,8 +210,8 @@ import com.jme3.util.BufferUtils; invalid = true; } } - - if(!invalid) { + + if (!invalid) { // applying animations AnimControl control = new AnimControl(animationData.skeleton); List animList = animationData.anims; @@ -219,8 +225,51 @@ import com.jme3.util.BufferUtils; } node.addControl(control); node.addControl(new SkeletonControl(animationData.skeleton)); - blenderContext.setNodeForSkeleton(skeleton, node); + + TempVars tempVars = TempVars.get(); + try { + Pointer pPose = (Pointer) armatureObject.getFieldValue("pose"); + if (pPose.isNotNull()) { + LOGGER.fine("Loading the pose of the armature."); + ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class); + ConstraintHelper constraintHelper = blenderContext.getHelper(ConstraintHelper.class); + + Structure pose = pPose.fetchData(blenderContext.getInputStream()).get(0); + Structure chanbase = (Structure) pose.getFieldValue("chanbase"); + List chans = chanbase.evaluateListBase(blenderContext); + Transform transform = new Transform(); + for (Structure poseChannel : chans) { + Pointer pBone = (Pointer) poseChannel.getFieldValue("bone"); + if (pBone.isNull()) { + throw new BlenderFileException("Cannot find bone for pose channel named: " + poseChannel.getName()); + } + BoneContext boneContext = blenderContext.getBoneContext(pBone.getOldMemoryAddress()); + + LOGGER.log(Level.FINEST, "Getting the global pose transformation for bone: {0}", boneContext); + Matrix4f poseMat = objectHelper.getMatrix(poseChannel, "pose_mat", blenderContext.getBlenderKey().isFixUpAxis()); + poseMat.multLocal(BoneContext.BONE_ARMATURE_TRANSFORMATION_MATRIX); + + Matrix4f armatureWorldMat = objectHelper.getMatrix(armatureObject, "obmat", blenderContext.getBlenderKey().isFixUpAxis()); + Matrix4f boneWorldMat = armatureWorldMat.multLocal(poseMat); + + boneWorldMat.toTranslationVector(tempVars.vect1); + boneWorldMat.toRotationQuat(tempVars.quat1); + boneWorldMat.toScaleVector(tempVars.vect2); + transform.setTranslation(tempVars.vect1); + transform.setRotation(tempVars.quat1); + transform.setScale(tempVars.vect2); + + constraintHelper.applyTransform(boneContext.getArmatureObjectOMA(), boneContext.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD, transform); + } + } + } catch (BlenderFileException e) { + LOGGER.log(Level.WARNING, "Problems occured during pose loading: {0}.", e.getLocalizedMessage()); + } finally { + tempVars.release(); + } + + node.updateModelBound(); } } } @@ -277,8 +326,7 @@ import com.jme3.util.BufferUtils; * this exception is thrown when the blend file structure is * somehow invalid or corrupted */ - private VertexBuffer[] getBoneWeightAndIndexBuffer(Structure meshStructure, int vertexListSize, int[] bonesGroups, Map> vertexReferenceMap, Map groupToBoneIndexMap, BlenderContext blenderContext) - throws BlenderFileException { + private VertexBuffer[] getBoneWeightAndIndexBuffer(Structure meshStructure, int vertexListSize, int[] bonesGroups, Map> vertexReferenceMap, Map groupToBoneIndexMap, BlenderContext blenderContext) throws BlenderFileException { bonesGroups[0] = 0; Pointer pDvert = (Pointer) meshStructure.getFieldValue("dvert");// dvert // = @@ -295,7 +343,7 @@ import com.jme3.util.BufferUtils; TreeMap weightToIndexMap = new TreeMap(); for (Structure dvert : dverts) { - //we fetch the referenced vertices here + // we fetch the referenced vertices here List vertexIndices = vertexReferenceMap.get(Integer.valueOf(vertexIndex)); if (vertexIndices != null) { // total amount of wights assigned to the vertex (max. 4 in JME)