diff --git a/engine/src/core/com/jme3/animation/Bone.java b/engine/src/core/com/jme3/animation/Bone.java index 15438d21b..b242e4d5d 100644 --- a/engine/src/core/com/jme3/animation/Bone.java +++ b/engine/src/core/com/jme3/animation/Bone.java @@ -235,7 +235,7 @@ public final class Bone implements Savable { /** * Updates the world transforms for this bone, and, possibly the attach node if not null. */ - final void updateWorldVectors() { + public final void updateWorldVectors() { if (parent != null) { //rotation @@ -381,7 +381,16 @@ public final class Bone implements Savable { worldPos.set(translation); worldRot.set(rotation); } - + + protected Vector3f tmpVec=new Vector3f(); + protected Quaternion tmpQuat=new Quaternion(); + public Quaternion getTmpQuat() { + return tmpQuat; + } + public Vector3f getTmpVec() { + return tmpVec; + } + /** * Returns the attachment node. * Attach models and effects to this node to make diff --git a/engine/src/core/com/jme3/scene/Spatial.java b/engine/src/core/com/jme3/scene/Spatial.java index f22b73a45..2475b4f87 100644 --- a/engine/src/core/com/jme3/scene/Spatial.java +++ b/engine/src/core/com/jme3/scene/Spatial.java @@ -150,8 +150,8 @@ public abstract class Spatial implements Savable, Cloneable, Collidable { refreshFlags |= RF_BOUND; } - - /** + + /** * Constructor instantiates a new Spatial object setting the * rotation, translation and scale value to defaults. * @@ -487,7 +487,7 @@ public abstract class Spatial implements Savable, Cloneable, Collidable { } private void runControlUpdate(float tpf) { - if (controls.size() == 0) { + if (controls.isEmpty()) { return; } @@ -507,7 +507,7 @@ public abstract class Spatial implements Savable, Cloneable, Collidable { * @see Spatial#getControl(java.lang.Class) */ public void runControlRender(RenderManager rm, ViewPort vp) { - if (controls.size() == 0) { + if (controls.isEmpty()) { return; } diff --git a/engine/src/core/com/jme3/util/TempVars.java b/engine/src/core/com/jme3/util/TempVars.java index ebd828a3d..7bc569c53 100644 --- a/engine/src/core/com/jme3/util/TempVars.java +++ b/engine/src/core/com/jme3/util/TempVars.java @@ -167,6 +167,7 @@ public class TempVars { * General quaternions. */ public final Quaternion quat1 = new Quaternion(); + public final Quaternion quat2 = new Quaternion(); /** * Eigen diff --git a/engine/src/jbullet/com/jme3/bullet/control/RagdollControl.java b/engine/src/jbullet/com/jme3/bullet/control/RagdollControl.java index 3c755eedc..b242fb5a4 100644 --- a/engine/src/jbullet/com/jme3/bullet/control/RagdollControl.java +++ b/engine/src/jbullet/com/jme3/bullet/control/RagdollControl.java @@ -1,5 +1,7 @@ package com.jme3.bullet.control; +import com.jme3.bullet.control.radoll.RagdollPreset; +import com.jme3.bullet.control.radoll.HumanoidRagdollPreset; import com.jme3.animation.AnimControl; import com.jme3.animation.Bone; import com.jme3.animation.Skeleton; @@ -12,12 +14,10 @@ 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.joints.PhysicsJoint; import com.jme3.bullet.joints.SixDofJoint; import com.jme3.bullet.objects.PhysicsRigidBody; import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; -import com.jme3.math.FastMath; import com.jme3.math.Quaternion; import com.jme3.math.Vector3f; import com.jme3.renderer.RenderManager; @@ -35,6 +35,7 @@ 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.logging.Level; @@ -61,6 +62,7 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener protected float eventDispatchImpulseThreshold = 10; protected float eventDiscardImpulseThreshold = 3; protected RagdollPreset preset = new HumanoidRagdollPreset(); + protected List boneList = new LinkedList(); public RagdollControl() { } @@ -78,6 +80,8 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener if (control) { Quaternion q2 = vars.quat1; + Quaternion q3 = vars.quat2; + Vector3f p2 = vars.vect2; // skeleton.reset(); for (PhysicsBoneLink link : boneLinks.values()) { @@ -101,9 +105,12 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener } - link.bone.setUserControl(true); - link.bone.setUserTransformsWorld(position, q2); - + if (boneList.isEmpty()) { + link.bone.setUserControl(true); + link.bone.setUserTransformsWorld(position, q2); + } else { + setTransform(link.bone, position, q2); + } } @@ -112,6 +119,9 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener for (PhysicsBoneLink link : boneLinks.values()) { //the ragdoll does not control the skeleton link.bone.setUserControl(false); + if (!link.rigidBody.isKinematic()) { + link.rigidBody.setKinematic(true); + } Vector3f position = vars.vect1; Quaternion rotation = vars.quat1; @@ -134,6 +144,21 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener } + private void setTransform(Bone bone, Vector3f pos, Quaternion rot) { + bone.setUserControl(true); + bone.setUserTransformsWorld(pos, rot); + for (Bone childBone : bone.getChildren()) { + if (!boneList.contains(childBone.getName())) { + Vector3f tmpVec = childBone.getTmpVec(); + Quaternion tmpQuat = childBone.getTmpQuat(); + rot.mult(childBone.getLocalPosition(), tmpVec).addLocal(pos); + tmpQuat.set(rot).multLocal(childBone.getLocalRotation()); + setTransform(childBone, tmpVec, tmpQuat); + + } + } + } + public Control cloneForSpatial(Spatial spatial) { throw new UnsupportedOperationException("Not supported yet."); } @@ -165,7 +190,7 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener // maybe dont reset to ragdoll out of animations? scanSpatial(model); - + if (parent != null) { parent.attachChild(model); @@ -178,7 +203,7 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener } public void addBoneName(String name) { - throw new UnsupportedOperationException("Not supported yet."); + boneList.add(name); } private void scanSpatial(Spatial model) { @@ -204,53 +229,60 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener } private void boneRecursion(Spatial model, Bone bone, PhysicsRigidBody parent, int reccount) { - - //get world space position of the bone - Vector3f pos = bone.getModelSpacePosition().add(model.getLocalTranslation()); + PhysicsRigidBody parentShape = parent; + if (boneList.isEmpty() || boneList.contains(bone.getName())) { + //get world space position of the bone + Vector3f pos = bone.getModelSpacePosition().add(model.getLocalTranslation()); // Quaternion rot = bone.getModelSpaceRotation().mult(initRotation); - //creating the collision shape from the bone's associated vertices - PhysicsRigidBody shapeNode = new PhysicsRigidBody(makeShape(bone, model), 10.0f / (float) reccount); + //creating the collision shape from the bone's associated vertices + PhysicsRigidBody shapeNode = new PhysicsRigidBody(makeShape(bone, model), 10.0f / (float) reccount); - // shapeNode.setPhysicsRotation(rot); + // shapeNode.setPhysicsRotation(rot); - PhysicsBoneLink link = new PhysicsBoneLink(); - link.bone = bone; - link.rigidBody = shapeNode; - link.initalWorldRotation = bone.getModelSpaceRotation().clone(); - // link.mass = 10.0f / (float) reccount; + PhysicsBoneLink link = new PhysicsBoneLink(); + link.bone = bone; + link.rigidBody = shapeNode; - //TODO: ragdoll mass 1 - if (parent != null) { - //get joint position for parent - Vector3f posToParent = new Vector3f(); - if (bone.getParent() != null) { - bone.getModelSpacePosition().subtract(bone.getParent().getModelSpacePosition(), posToParent); - } + link.initalWorldRotation = bone.getModelSpaceRotation().clone(); + // link.mass = 10.0f / (float) reccount; - //Joint local position from parent - link.pivotA = posToParent; - //joint local position from current bone - link.pivotB = new Vector3f(0, 0, 0f); + //TODO: ragdoll mass 1 + if (parent != null) { + //get joint position for parent + Vector3f posToParent = new Vector3f(); + if (bone.getParent() != null) { + bone.getModelSpacePosition().subtract(bone.getParent().getModelSpacePosition(), posToParent); + } + + //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); - //TODO find a way to correctly compute/import joints (maybe based on their names) - preset.setupJointForBone(bone.getName(), joint); - //setJointLimit(joint, 0, 0, 0, 0, 0, 0); + SixDofJoint joint = new SixDofJoint(parent, shapeNode, link.pivotA, link.pivotB, true); + joint.getTranslationalLimitMotor().setUpperLimit(new Vector3f(0, 0, 0)); + joint.getTranslationalLimitMotor().setLowerLimit(new Vector3f(0, 0, 0)); + //TODO find a way to correctly compute/import joints (maybe based on their names) + preset.setupJointForBone(bone.getName(), joint); + //setJointLimit(joint, 0, 0, 0, 0, 0, 0); - link.joint = joint; - joint.setCollisionBetweenLinkedBodys(false); + link.joint = joint; + joint.setCollisionBetweenLinkedBodys(false); + } + boneLinks.put(bone.getName(), link); + shapeNode.setUserObject(link); + parentShape = shapeNode; } - boneLinks.put(bone.getName(), link); - shapeNode.setUserObject(link); for (Iterator it = bone.getChildren().iterator(); it.hasNext();) { Bone childBone = it.next(); - boneRecursion(model, childBone, shapeNode, reccount++); + boneRecursion(model, childBone, parentShape, reccount++); } + } /** @@ -323,17 +355,31 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener } private HullCollisionShape makeShape(Bone bone, Spatial model) { - int boneIndex = skeleton.getBoneIndex(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; - points.addAll(getPoints(g.getMesh(), boneIndex, bone.getModelSpacePosition())); + 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; - points.addAll(getPoints(g.getMesh(), boneIndex, bone.getModelSpacePosition())); + for (Integer index : boneIndices) { + points.addAll(getPoints(g.getMesh(), index, bone.getModelSpacePosition())); + } + } } } @@ -345,6 +391,17 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener return new HullCollisionShape(p); } + private 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; + } + protected List getPoints(Mesh mesh, int boneIndex, Vector3f offset) { FloatBuffer vertices = mesh.getFloatBuffer(Type.Position); @@ -529,10 +586,22 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener this.control = control; for (PhysicsBoneLink link : boneLinks.values()) { - link.bone.setUserControl(control); + // link.bone.setUserControl(control); link.rigidBody.setKinematic(!control); } + + for (Bone bone : skeleton.getRoots()) { + setUserControl(bone, control); + } + + } + + private void setUserControl(Bone bone, boolean bool) { + bone.setUserControl(bool); + for (Bone child : bone.getChildren()) { + setUserControl(child, bool); + } } public boolean hasControl() { diff --git a/engine/src/jbullet/com/jme3/bullet/control/HumanoidRagdollPreset.java b/engine/src/jbullet/com/jme3/bullet/control/radoll/HumanoidRagdollPreset.java similarity index 98% rename from engine/src/jbullet/com/jme3/bullet/control/HumanoidRagdollPreset.java rename to engine/src/jbullet/com/jme3/bullet/control/radoll/HumanoidRagdollPreset.java index c3455760c..3d9207081 100644 --- a/engine/src/jbullet/com/jme3/bullet/control/HumanoidRagdollPreset.java +++ b/engine/src/jbullet/com/jme3/bullet/control/radoll/HumanoidRagdollPreset.java @@ -2,7 +2,7 @@ * To change this template, choose Tools | Templates * and open the template in the editor. */ -package com.jme3.bullet.control; +package com.jme3.bullet.control.radoll; import com.jme3.math.FastMath; diff --git a/engine/src/jbullet/com/jme3/bullet/control/RagdollPreset.java b/engine/src/jbullet/com/jme3/bullet/control/radoll/RagdollPreset.java similarity index 98% rename from engine/src/jbullet/com/jme3/bullet/control/RagdollPreset.java rename to engine/src/jbullet/com/jme3/bullet/control/radoll/RagdollPreset.java index 415b719fa..460cfc369 100644 --- a/engine/src/jbullet/com/jme3/bullet/control/RagdollPreset.java +++ b/engine/src/jbullet/com/jme3/bullet/control/radoll/RagdollPreset.java @@ -2,7 +2,7 @@ * To change this template, choose Tools | Templates * and open the template in the editor. */ -package com.jme3.bullet.control; +package com.jme3.bullet.control.radoll; import com.jme3.bullet.joints.SixDofJoint; import java.util.HashMap; diff --git a/engine/src/test/jme3test/bullet/TestBoneRagdoll.java b/engine/src/test/jme3test/bullet/TestBoneRagdoll.java index 359a3711a..368907991 100644 --- a/engine/src/test/jme3test/bullet/TestBoneRagdoll.java +++ b/engine/src/test/jme3test/bullet/TestBoneRagdoll.java @@ -91,11 +91,11 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi bulletAppState = new BulletAppState(); bulletAppState.setEnabled(true); stateManager.attach(bulletAppState); - // bulletAppState.getPhysicsSpace().enableDebug(assetManager); + //bulletAppState.getPhysicsSpace().enableDebug(assetManager); PhysicsTestHelper.createPhysicsTestWorld(rootNode, assetManager, bulletAppState.getPhysicsSpace()); setupLight(); - model = (Node) assetManager.loadModel("Models/Oto/Oto.mesh.xml"); + model = (Node) assetManager.loadModel("Models/Sinbad/Sinbad.mesh.xml"); // model.setLocalTranslation(5, 0, 5); // model.setLocalRotation(new Quaternion().fromAngleAxis(FastMath.HALF_PI, Vector3f.UNIT_X)); @@ -109,24 +109,26 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi skeletonDebug.setLocalTranslation(model.getLocalTranslation()); //Note: PhysicsRagdollControl is still TODO, constructor will change - ragdoll = new RagdollControl(1.0f); + ragdoll = new RagdollControl(0.7f); + setupSinbad(ragdoll); ragdoll.addCollisionListener(this); model.addControl(ragdoll); float eighth_pi = FastMath.PI * 0.125f; //Oto's head is almost rigid - ragdoll.setJointLimit("head", 0, 0, eighth_pi, -eighth_pi, 0, 0); + // ragdoll.setJointLimit("head", 0, 0, eighth_pi, -eighth_pi, 0, 0); getPhysicsSpace().add(ragdoll); speed = 1.3f; rootNode.attachChild(model); + // rootNode.attachChild(skeletonDebug); flyCam.setMoveSpeed(50); final AnimChannel channel = control.createChannel(); - channel.setAnim("Walk"); + channel.setAnim("Dance"); inputManager.addListener(new ActionListener() { @@ -137,6 +139,10 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi if (name.equals("shoot") && isPressed) { timer = 0; + } + if (name.equals("stop") && isPressed) { + bulletAppState.setEnabled(!bulletAppState.isEnabled()); + } if (name.equals("shoot") && !isPressed) { Geometry bulletg = new Geometry("bullet", bullet); @@ -144,7 +150,7 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi bulletg.setLocalTranslation(cam.getLocation()); bulletg.setLocalScale(timer); bulletCollisionShape = new SphereCollisionShape(timer); - // RigidBodyControl bulletNode = new BombControl(assetManager, bulletCollisionShape, 1); + // RigidBodyControl bulletNode = new BombControl(assetManager, bulletCollisionShape, 1); RigidBodyControl bulletNode = new RigidBodyControl(bulletCollisionShape, timer * 10); bulletNode.setCcdMotionThreshold(0.001f); bulletNode.setLinearVelocity(cam.getDirection().mult(80)); @@ -155,16 +161,17 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi } } - }, "toggle", "shoot"); + }, "toggle", "shoot","stop"); inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_SPACE)); inputManager.addMapping("shoot", new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); + inputManager.addMapping("stop", new KeyTrigger(KeyInput.KEY_H)); } private void setupLight() { AmbientLight al = new AmbientLight(); - // al.setColor(ColorRGBA.White.mult(1)); - // rootNode.addLight(al); + // al.setColor(ColorRGBA.White.mult(1)); + // rootNode.addLight(al); DirectionalLight dl = new DirectionalLight(); dl.setDirection(new Vector3f(-0.1f, -0.7f, -1).normalizeLocal()); @@ -208,22 +215,115 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi public void collide(Bone bone, PhysicsCollisionObject object) { - if(object.getUserObject()!=null && object.getUserObject() instanceof Geometry){ - Geometry geom=(Geometry)object.getUserObject(); - if ("Floor".equals(geom.getName())) { + if (object.getUserObject() != null && object.getUserObject() instanceof Geometry) { + Geometry geom = (Geometry) object.getUserObject(); + if ("Floor".equals(geom.getName())) { return; } } - - + + if (!ragdoll.hasControl()) { - // bulletTime(); + //bulletTime(); ragdoll.setControl(true); } } + private void setupSinbad(RagdollControl ragdoll) { + ragdoll.addBoneName("Ulna.L"); + ragdoll.addBoneName("Ulna.R"); + ragdoll.addBoneName("Chest"); + ragdoll.addBoneName("Foot.L"); + ragdoll.addBoneName("Foot.R"); + ragdoll.addBoneName("Hand.R"); + ragdoll.addBoneName("Hand.L"); + ragdoll.addBoneName("Neck"); + ragdoll.addBoneName("Head"); + ragdoll.addBoneName("Root"); + ragdoll.addBoneName("Stomach"); + ragdoll.addBoneName("Waist"); + ragdoll.addBoneName("Humerus.L"); + ragdoll.addBoneName("Humerus.R"); + ragdoll.addBoneName("Thigh.L"); + ragdoll.addBoneName("Thigh.R"); + ragdoll.addBoneName("Calf.L"); + ragdoll.addBoneName("Calf.R"); + ragdoll.addBoneName("Clavicle.L"); + ragdoll.addBoneName("Clavicle.R"); + +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// + + } + private void bulletTime() { speed = 0.1f; elTime = 0;