- WIP Sinbad Ragdoll can now stand up after beeing whacked

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7309 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
rem..om 14 years ago
parent ea9e60d099
commit 2f1f2e7e54
  1. 91
      engine/src/jbullet/com/jme3/bullet/control/RagdollControl.java
  2. 108
      engine/src/test/jme3test/bullet/TestBoneRagdoll.java

@ -31,10 +31,12 @@
*/ */
package com.jme3.bullet.control; package com.jme3.bullet.control;
import com.jme3.animation.AnimChannel;
import com.jme3.bullet.control.ragdoll.RagdollPreset; import com.jme3.bullet.control.ragdoll.RagdollPreset;
import com.jme3.bullet.control.ragdoll.HumanoidRagdollPreset; import com.jme3.bullet.control.ragdoll.HumanoidRagdollPreset;
import com.jme3.animation.AnimControl; import com.jme3.animation.AnimControl;
import com.jme3.animation.Bone; import com.jme3.animation.Bone;
import com.jme3.animation.LoopMode;
import com.jme3.animation.Skeleton; import com.jme3.animation.Skeleton;
import com.jme3.animation.SkeletonControl; import com.jme3.animation.SkeletonControl;
import com.jme3.asset.AssetManager; import com.jme3.asset.AssetManager;
@ -90,12 +92,16 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
protected Spatial targetModel; protected Spatial targetModel;
protected Vector3f initScale; protected Vector3f initScale;
protected boolean control = false; protected boolean control = false;
protected boolean blendedControl = false;
protected float blendTime = 1.0f;
protected float blendStart = 0.0f;
protected List<RagdollCollisionListener> listeners; protected List<RagdollCollisionListener> listeners;
protected float eventDispatchImpulseThreshold = 10; protected float eventDispatchImpulseThreshold = 10;
protected float eventDiscardImpulseThreshold = 3; protected float eventDiscardImpulseThreshold = 3;
protected RagdollPreset preset = new HumanoidRagdollPreset(); protected RagdollPreset preset = new HumanoidRagdollPreset();
protected List<String> boneList = new LinkedList<String>(); protected List<String> boneList = new LinkedList<String>();
protected Vector3f modelPosition = new Vector3f(); protected Vector3f modelPosition = new Vector3f();
protected Quaternion modelRotation = new Quaternion();
protected float rootMass = 15; protected float rootMass = 15;
private float totalMass = 0; private float totalMass = 0;
@ -121,11 +127,12 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
} }
TempVars vars = TempVars.get(); TempVars vars = TempVars.get();
assert vars.lock(); assert vars.lock();
if (control) {
Quaternion q2 = vars.quat1; Quaternion q2 = vars.quat1;
Quaternion q3 = vars.quat2; Quaternion q3 = vars.quat2;
if (control) {
for (PhysicsBoneLink link : boneLinks.values()) { for (PhysicsBoneLink link : boneLinks.values()) {
Vector3f p = link.rigidBody.getMotionState().getWorldLocation(); Vector3f p = link.rigidBody.getMotionState().getWorldLocation();
@ -140,7 +147,9 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
q2.normalize(); q2.normalize();
if (link.bone.getParent() == null) { if (link.bone.getParent() == null) {
modelPosition.set(p).subtractLocal(link.bone.getInitialPos()); modelPosition.set(p).subtractLocal(link.bone.getInitialPos());
modelRotation.set(q).multLocal(link.bone.getInitialRot().inverse());
targetModel.setLocalTranslation(modelPosition); targetModel.setLocalTranslation(modelPosition);
targetModel.setLocalRotation(modelRotation);
link.bone.setUserControl(true); link.bone.setUserControl(true);
link.bone.setUserTransformsWorld(position, q2); link.bone.setUserTransformsWorld(position, q2);
@ -154,6 +163,8 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
} }
} }
} else { } else {
for (PhysicsBoneLink link : boneLinks.values()) { for (PhysicsBoneLink link : boneLinks.values()) {
//the ragdoll does not control the skeleton //the ragdoll does not control the skeleton
link.bone.setUserControl(false); link.bone.setUserControl(false);
@ -161,6 +172,32 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
link.rigidBody.setKinematic(true); link.rigidBody.setKinematic(true);
} }
if (blendedControl) {
Vector3f position = vars.vect1.set(link.startBlendingPos);
Vector3f position2 = vars.vect2;
q2.set(link.startBlendingRot);
q3.set(q2).slerp(link.bone.getModelSpaceRotation(), blendStart / blendTime);
position2.set(position).interpolate(link.bone.getModelSpacePosition(), blendStart / blendTime);
q2.set(q3);
position.set(position2);
if (boneList.isEmpty()) {
link.bone.setUserControl(true);
link.bone.setUserTransformsWorld(position, q2);
} else {
setTransform(link.bone, position, q2);
}
}
Vector3f position = vars.vect1; Vector3f position = vars.vect1;
Quaternion rotation = vars.quat1; Quaternion rotation = vars.quat1;
@ -175,6 +212,14 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
link.rigidBody.setPhysicsLocation(position); link.rigidBody.setPhysicsLocation(position);
link.rigidBody.setPhysicsRotation(rotation); link.rigidBody.setPhysicsRotation(rotation);
} }
if (blendedControl) {
blendStart += tpf;
if (blendStart > blendTime) {
blendedControl = false;
}
}
} }
@ -191,6 +236,7 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
setTransform(childBone, t.getTranslation(), t.getRotation()); setTransform(childBone, t.getTranslation(), t.getRotation());
} }
} }
bone.setUserControl(false);
} }
public Control cloneForSpatial(Spatial spatial) { public Control cloneForSpatial(Spatial spatial) {
@ -615,6 +661,44 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
} }
public void blendControlToAnim(String anim, AnimChannel channel) {
blendedControl = true;
control = false;
AnimControl animControl = targetModel.getControl(AnimControl.class);
animControl.setEnabled(true);
channel.setAnim(anim, 0);
channel.setLoopMode(LoopMode.DontLoop);
TempVars vars = TempVars.get();
assert vars.lock();
//this.control = control;
for (PhysicsBoneLink link : boneLinks.values()) {
Vector3f p = link.rigidBody.getMotionState().getWorldLocation();
Vector3f position = vars.vect1;
targetModel.getWorldTransform().transformInverseVector(p, position);
Quaternion q = link.rigidBody.getMotionState().getWorldRotationQuat();
Quaternion q2 = vars.quat1;
Quaternion q3 = vars.quat2;
q2.set(q).multLocal(link.initalWorldRotation).normalize();
q3.set(targetModel.getWorldRotation()).inverseLocal().mult(q2, q2);
q2.normalize();
link.startBlendingPos.set(position);
link.startBlendingRot.set(q2);
link.rigidBody.setKinematic(true);
}
assert vars.unlock();
for (Bone bone : skeleton.getRoots()) {
setUserControl(bone, false);
}
blendStart = 0;
}
private void setUserControl(Bone bone, boolean bool) { private void setUserControl(Bone bone, boolean bool) {
bone.setUserControl(bool); bone.setUserControl(bool);
for (Bone child : bone.getChildren()) { for (Bone child : bone.getChildren()) {
@ -643,7 +727,8 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
PhysicsRigidBody rigidBody; PhysicsRigidBody rigidBody;
Vector3f pivotA; Vector3f pivotA;
Vector3f pivotB; Vector3f pivotB;
float volume = 0; Quaternion startBlendingRot = new Quaternion();
Vector3f startBlendingPos = new Vector3f();
} }
public void setRootMass(float rootMass) { public void setRootMass(float rootMass) {

@ -33,7 +33,9 @@ package jme3test.bullet;
import com.jme3.animation.AnimChannel; import com.jme3.animation.AnimChannel;
import com.jme3.animation.AnimControl; import com.jme3.animation.AnimControl;
import com.jme3.animation.AnimEventListener;
import com.jme3.animation.Bone; import com.jme3.animation.Bone;
import com.jme3.animation.LoopMode;
import com.jme3.bullet.BulletAppState; import com.jme3.bullet.BulletAppState;
import com.jme3.app.SimpleApplication; import com.jme3.app.SimpleApplication;
import com.jme3.asset.TextureKey; import com.jme3.asset.TextureKey;
@ -57,6 +59,7 @@ import com.jme3.light.DirectionalLight;
import com.jme3.material.Material; import com.jme3.material.Material;
import com.jme3.math.ColorRGBA; import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath; import com.jme3.math.FastMath;
import com.jme3.math.Matrix3f;
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;
@ -70,7 +73,7 @@ import com.jme3.texture.Texture;
* PHYSICS RAGDOLLS ARE NOT WORKING PROPERLY YET! * PHYSICS RAGDOLLS ARE NOT WORKING PROPERLY YET!
* @author normenhansen * @author normenhansen
*/ */
public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisionListener { public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisionListener, AnimEventListener{
private BulletAppState bulletAppState; private BulletAppState bulletAppState;
Material matBullet; Material matBullet;
@ -135,13 +138,26 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi
animChannel = control.createChannel(); animChannel = control.createChannel();
animChannel.setAnim("Dance"); animChannel.setAnim("Dance");
control.addListener(this);
inputManager.addListener(new ActionListener() { inputManager.addListener(new ActionListener() {
public void onAction(String name, boolean isPressed, float tpf) { public void onAction(String name, boolean isPressed, float tpf) {
if (name.equals("toggle") && isPressed) { if (name.equals("toggle") && isPressed) {
ragdoll.setControl(false);
model.setLocalTranslation(0, 0, 0); Vector3f v=new Vector3f();
v.set(model.getLocalTranslation());
v.y=0;
model.setLocalTranslation(v);
Quaternion q=new Quaternion();
float[] angles=new float[3];
model.getLocalRotation().toAngles(angles);
q.fromAngleAxis(angles[1], Vector3f.UNIT_Y);
//q.lookAt(model.getLocalRotation().toRotationMatrix().getColumn(2), Vector3f.UNIT_Y);
model.setLocalRotation(q);
// animChannel.setAnim("StandUpBack");
ragdoll.blendControlToAnim("StandUpFront",animChannel);
// animChannel.setAnim("StandUpFront",0.00f);
} }
if (name.equals("bullet+") && isPressed) { if (name.equals("bullet+") && isPressed) {
bulletSize += 0.1f; bulletSize += 0.1f;
@ -166,7 +182,7 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi
bulletCollisionShape = new SphereCollisionShape(bulletSize); bulletCollisionShape = new SphereCollisionShape(bulletSize);
RigidBodyControl bulletNode = new RigidBodyControl(bulletCollisionShape, bulletSize * 10); RigidBodyControl bulletNode = new RigidBodyControl(bulletCollisionShape, bulletSize * 10);
bulletNode.setCcdMotionThreshold(0.001f); bulletNode.setCcdMotionThreshold(0.001f);
bulletNode.setLinearVelocity(cam.getDirection().mult(180)); bulletNode.setLinearVelocity(cam.getDirection().mult(80));
bulletg.addControl(bulletNode); bulletg.addControl(bulletNode);
rootNode.attachChild(bulletg); rootNode.attachChild(bulletg);
getPhysicsSpace().add(bulletNode); getPhysicsSpace().add(bulletNode);
@ -295,40 +311,60 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi
@Override @Override
public void simpleUpdate(float tpf) { public void simpleUpdate(float tpf) {
elTime += tpf; // elTime += tpf;
if (elTime > 3) { // if (elTime > 3) {
elTime = 0; // elTime = 0;
if (dance) { // if (dance) {
rotate.multLocal(direction); // rotate.multLocal(direction);
} // }
if (Math.random() > 0.80) { // if (Math.random() > 0.80) {
dance = true; // dance = true;
animChannel.setAnim("Dance"); // animChannel.setAnim("Dance");
} else { // } else {
dance = false; // dance = false;
animChannel.setAnim("RunBase"); // animChannel.setAnim("RunBase");
rotate.fromAngleAxis(FastMath.QUARTER_PI * ((float) Math.random() - 0.5f), Vector3f.UNIT_Y); // rotate.fromAngleAxis(FastMath.QUARTER_PI * ((float) Math.random() - 0.5f), Vector3f.UNIT_Y);
rotate.multLocal(direction); // rotate.multLocal(direction);
} // }
} // }
if (!ragdoll.hasControl() && !dance) { // if (!ragdoll.hasControl() && !dance) {
if (model.getLocalTranslation().getZ() < -10) { // if (model.getLocalTranslation().getZ() < -10) {
direction.z = 1; // direction.z = 1;
direction.normalizeLocal(); // direction.normalizeLocal();
} else if (model.getLocalTranslation().getZ() > 10) { // } else if (model.getLocalTranslation().getZ() > 10) {
direction.z = -1; // direction.z = -1;
direction.normalizeLocal(); // direction.normalizeLocal();
// }
// if (model.getLocalTranslation().getX() < -10) {
// direction.x = 1;
// direction.normalizeLocal();
// } else if (model.getLocalTranslation().getX() > 10) {
// direction.x = -1;
// direction.normalizeLocal();
// }
// model.move(direction.multLocal(tpf * 8));
// direction.normalizeLocal();
// model.lookAt(model.getLocalTranslation().add(direction), Vector3f.UNIT_Y);
// }
} }
if (model.getLocalTranslation().getX() < -10) {
direction.x = 1; public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) {
direction.normalizeLocal(); // if(channel.getAnimationName().equals("StandUpFront")){
} else if (model.getLocalTranslation().getX() > 10) { // channel.setAnim("Dance");
direction.x = -1; // }
direction.normalizeLocal();
if(channel.getAnimationName().equals("StandUpBack") || channel.getAnimationName().equals("StandUpFront")){
channel.setLoopMode(LoopMode.DontLoop);
channel.setAnim("IdleTop",5);
channel.setLoopMode(LoopMode.Loop);
} }
model.move(direction.multLocal(tpf * 8)); // if(channel.getAnimationName().equals("IdleTop")){
direction.normalizeLocal(); // channel.setAnim("StandUpFront");
model.lookAt(model.getLocalTranslation().add(direction), Vector3f.UNIT_Y); // }
} }
public void onAnimChange(AnimControl control, AnimChannel channel, String animName) {
} }
} }

Loading…
Cancel
Save