From 5b866bcd6a17ae517fe9595c838836a15a55c6d3 Mon Sep 17 00:00:00 2001 From: "remy.bouquet@gmail.com" Date: Sun, 1 May 2011 09:18:29 +0000 Subject: [PATCH] KinematicRagdollControl : - Made a lot of clean up and optimization - Better automagic creation of the ragdoll git-svn-id: http://jmonkeyengine.googlecode.com/svn/trunk@7379 75d07b2b-3a1a-0410-a2c5-0572b91ccdca --- .../bullet/control/KinematicRagdollControl.java | 284 +++++---------------- .../jme3/bullet/control/ragdoll/RagdollUtils.java | 273 ++++++++++++++++++++ .../src/test/jme3test/bullet/TestBoneRagdoll.java | 20 +- 3 files changed, 348 insertions(+), 229 deletions(-) create mode 100644 engine/src/jbullet/com/jme3/bullet/control/ragdoll/RagdollUtils.java diff --git a/engine/src/jbullet/com/jme3/bullet/control/KinematicRagdollControl.java b/engine/src/jbullet/com/jme3/bullet/control/KinematicRagdollControl.java index 28a3fdb69..e9783bafe 100644 --- a/engine/src/jbullet/com/jme3/bullet/control/KinematicRagdollControl.java +++ b/engine/src/jbullet/com/jme3/bullet/control/KinematicRagdollControl.java @@ -31,12 +31,10 @@ */ package com.jme3.bullet.control; -import com.jme3.animation.AnimChannel; import com.jme3.bullet.control.ragdoll.RagdollPreset; import com.jme3.bullet.control.ragdoll.HumanoidRagdollPreset; import com.jme3.animation.AnimControl; import com.jme3.animation.Bone; -import com.jme3.animation.LoopMode; import com.jme3.animation.Skeleton; import com.jme3.animation.SkeletonControl; import com.jme3.asset.AssetManager; @@ -47,6 +45,7 @@ import com.jme3.bullet.collision.PhysicsCollisionObject; import com.jme3.bullet.collision.RagdollCollisionListener; import com.jme3.bullet.collision.shapes.BoxCollisionShape; import com.jme3.bullet.collision.shapes.HullCollisionShape; +import com.jme3.bullet.control.ragdoll.RagdollUtils; import com.jme3.bullet.joints.SixDofJoint; import com.jme3.bullet.objects.PhysicsRigidBody; import com.jme3.export.JmeExporter; @@ -56,22 +55,18 @@ import com.jme3.math.Transform; import com.jme3.math.Vector3f; import com.jme3.renderer.RenderManager; import com.jme3.renderer.ViewPort; -import com.jme3.scene.Geometry; -import com.jme3.scene.Mesh; import com.jme3.scene.Node; import com.jme3.scene.Spatial; -import com.jme3.scene.VertexBuffer.Type; import com.jme3.scene.control.Control; import com.jme3.util.TempVars; import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.FloatBuffer; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; -import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.TreeSet; import java.util.logging.Level; import java.util.logging.Logger; @@ -114,7 +109,7 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision protected boolean enabled = true; protected boolean debug = false; protected PhysicsRigidBody baseRigidBody; - protected float weightThreshold = 1.0f; + protected float weightThreshold = -1.0f; protected Spatial targetModel; protected Vector3f initScale; protected Mode mode = Mode.Kinetmatic; @@ -124,19 +119,29 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision protected List listeners; protected float eventDispatchImpulseThreshold = 10; protected RagdollPreset preset = new HumanoidRagdollPreset(); - protected List boneList = new LinkedList(); + protected Set boneList = new TreeSet(); protected Vector3f modelPosition = new Vector3f(); protected Quaternion modelRotation = new Quaternion(); protected float rootMass = 15; protected float totalMass = 0; protected boolean added = false; - public enum Mode { + public static enum Mode { Kinetmatic, Ragdoll } + protected class PhysicsBoneLink { + + protected Bone bone; + protected Quaternion initalWorldRotation; + protected SixDofJoint joint; + protected PhysicsRigidBody rigidBody; + protected Quaternion startBlendingRot = new Quaternion(); + protected Vector3f startBlendingPos = new Vector3f(); + } + /** * contruct a KinematicRagdollControl */ @@ -206,7 +211,7 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision } else { //boneList is not empty, this means some bones of the skeleton might not be associated with a collision shape. //So we update them recusively - setTransform(link.bone, position, tmpRot1, false); + RagdollUtils.setTransform(link.bone, position, tmpRot1, false, boneList); } } } @@ -238,7 +243,7 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision //we give control back to the key framed animation. link.bone.setUserControl(false); } else { - setTransform(link.bone, position, tmpRot1, true); + RagdollUtils.setTransform(link.bone, position, tmpRot1, true, boneList); } } @@ -252,7 +257,6 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision blendStart += tpf; if (blendStart > blendTime) { blendedControl = false; - } } } @@ -261,35 +265,6 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision } /** - * Updates a bone position and rotation. - * if the child bones are not in the bone list this means, they are not associated with a physic shape. - * So they have to be updated - * @param bone the bone - * @param pos the position - * @param rot the rotation - */ - private void setTransform(Bone bone, Vector3f pos, Quaternion rot, boolean restoreBoneControl) { - //we ensure that we have the control - if (restoreBoneControl) { - bone.setUserControl(true); - } - //we set te user transforms of the bone - bone.setUserTransformsWorld(pos, rot); - for (Bone childBone : bone.getChildren()) { - //each child bone that is not in the list is updated - if (!boneList.contains(childBone.getName())) { - Transform t = childBone.getCombinedTransform(pos, rot); - setTransform(childBone, t.getTranslation(), t.getRotation(), restoreBoneControl); - } - } - //we give back the control to the keyframed animation - if (restoreBoneControl) { - bone.setUserControl(false); - } - - } - - /** * Set the transforms of a rigidBody to match the transforms of a bone. * this is used to make the ragdoll follow the skeleton motion while in Kinematic mode * @param link the link containing the bone and the rigidBody @@ -309,16 +284,17 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision link.rigidBody.setPhysicsLocation(position); link.rigidBody.setPhysicsRotation(tmpRot1); -// position.set(link.bone.getModelSpaceScale()).multLocal(targetModel.getWorldScale()); -// //TODO support scale! -// link.rigidBody.getCollisionShape().setScale(position); } public Control cloneForSpatial(Spatial spatial) { throw new UnsupportedOperationException("Not supported yet."); } - public void reInit() { + /** + * rebuild the ragdoll + * this is useful if you applied scale on the ragdoll after it's been initialized + */ + public void reBuild() { setSpatial(targetModel); addToPhysicsSpace(); } @@ -367,12 +343,21 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision logger.log(Level.INFO, "Created physics ragdoll for skeleton {0}", skeleton); } + /** + * Add a bone name to this control + * Using this method you can specify which bones of the skeleton will be used to build the collision shapes. + * @param name + */ public void addBoneName(String name) { boneList.add(name); } private void scanSpatial(Spatial model) { AnimControl animControl = model.getControl(AnimControl.class); + Map> pointsMap = null; + if (weightThreshold == -1.0f) { + pointsMap = RagdollUtils.buildPointMap(model); + } skeleton = animControl.getSkeleton(); skeleton.resetAndUpdate(); @@ -382,19 +367,29 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision logger.log(Level.INFO, "Found root bone in skeleton {0}", skeleton); baseRigidBody = new PhysicsRigidBody(new BoxCollisionShape(Vector3f.UNIT_XYZ.mult(0.1f)), 1); baseRigidBody.setKinematic(mode == Mode.Kinetmatic); - boneRecursion(model, childBone, baseRigidBody, 1); + boneRecursion(model, childBone, baseRigidBody, 1, pointsMap); } } } - private void boneRecursion(Spatial model, Bone bone, PhysicsRigidBody parent, int reccount) { + private void boneRecursion(Spatial model, Bone bone, PhysicsRigidBody parent, int reccount, Map> pointsMap) { PhysicsRigidBody parentShape = parent; if (boneList.isEmpty() || boneList.contains(bone.getName())) { PhysicsBoneLink link = new PhysicsBoneLink(); link.bone = bone; - //creating the collision shape from the bone's associated vertices - PhysicsRigidBody shapeNode = new PhysicsRigidBody(makeShape(link, model), rootMass / (float) reccount); + + //creating the collision shape + HullCollisionShape shape = null; + if (pointsMap != null) { + //build a shape for the bone, using the vertices that are most influenced by this bone + shape = RagdollUtils.makeShapeFromPointMap(pointsMap, RagdollUtils.getBoneIndices(link.bone, skeleton, boneList), initScale, link.bone.getModelSpacePosition()); + } else { + //build a shape for the bone, using the vertices associated with this bone with a weight above the threshold + shape = RagdollUtils.makeShapeFromVerticeWeights(model, RagdollUtils.getBoneIndices(link.bone, skeleton, boneList), initScale, link.bone.getModelSpacePosition(), weightThreshold); + } + + PhysicsRigidBody shapeNode = new PhysicsRigidBody(shape, rootMass / (float) reccount); shapeNode.setKinematic(mode == Mode.Kinetmatic); totalMass += rootMass / (float) reccount; @@ -408,12 +403,7 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision bone.getModelSpacePosition().subtract(bone.getParent().getModelSpacePosition(), posToParent).multLocal(initScale); } - //Joint local position from parent - link.pivotA = posToParent; - //joint local position from current bone - link.pivotB = new Vector3f(0, 0, 0f); - - SixDofJoint joint = new SixDofJoint(parent, shapeNode, link.pivotA, link.pivotB, true); + SixDofJoint joint = new SixDofJoint(parent, shapeNode, posToParent, new Vector3f(0, 0, 0f), true); preset.setupJointForBone(bone.getName(), joint); link.joint = joint; @@ -426,10 +416,8 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision for (Iterator it = bone.getChildren().iterator(); it.hasNext();) { Bone childBone = it.next(); - boneRecursion(model, childBone, parentShape, reccount + 1); + boneRecursion(model, childBone, parentShape, reccount + 1, pointsMap); } - - } /** @@ -446,7 +434,7 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision public void setJointLimit(String boneName, float maxX, float minX, float maxY, float minY, float maxZ, float minZ) { PhysicsBoneLink link = boneLinks.get(boneName); if (link != null) { - setJointLimit(link.joint, maxX, minX, maxY, minY, maxZ, minZ); + RagdollUtils.setJointLimit(link.joint, maxX, minX, maxY, minY, maxZ, minZ); } else { logger.log(Level.WARNING, "Not joint was found for bone {0}. make sure you call spatial.addControl(ragdoll) before setting joints limit", boneName); } @@ -468,16 +456,6 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision } } - private void setJointLimit(SixDofJoint joint, float maxX, float minX, float maxY, float minY, float maxZ, float minZ) { - - joint.getRotationalLimitMotor(0).setHiLimit(maxX); - joint.getRotationalLimitMotor(0).setLoLimit(minX); - joint.getRotationalLimitMotor(1).setHiLimit(maxY); - joint.getRotationalLimitMotor(1).setLoLimit(minY); - joint.getRotationalLimitMotor(2).setHiLimit(maxZ); - joint.getRotationalLimitMotor(2).setLoLimit(minZ); - } - private void clearData() { boneLinks.clear(); baseRigidBody = null; @@ -504,111 +482,6 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision } } - /** - * Create a hull collision shape from linked vertices to this bone. - * - * @param link - * @param model - * @return - */ - protected HullCollisionShape makeShape(PhysicsBoneLink link, Spatial model) { - Bone bone = link.bone; - List boneIndices = null; - if (boneList.isEmpty()) { - boneIndices = new LinkedList(); - boneIndices.add(skeleton.getBoneIndex(bone)); - } else { - boneIndices = getBoneIndices(bone, skeleton); - } - - ArrayList points = new ArrayList(); - if (model instanceof Geometry) { - Geometry g = (Geometry) model; - for (Integer index : boneIndices) { - points.addAll(getPoints(g.getMesh(), index, bone.getModelSpacePosition())); - } - } else if (model instanceof Node) { - Node node = (Node) model; - for (Spatial s : node.getChildren()) { - if (s instanceof Geometry) { - Geometry g = (Geometry) s; - for (Integer index : boneIndices) { - points.addAll(getPoints(g.getMesh(), index, bone.getModelSpacePosition())); - } - - } - } - } - float[] p = new float[points.size()]; - for (int i = 0; i < points.size(); i++) { - p[i] = points.get(i); - } - - - return new HullCollisionShape(p); - } - - //retruns the list of bone indices of the given bone and its child(if they are not in the boneList) - protected List getBoneIndices(Bone bone, Skeleton skeleton) { - List list = new LinkedList(); - list.add(skeleton.getBoneIndex(bone)); - for (Bone chilBone : bone.getChildren()) { - if (!boneList.contains(chilBone.getName())) { - list.addAll(getBoneIndices(chilBone, skeleton)); - } - } - return list; - } - - /** - * returns a list of points for the given bone - * @param mesh - * @param boneIndex - * @param offset - * @param link - * @return - */ - private List getPoints(Mesh mesh, int boneIndex, Vector3f offset) { - - FloatBuffer vertices = mesh.getFloatBuffer(Type.Position); - ByteBuffer boneIndices = (ByteBuffer) mesh.getBuffer(Type.BoneIndex).getData(); - FloatBuffer boneWeight = (FloatBuffer) mesh.getBuffer(Type.BoneWeight).getData(); - - vertices.rewind(); - boneIndices.rewind(); - boneWeight.rewind(); - - ArrayList results = new ArrayList(); - - int vertexComponents = mesh.getVertexCount() * 3; - - for (int i = 0; i < vertexComponents; i += 3) { - int k; - boolean add = false; - int start = i / 3 * 4; - for (k = start; k < start + 4; k++) { - if (boneIndices.get(k) == boneIndex && boneWeight.get(k) >= weightThreshold) { - add = true; - break; - } - } - if (add) { - - Vector3f pos = new Vector3f(); - pos.x = vertices.get(i); - pos.y = vertices.get(i + 1); - pos.z = vertices.get(i + 2); - pos.subtractLocal(offset).multLocal(initScale); - results.add(pos.x); - results.add(pos.y); - results.add(pos.z); - - } - } - - return results; - } - protected void removeFromPhysicsSpace() { if (space == null) { return; @@ -818,28 +691,7 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision assert vars.unlock(); for (Bone bone : skeleton.getRoots()) { - setUserControl(bone, mode == Mode.Ragdoll); - } - } - - /** - * Set the control into Kinematic mode - * In theis mode, the collision shapes follow the movements of the skeleton, - * and can interact with physical environement - */ - public void setKinematicMode() { - if (mode != Mode.Kinetmatic) { - setMode(Mode.Kinetmatic); - } - } - - /** - * Sets the control into Ragdoll mode - * The skeleton is entirely controlled by physics. - */ - public void setRagdollMode() { - if (mode != Mode.Ragdoll) { - setMode(Mode.Ragdoll); + RagdollUtils.setUserControl(bone, mode == Mode.Ragdoll); } } @@ -883,16 +735,30 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision assert vars.unlock(); for (Bone bone : skeleton.getRoots()) { - setUserControl(bone, false); + RagdollUtils.setUserControl(bone, false); } blendStart = 0; } - private void setUserControl(Bone bone, boolean bool) { - bone.setUserControl(bool); - for (Bone child : bone.getChildren()) { - setUserControl(child, bool); + /** + * Set the control into Kinematic mode + * In theis mode, the collision shapes follow the movements of the skeleton, + * and can interact with physical environement + */ + public void setKinematicMode() { + if (mode != Mode.Kinetmatic) { + setMode(Mode.Kinetmatic); + } + } + + /** + * Sets the control into Ragdoll mode + * The skeleton is entirely controlled by physics. + */ + public void setRagdollMode() { + if (mode != Mode.Ragdoll) { + setMode(Mode.Ragdoll); } } @@ -915,18 +781,6 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision listeners.add(listener); } - protected static class PhysicsBoneLink { - - Bone bone; - Quaternion initalWorldRotation; - SixDofJoint joint; - PhysicsRigidBody rigidBody; - Vector3f pivotA; - Vector3f pivotB; - Quaternion startBlendingRot = new Quaternion(); - Vector3f startBlendingPos = new Vector3f(); - } - public void setRootMass(float rootMass) { this.rootMass = rootMass; } diff --git a/engine/src/jbullet/com/jme3/bullet/control/ragdoll/RagdollUtils.java b/engine/src/jbullet/com/jme3/bullet/control/ragdoll/RagdollUtils.java new file mode 100644 index 000000000..7aeb3a901 --- /dev/null +++ b/engine/src/jbullet/com/jme3/bullet/control/ragdoll/RagdollUtils.java @@ -0,0 +1,273 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package com.jme3.bullet.control.ragdoll; + +import com.jme3.animation.Bone; +import com.jme3.animation.Skeleton; +import com.jme3.bullet.collision.shapes.HullCollisionShape; +import com.jme3.bullet.joints.SixDofJoint; +import com.jme3.math.Quaternion; +import com.jme3.math.Transform; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.VertexBuffer.Type; +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * + * @author Nehon + */ +public class RagdollUtils { + + public static void setJointLimit(SixDofJoint joint, float maxX, float minX, float maxY, float minY, float maxZ, float minZ) { + + joint.getRotationalLimitMotor(0).setHiLimit(maxX); + joint.getRotationalLimitMotor(0).setLoLimit(minX); + joint.getRotationalLimitMotor(1).setHiLimit(maxY); + joint.getRotationalLimitMotor(1).setLoLimit(minY); + joint.getRotationalLimitMotor(2).setHiLimit(maxZ); + joint.getRotationalLimitMotor(2).setLoLimit(minZ); + } + + public static Map> buildPointMap(Spatial model) { + + + Map> map = new HashMap>(); + if (model instanceof Geometry) { + Geometry g = (Geometry) model; + buildPointMapForMesh(g.getMesh(), map); + } else if (model instanceof Node) { + Node node = (Node) model; + for (Spatial s : node.getChildren()) { + if (s instanceof Geometry) { + Geometry g = (Geometry) s; + buildPointMapForMesh(g.getMesh(), map); + } + } + } + return map; + } + + private static Map> buildPointMapForMesh(Mesh mesh, Map> map) { + + FloatBuffer vertices = mesh.getFloatBuffer(Type.Position); + ByteBuffer boneIndices = (ByteBuffer) mesh.getBuffer(Type.BoneIndex).getData(); + FloatBuffer boneWeight = (FloatBuffer) mesh.getBuffer(Type.BoneWeight).getData(); + + vertices.rewind(); + boneIndices.rewind(); + boneWeight.rewind(); + + int vertexComponents = mesh.getVertexCount() * 3; + int k, start, index; + float maxWeight = 0; + + for (int i = 0; i < vertexComponents; i += 3) { + + + start = i / 3 * 4; + index = 0; + maxWeight = -1; + for (k = start; k < start + 4; k++) { + float weight = boneWeight.get(k); + if (weight > maxWeight) { + maxWeight = weight; + index = boneIndices.get(k); + } + } + List points = map.get(index); + if (points == null) { + points = new ArrayList(); + map.put(index, points); + } + points.add(vertices.get(i)); + points.add(vertices.get(i + 1)); + points.add(vertices.get(i + 2)); + } + return map; + } + + /** + * Create a hull collision shape from linked vertices to this bone. + * Vertices have to be previoulsly gathered in a map using buildPointMap method + * @param link + * @param model + * @return + */ + public static HullCollisionShape makeShapeFromPointMap(Map> pointsMap, List boneIndices, Vector3f initialScale, Vector3f initialPosition) { + + ArrayList points = new ArrayList(); + for (Integer index : boneIndices) { + List l = pointsMap.get(index); + if (l != null) { + + for (int i = 0; i < l.size(); i += 3) { + Vector3f pos = new Vector3f(); + pos.x = l.get(i); + pos.y = l.get(i + 1); + pos.z = l.get(i + 2); + pos.subtractLocal(initialPosition).multLocal(initialScale); + points.add(pos.x); + points.add(pos.y); + points.add(pos.z); + } + } + } + + float[] p = new float[points.size()]; + for (int i = 0; i < points.size(); i++) { + p[i] = points.get(i); + } + + + return new HullCollisionShape(p); + } + + //retruns the list of bone indices of the given bone and its child(if they are not in the boneList) + public static List getBoneIndices(Bone bone, Skeleton skeleton, Set boneList) { + List list = new LinkedList(); + if (boneList.isEmpty()) { + list.add(skeleton.getBoneIndex(bone)); + } else { + list.add(skeleton.getBoneIndex(bone)); + for (Bone chilBone : bone.getChildren()) { + if (!boneList.contains(chilBone.getName())) { + list.addAll(getBoneIndices(chilBone, skeleton, boneList)); + } + } + } + return list; + } + + /** + * Create a hull collision shape from linked vertices to this bone. + * + * @param link + * @param model + * @return + */ + public static HullCollisionShape makeShapeFromVerticeWeights(Spatial model, List boneIndices, Vector3f initialScale, Vector3f initialPosition, float weightThreshold) { + + ArrayList points = new ArrayList(); + if (model instanceof Geometry) { + Geometry g = (Geometry) model; + for (Integer index : boneIndices) { + points.addAll(getPoints(g.getMesh(), index, initialScale, initialPosition, weightThreshold)); + } + } else if (model instanceof Node) { + Node node = (Node) model; + for (Spatial s : node.getChildren()) { + if (s instanceof Geometry) { + Geometry g = (Geometry) s; + for (Integer index : boneIndices) { + points.addAll(getPoints(g.getMesh(), index, initialScale, initialPosition, weightThreshold)); + } + + } + } + } + float[] p = new float[points.size()]; + for (int i = 0; i < points.size(); i++) { + p[i] = points.get(i); + } + + + return new HullCollisionShape(p); + } + + /** + * returns a list of points for the given bone + * @param mesh + * @param boneIndex + * @param offset + * @param link + * @return + */ + private static List getPoints(Mesh mesh, int boneIndex, Vector3f initialScale, Vector3f offset, float weightThreshold) { + + FloatBuffer vertices = mesh.getFloatBuffer(Type.Position); + ByteBuffer boneIndices = (ByteBuffer) mesh.getBuffer(Type.BoneIndex).getData(); + FloatBuffer boneWeight = (FloatBuffer) mesh.getBuffer(Type.BoneWeight).getData(); + + vertices.rewind(); + boneIndices.rewind(); + boneWeight.rewind(); + + ArrayList results = new ArrayList(); + + int vertexComponents = mesh.getVertexCount() * 3; + + for (int i = 0; i < vertexComponents; i += 3) { + int k; + boolean add = false; + int start = i / 3 * 4; + for (k = start; k < start + 4; k++) { + if (boneIndices.get(k) == boneIndex && boneWeight.get(k) >= weightThreshold) { + add = true; + break; + } + } + if (add) { + + Vector3f pos = new Vector3f(); + pos.x = vertices.get(i); + pos.y = vertices.get(i + 1); + pos.z = vertices.get(i + 2); + pos.subtractLocal(offset).multLocal(initialScale); + results.add(pos.x); + results.add(pos.y); + results.add(pos.z); + + } + } + + return results; + } + + /** + * Updates a bone position and rotation. + * if the child bones are not in the bone list this means, they are not associated with a physic shape. + * So they have to be updated + * @param bone the bone + * @param pos the position + * @param rot the rotation + */ + public static void setTransform(Bone bone, Vector3f pos, Quaternion rot, boolean restoreBoneControl, Set boneList) { + //we ensure that we have the control + if (restoreBoneControl) { + bone.setUserControl(true); + } + //we set te user transforms of the bone + bone.setUserTransformsWorld(pos, rot); + for (Bone childBone : bone.getChildren()) { + //each child bone that is not in the list is updated + if (!boneList.contains(childBone.getName())) { + Transform t = childBone.getCombinedTransform(pos, rot); + setTransform(childBone, t.getTranslation(), t.getRotation(), restoreBoneControl, boneList); + } + } + //we give back the control to the keyframed animation + if (restoreBoneControl) { + bone.setUserControl(false); + } + } + + public static void setUserControl(Bone bone, boolean bool) { + bone.setUserControl(bool); + for (Bone child : bone.getChildren()) { + setUserControl(child, bool); + } + } +} diff --git a/engine/src/test/jme3test/bullet/TestBoneRagdoll.java b/engine/src/test/jme3test/bullet/TestBoneRagdoll.java index 36afbc75e..f78c9f3ab 100644 --- a/engine/src/test/jme3test/bullet/TestBoneRagdoll.java +++ b/engine/src/test/jme3test/bullet/TestBoneRagdoll.java @@ -39,7 +39,6 @@ import com.jme3.animation.LoopMode; import com.jme3.bullet.BulletAppState; import com.jme3.app.SimpleApplication; import com.jme3.asset.TextureKey; -import com.jme3.bounding.BoundingBox; import com.jme3.bullet.PhysicsSpace; import com.jme3.bullet.collision.PhysicsCollisionEvent; import com.jme3.bullet.collision.PhysicsCollisionObject; @@ -102,7 +101,7 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi bullet.setTextureMode(TextureMode.Projected); bulletCollisionShape = new SphereCollisionShape(1.0f); - bulletAppState.getPhysicsSpace().enableDebug(assetManager); +// bulletAppState.getPhysicsSpace().enableDebug(assetManager); PhysicsTestHelper.createPhysicsTestWorld(rootNode, assetManager, bulletAppState.getPhysicsSpace()); setupLight(); @@ -161,13 +160,10 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi model.setLocalRotation(q); if (angles[0] < 0) { animChannel.setAnim("StandUpBack"); - // ragdoll.setKinematicMode(); ragdoll.blendToKinematicMode(0.5f); } else { animChannel.setAnim("StandUpFront"); ragdoll.blendToKinematicMode(0.5f); - // ragdoll.setKinematicMode(); - } } @@ -179,15 +175,12 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi bulletSize -= 0.1f; } - if (name.equals("shoot") && isPressed) { -// bulletSize = 0; - } - if (name.equals("stop") && isPressed) { - // bulletAppState.setEnabled(!bulletAppState.isEnabled()); + if (name.equals("stop") && isPressed) { ragdoll.setEnabled(!ragdoll.isEnabled()); ragdoll.setRagdollMode(); } + if (name.equals("shoot") && !isPressed) { Geometry bulletg = new Geometry("bullet", bullet); bulletg.setMaterial(matBullet); @@ -208,8 +201,8 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi bulletg.setLocalScale(bulletSize); bulletCollisionShape = new SphereCollisionShape(bulletSize); BombControl bulletNode = new BombControl(assetManager, bulletCollisionShape, 1); - bulletNode.setForceFactor(10); - bulletNode.setExplosionRadius(30); + bulletNode.setForceFactor(8); + bulletNode.setExplosionRadius(20); bulletNode.setCcdMotionThreshold(0.001f); bulletNode.setLinearVelocity(cam.getDirection().mult(180)); bulletg.addControl(bulletNode); @@ -285,7 +278,6 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi ragdoll.addBoneName("Hand.R"); ragdoll.addBoneName("Hand.L"); ragdoll.addBoneName("Neck"); - // ragdoll.addBoneName("Head"); ragdoll.addBoneName("Root"); ragdoll.addBoneName("Stomach"); ragdoll.addBoneName("Waist"); @@ -309,7 +301,7 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi @Override public void simpleUpdate(float tpf) { - // System.out.println(((BoundingBox) model.getWorldBound()).getYExtent()); + // System.out.println(((BoundingBox) model.getWorldBound()).getYExtent()); // elTime += tpf; // if (elTime > 3) { // elTime = 0; -- 2.11.0