KinematicRagdollControl :
- Made a lot of clean up and optimization - Better automagic creation of the ragdoll git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7379 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
This commit is contained in:
parent
f72d5c20fd
commit
4d1d9edc29
@ -31,12 +31,10 @@
|
|||||||
*/
|
*/
|
||||||
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;
|
||||||
@ -47,6 +45,7 @@ import com.jme3.bullet.collision.PhysicsCollisionObject;
|
|||||||
import com.jme3.bullet.collision.RagdollCollisionListener;
|
import com.jme3.bullet.collision.RagdollCollisionListener;
|
||||||
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
|
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
|
||||||
import com.jme3.bullet.collision.shapes.HullCollisionShape;
|
import com.jme3.bullet.collision.shapes.HullCollisionShape;
|
||||||
|
import com.jme3.bullet.control.ragdoll.RagdollUtils;
|
||||||
import com.jme3.bullet.joints.SixDofJoint;
|
import com.jme3.bullet.joints.SixDofJoint;
|
||||||
import com.jme3.bullet.objects.PhysicsRigidBody;
|
import com.jme3.bullet.objects.PhysicsRigidBody;
|
||||||
import com.jme3.export.JmeExporter;
|
import com.jme3.export.JmeExporter;
|
||||||
@ -56,22 +55,18 @@ import com.jme3.math.Transform;
|
|||||||
import com.jme3.math.Vector3f;
|
import com.jme3.math.Vector3f;
|
||||||
import com.jme3.renderer.RenderManager;
|
import com.jme3.renderer.RenderManager;
|
||||||
import com.jme3.renderer.ViewPort;
|
import com.jme3.renderer.ViewPort;
|
||||||
import com.jme3.scene.Geometry;
|
|
||||||
import com.jme3.scene.Mesh;
|
|
||||||
import com.jme3.scene.Node;
|
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.control.Control;
|
import com.jme3.scene.control.Control;
|
||||||
import com.jme3.util.TempVars;
|
import com.jme3.util.TempVars;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.FloatBuffer;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeSet;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@ -114,7 +109,7 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision
|
|||||||
protected boolean enabled = true;
|
protected boolean enabled = true;
|
||||||
protected boolean debug = false;
|
protected boolean debug = false;
|
||||||
protected PhysicsRigidBody baseRigidBody;
|
protected PhysicsRigidBody baseRigidBody;
|
||||||
protected float weightThreshold = 1.0f;
|
protected float weightThreshold = -1.0f;
|
||||||
protected Spatial targetModel;
|
protected Spatial targetModel;
|
||||||
protected Vector3f initScale;
|
protected Vector3f initScale;
|
||||||
protected Mode mode = Mode.Kinetmatic;
|
protected Mode mode = Mode.Kinetmatic;
|
||||||
@ -124,19 +119,29 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision
|
|||||||
protected List<RagdollCollisionListener> listeners;
|
protected List<RagdollCollisionListener> listeners;
|
||||||
protected float eventDispatchImpulseThreshold = 10;
|
protected float eventDispatchImpulseThreshold = 10;
|
||||||
protected RagdollPreset preset = new HumanoidRagdollPreset();
|
protected RagdollPreset preset = new HumanoidRagdollPreset();
|
||||||
protected List<String> boneList = new LinkedList<String>();
|
protected Set<String> boneList = new TreeSet<String>();
|
||||||
protected Vector3f modelPosition = new Vector3f();
|
protected Vector3f modelPosition = new Vector3f();
|
||||||
protected Quaternion modelRotation = new Quaternion();
|
protected Quaternion modelRotation = new Quaternion();
|
||||||
protected float rootMass = 15;
|
protected float rootMass = 15;
|
||||||
protected float totalMass = 0;
|
protected float totalMass = 0;
|
||||||
protected boolean added = false;
|
protected boolean added = false;
|
||||||
|
|
||||||
public enum Mode {
|
public static enum Mode {
|
||||||
|
|
||||||
Kinetmatic,
|
Kinetmatic,
|
||||||
Ragdoll
|
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
|
* contruct a KinematicRagdollControl
|
||||||
*/
|
*/
|
||||||
@ -206,7 +211,7 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision
|
|||||||
} else {
|
} else {
|
||||||
//boneList is not empty, this means some bones of the skeleton might not be associated with a collision shape.
|
//boneList is not empty, this means some bones of the skeleton might not be associated with a collision shape.
|
||||||
//So we update them recusively
|
//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.
|
//we give control back to the key framed animation.
|
||||||
link.bone.setUserControl(false);
|
link.bone.setUserControl(false);
|
||||||
} else {
|
} 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;
|
blendStart += tpf;
|
||||||
if (blendStart > blendTime) {
|
if (blendStart > blendTime) {
|
||||||
blendedControl = false;
|
blendedControl = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -260,35 +264,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.
|
* 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
|
* this is used to make the ragdoll follow the skeleton motion while in Kinematic mode
|
||||||
@ -309,16 +284,17 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision
|
|||||||
link.rigidBody.setPhysicsLocation(position);
|
link.rigidBody.setPhysicsLocation(position);
|
||||||
link.rigidBody.setPhysicsRotation(tmpRot1);
|
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) {
|
public Control cloneForSpatial(Spatial spatial) {
|
||||||
throw new UnsupportedOperationException("Not supported yet.");
|
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);
|
setSpatial(targetModel);
|
||||||
addToPhysicsSpace();
|
addToPhysicsSpace();
|
||||||
}
|
}
|
||||||
@ -367,12 +343,21 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision
|
|||||||
logger.log(Level.INFO, "Created physics ragdoll for skeleton {0}", skeleton);
|
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) {
|
public void addBoneName(String name) {
|
||||||
boneList.add(name);
|
boneList.add(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void scanSpatial(Spatial model) {
|
private void scanSpatial(Spatial model) {
|
||||||
AnimControl animControl = model.getControl(AnimControl.class);
|
AnimControl animControl = model.getControl(AnimControl.class);
|
||||||
|
Map<Integer, List<Float>> pointsMap = null;
|
||||||
|
if (weightThreshold == -1.0f) {
|
||||||
|
pointsMap = RagdollUtils.buildPointMap(model);
|
||||||
|
}
|
||||||
|
|
||||||
skeleton = animControl.getSkeleton();
|
skeleton = animControl.getSkeleton();
|
||||||
skeleton.resetAndUpdate();
|
skeleton.resetAndUpdate();
|
||||||
@ -382,19 +367,29 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision
|
|||||||
logger.log(Level.INFO, "Found root bone in skeleton {0}", skeleton);
|
logger.log(Level.INFO, "Found root bone in skeleton {0}", skeleton);
|
||||||
baseRigidBody = new PhysicsRigidBody(new BoxCollisionShape(Vector3f.UNIT_XYZ.mult(0.1f)), 1);
|
baseRigidBody = new PhysicsRigidBody(new BoxCollisionShape(Vector3f.UNIT_XYZ.mult(0.1f)), 1);
|
||||||
baseRigidBody.setKinematic(mode == Mode.Kinetmatic);
|
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<Integer, List<Float>> pointsMap) {
|
||||||
PhysicsRigidBody parentShape = parent;
|
PhysicsRigidBody parentShape = parent;
|
||||||
if (boneList.isEmpty() || boneList.contains(bone.getName())) {
|
if (boneList.isEmpty() || boneList.contains(bone.getName())) {
|
||||||
|
|
||||||
PhysicsBoneLink link = new PhysicsBoneLink();
|
PhysicsBoneLink link = new PhysicsBoneLink();
|
||||||
link.bone = bone;
|
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);
|
shapeNode.setKinematic(mode == Mode.Kinetmatic);
|
||||||
totalMass += rootMass / (float) reccount;
|
totalMass += rootMass / (float) reccount;
|
||||||
|
|
||||||
@ -408,12 +403,7 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision
|
|||||||
bone.getModelSpacePosition().subtract(bone.getParent().getModelSpacePosition(), posToParent).multLocal(initScale);
|
bone.getModelSpacePosition().subtract(bone.getParent().getModelSpacePosition(), posToParent).multLocal(initScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Joint local position from parent
|
SixDofJoint joint = new SixDofJoint(parent, shapeNode, posToParent, new Vector3f(0, 0, 0f), true);
|
||||||
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);
|
|
||||||
preset.setupJointForBone(bone.getName(), joint);
|
preset.setupJointForBone(bone.getName(), joint);
|
||||||
|
|
||||||
link.joint = joint;
|
link.joint = joint;
|
||||||
@ -426,10 +416,8 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision
|
|||||||
|
|
||||||
for (Iterator<Bone> it = bone.getChildren().iterator(); it.hasNext();) {
|
for (Iterator<Bone> it = bone.getChildren().iterator(); it.hasNext();) {
|
||||||
Bone childBone = it.next();
|
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) {
|
public void setJointLimit(String boneName, float maxX, float minX, float maxY, float minY, float maxZ, float minZ) {
|
||||||
PhysicsBoneLink link = boneLinks.get(boneName);
|
PhysicsBoneLink link = boneLinks.get(boneName);
|
||||||
if (link != null) {
|
if (link != null) {
|
||||||
setJointLimit(link.joint, maxX, minX, maxY, minY, maxZ, minZ);
|
RagdollUtils.setJointLimit(link.joint, maxX, minX, maxY, minY, maxZ, minZ);
|
||||||
} else {
|
} else {
|
||||||
logger.log(Level.WARNING, "Not joint was found for bone {0}. make sure you call spatial.addControl(ragdoll) before setting joints limit", boneName);
|
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() {
|
private void clearData() {
|
||||||
boneLinks.clear();
|
boneLinks.clear();
|
||||||
baseRigidBody = null;
|
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<Integer> boneIndices = null;
|
|
||||||
if (boneList.isEmpty()) {
|
|
||||||
boneIndices = new LinkedList<Integer>();
|
|
||||||
boneIndices.add(skeleton.getBoneIndex(bone));
|
|
||||||
} else {
|
|
||||||
boneIndices = getBoneIndices(bone, skeleton);
|
|
||||||
}
|
|
||||||
|
|
||||||
ArrayList<Float> points = new ArrayList<Float>();
|
|
||||||
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<Integer> getBoneIndices(Bone bone, Skeleton skeleton) {
|
|
||||||
List<Integer> list = new LinkedList<Integer>();
|
|
||||||
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<Float> 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<Float> results = new ArrayList<Float>();
|
|
||||||
|
|
||||||
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() {
|
protected void removeFromPhysicsSpace() {
|
||||||
if (space == null) {
|
if (space == null) {
|
||||||
return;
|
return;
|
||||||
@ -818,28 +691,7 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision
|
|||||||
assert vars.unlock();
|
assert vars.unlock();
|
||||||
|
|
||||||
for (Bone bone : skeleton.getRoots()) {
|
for (Bone bone : skeleton.getRoots()) {
|
||||||
setUserControl(bone, mode == Mode.Ragdoll);
|
RagdollUtils.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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -883,16 +735,30 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision
|
|||||||
assert vars.unlock();
|
assert vars.unlock();
|
||||||
|
|
||||||
for (Bone bone : skeleton.getRoots()) {
|
for (Bone bone : skeleton.getRoots()) {
|
||||||
setUserControl(bone, false);
|
RagdollUtils.setUserControl(bone, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
blendStart = 0;
|
blendStart = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setUserControl(Bone bone, boolean bool) {
|
/**
|
||||||
bone.setUserControl(bool);
|
* Set the control into Kinematic mode
|
||||||
for (Bone child : bone.getChildren()) {
|
* In theis mode, the collision shapes follow the movements of the skeleton,
|
||||||
setUserControl(child, bool);
|
* 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);
|
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) {
|
public void setRootMass(float rootMass) {
|
||||||
this.rootMass = rootMass;
|
this.rootMass = rootMass;
|
||||||
}
|
}
|
||||||
|
@ -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<Integer, List<Float>> buildPointMap(Spatial model) {
|
||||||
|
|
||||||
|
|
||||||
|
Map<Integer, List<Float>> map = new HashMap<Integer, List<Float>>();
|
||||||
|
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<Integer, List<Float>> buildPointMapForMesh(Mesh mesh, Map<Integer, List<Float>> 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<Float> points = map.get(index);
|
||||||
|
if (points == null) {
|
||||||
|
points = new ArrayList<Float>();
|
||||||
|
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<Integer, List<Float>> pointsMap, List<Integer> boneIndices, Vector3f initialScale, Vector3f initialPosition) {
|
||||||
|
|
||||||
|
ArrayList<Float> points = new ArrayList<Float>();
|
||||||
|
for (Integer index : boneIndices) {
|
||||||
|
List<Float> 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<Integer> getBoneIndices(Bone bone, Skeleton skeleton, Set<String> boneList) {
|
||||||
|
List<Integer> list = new LinkedList<Integer>();
|
||||||
|
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<Integer> boneIndices, Vector3f initialScale, Vector3f initialPosition, float weightThreshold) {
|
||||||
|
|
||||||
|
ArrayList<Float> points = new ArrayList<Float>();
|
||||||
|
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<Float> 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<Float> results = new ArrayList<Float>();
|
||||||
|
|
||||||
|
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<String> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -39,7 +39,6 @@ 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;
|
||||||
import com.jme3.bounding.BoundingBox;
|
|
||||||
import com.jme3.bullet.PhysicsSpace;
|
import com.jme3.bullet.PhysicsSpace;
|
||||||
import com.jme3.bullet.collision.PhysicsCollisionEvent;
|
import com.jme3.bullet.collision.PhysicsCollisionEvent;
|
||||||
import com.jme3.bullet.collision.PhysicsCollisionObject;
|
import com.jme3.bullet.collision.PhysicsCollisionObject;
|
||||||
@ -102,7 +101,7 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi
|
|||||||
bullet.setTextureMode(TextureMode.Projected);
|
bullet.setTextureMode(TextureMode.Projected);
|
||||||
bulletCollisionShape = new SphereCollisionShape(1.0f);
|
bulletCollisionShape = new SphereCollisionShape(1.0f);
|
||||||
|
|
||||||
bulletAppState.getPhysicsSpace().enableDebug(assetManager);
|
// bulletAppState.getPhysicsSpace().enableDebug(assetManager);
|
||||||
PhysicsTestHelper.createPhysicsTestWorld(rootNode, assetManager, bulletAppState.getPhysicsSpace());
|
PhysicsTestHelper.createPhysicsTestWorld(rootNode, assetManager, bulletAppState.getPhysicsSpace());
|
||||||
setupLight();
|
setupLight();
|
||||||
|
|
||||||
@ -161,13 +160,10 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi
|
|||||||
model.setLocalRotation(q);
|
model.setLocalRotation(q);
|
||||||
if (angles[0] < 0) {
|
if (angles[0] < 0) {
|
||||||
animChannel.setAnim("StandUpBack");
|
animChannel.setAnim("StandUpBack");
|
||||||
// ragdoll.setKinematicMode();
|
|
||||||
ragdoll.blendToKinematicMode(0.5f);
|
ragdoll.blendToKinematicMode(0.5f);
|
||||||
} else {
|
} else {
|
||||||
animChannel.setAnim("StandUpFront");
|
animChannel.setAnim("StandUpFront");
|
||||||
ragdoll.blendToKinematicMode(0.5f);
|
ragdoll.blendToKinematicMode(0.5f);
|
||||||
// ragdoll.setKinematicMode();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -179,15 +175,12 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi
|
|||||||
bulletSize -= 0.1f;
|
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.setEnabled(!ragdoll.isEnabled());
|
||||||
ragdoll.setRagdollMode();
|
ragdoll.setRagdollMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name.equals("shoot") && !isPressed) {
|
if (name.equals("shoot") && !isPressed) {
|
||||||
Geometry bulletg = new Geometry("bullet", bullet);
|
Geometry bulletg = new Geometry("bullet", bullet);
|
||||||
bulletg.setMaterial(matBullet);
|
bulletg.setMaterial(matBullet);
|
||||||
@ -208,8 +201,8 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi
|
|||||||
bulletg.setLocalScale(bulletSize);
|
bulletg.setLocalScale(bulletSize);
|
||||||
bulletCollisionShape = new SphereCollisionShape(bulletSize);
|
bulletCollisionShape = new SphereCollisionShape(bulletSize);
|
||||||
BombControl bulletNode = new BombControl(assetManager, bulletCollisionShape, 1);
|
BombControl bulletNode = new BombControl(assetManager, bulletCollisionShape, 1);
|
||||||
bulletNode.setForceFactor(10);
|
bulletNode.setForceFactor(8);
|
||||||
bulletNode.setExplosionRadius(30);
|
bulletNode.setExplosionRadius(20);
|
||||||
bulletNode.setCcdMotionThreshold(0.001f);
|
bulletNode.setCcdMotionThreshold(0.001f);
|
||||||
bulletNode.setLinearVelocity(cam.getDirection().mult(180));
|
bulletNode.setLinearVelocity(cam.getDirection().mult(180));
|
||||||
bulletg.addControl(bulletNode);
|
bulletg.addControl(bulletNode);
|
||||||
@ -285,7 +278,6 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi
|
|||||||
ragdoll.addBoneName("Hand.R");
|
ragdoll.addBoneName("Hand.R");
|
||||||
ragdoll.addBoneName("Hand.L");
|
ragdoll.addBoneName("Hand.L");
|
||||||
ragdoll.addBoneName("Neck");
|
ragdoll.addBoneName("Neck");
|
||||||
// ragdoll.addBoneName("Head");
|
|
||||||
ragdoll.addBoneName("Root");
|
ragdoll.addBoneName("Root");
|
||||||
ragdoll.addBoneName("Stomach");
|
ragdoll.addBoneName("Stomach");
|
||||||
ragdoll.addBoneName("Waist");
|
ragdoll.addBoneName("Waist");
|
||||||
@ -309,7 +301,7 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void simpleUpdate(float tpf) {
|
public void simpleUpdate(float tpf) {
|
||||||
// System.out.println(((BoundingBox) model.getWorldBound()).getYExtent());
|
// System.out.println(((BoundingBox) model.getWorldBound()).getYExtent());
|
||||||
// elTime += tpf;
|
// elTime += tpf;
|
||||||
// if (elTime > 3) {
|
// if (elTime > 3) {
|
||||||
// elTime = 0;
|
// elTime = 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user