RagdollControl ---WIP----
- Automatic creation of the ragdoll collisions shapes - Changed TestBoneRagdoll (press space to activate physics, left click to shoot bombs) git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7151 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
This commit is contained in:
parent
4877b17cab
commit
50d55b7e59
@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
package com.jme3.animation;
|
package com.jme3.animation;
|
||||||
|
|
||||||
|
import com.jme3.bullet.control.RagdollControl;
|
||||||
import com.jme3.export.JmeExporter;
|
import com.jme3.export.JmeExporter;
|
||||||
import com.jme3.export.JmeImporter;
|
import com.jme3.export.JmeImporter;
|
||||||
import com.jme3.export.InputCapsule;
|
import com.jme3.export.InputCapsule;
|
||||||
@ -373,6 +374,13 @@ public final class AnimControl extends AbstractControl implements Savable, Clone
|
|||||||
return a.getLength();
|
return a.getLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private RagdollControl ragdoll=null;
|
||||||
|
|
||||||
|
public void setRagdoll(RagdollControl ragdoll) {
|
||||||
|
this.ragdoll = ragdoll;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void controlUpdate(float tpf) {
|
protected void controlUpdate(float tpf) {
|
||||||
resetToBind(); // reset morph meshes to bind pose
|
resetToBind(); // reset morph meshes to bind pose
|
||||||
@ -383,7 +391,11 @@ public final class AnimControl extends AbstractControl implements Savable, Clone
|
|||||||
}
|
}
|
||||||
|
|
||||||
skeleton.updateWorldVectors();
|
skeleton.updateWorldVectors();
|
||||||
// here update the targets verticles if no hardware skinning supported
|
// here update the targets vertices if no hardware skinning supported
|
||||||
|
|
||||||
|
if(ragdoll!=null){
|
||||||
|
ragdoll.update(tpf);
|
||||||
|
}
|
||||||
|
|
||||||
Matrix4f[] offsetMatrices = skeleton.computeSkinningMatrices();
|
Matrix4f[] offsetMatrices = skeleton.computeSkinningMatrices();
|
||||||
|
|
||||||
|
@ -27,6 +27,11 @@ public class HullCollisionShape extends CollisionShape {
|
|||||||
createShape(this.points);
|
createShape(this.points);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public HullCollisionShape(float[] points) {
|
||||||
|
this.points = points;
|
||||||
|
createShape(this.points);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(JmeExporter ex) throws IOException {
|
public void write(JmeExporter ex) throws IOException {
|
||||||
super.write(ex);
|
super.write(ex);
|
||||||
@ -41,37 +46,36 @@ public class HullCollisionShape extends CollisionShape {
|
|||||||
InputCapsule capsule = im.getCapsule(this);
|
InputCapsule capsule = im.getCapsule(this);
|
||||||
|
|
||||||
// for backwards compatability
|
// for backwards compatability
|
||||||
Mesh mesh = (Mesh)capsule.readSavable("hullMesh", null);
|
Mesh mesh = (Mesh) capsule.readSavable("hullMesh", null);
|
||||||
if (mesh != null){
|
if (mesh != null) {
|
||||||
this.points = getPoints(mesh);
|
this.points = getPoints(mesh);
|
||||||
}else{
|
} else {
|
||||||
this.points = capsule.readFloatArray("points", null);
|
this.points = capsule.readFloatArray("points", null);
|
||||||
|
|
||||||
}
|
}
|
||||||
createShape(this.points);
|
createShape(this.points);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void createShape(float[] points){
|
protected void createShape(float[] points) {
|
||||||
ObjectArrayList<Vector3f> pointList = new ObjectArrayList<Vector3f>();
|
ObjectArrayList<Vector3f> pointList = new ObjectArrayList<Vector3f>();
|
||||||
for (int i = 0; i < points.length; i += 3) {
|
for (int i = 0; i < points.length; i += 3) {
|
||||||
pointList.add(new Vector3f(points[i], points[i+1], points[i+2]));
|
pointList.add(new Vector3f(points[i], points[i + 1], points[i + 2]));
|
||||||
}
|
}
|
||||||
cShape = new ConvexHullShape(pointList);
|
cShape = new ConvexHullShape(pointList);
|
||||||
cShape.setLocalScaling(Converter.convert(getScale()));
|
cShape.setLocalScaling(Converter.convert(getScale()));
|
||||||
cShape.setMargin(margin);
|
cShape.setMargin(margin);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected float[] getPoints(Mesh mesh){
|
protected float[] getPoints(Mesh mesh) {
|
||||||
FloatBuffer vertices = mesh.getFloatBuffer(Type.Position);
|
FloatBuffer vertices = mesh.getFloatBuffer(Type.Position);
|
||||||
vertices.rewind();
|
vertices.rewind();
|
||||||
int components = mesh.getVertexCount() * 3;
|
int components = mesh.getVertexCount() * 3;
|
||||||
float[] pointsArray = new float[components];
|
float[] pointsArray = new float[components];
|
||||||
for (int i = 0; i < components; i += 3) {
|
for (int i = 0; i < components; i += 3) {
|
||||||
pointsArray[i] = vertices.get();
|
pointsArray[i] = vertices.get();
|
||||||
pointsArray[i+1] = vertices.get();
|
pointsArray[i + 1] = vertices.get();
|
||||||
pointsArray[i+2] = vertices.get();
|
pointsArray[i + 2] = vertices.get();
|
||||||
}
|
}
|
||||||
return pointsArray;
|
return pointsArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -6,21 +6,28 @@ import com.jme3.animation.Skeleton;
|
|||||||
import com.jme3.asset.AssetManager;
|
import com.jme3.asset.AssetManager;
|
||||||
import com.jme3.bullet.PhysicsSpace;
|
import com.jme3.bullet.PhysicsSpace;
|
||||||
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
|
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
|
||||||
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
|
import com.jme3.bullet.collision.shapes.HullCollisionShape;
|
||||||
import com.jme3.bullet.joints.ConeJoint;
|
import com.jme3.bullet.joints.ConeJoint;
|
||||||
import com.jme3.bullet.joints.PhysicsJoint;
|
import com.jme3.bullet.joints.PhysicsJoint;
|
||||||
import com.jme3.bullet.objects.PhysicsRigidBody;
|
import com.jme3.bullet.objects.PhysicsRigidBody;
|
||||||
import com.jme3.export.JmeExporter;
|
import com.jme3.export.JmeExporter;
|
||||||
import com.jme3.export.JmeImporter;
|
import com.jme3.export.JmeImporter;
|
||||||
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.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.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.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
@ -38,42 +45,60 @@ public class RagdollControl implements PhysicsControl {
|
|||||||
protected boolean debug = false;
|
protected boolean debug = false;
|
||||||
protected Quaternion tmp_jointRotation = new Quaternion();
|
protected Quaternion tmp_jointRotation = new Quaternion();
|
||||||
protected PhysicsRigidBody baseRigidBody;
|
protected PhysicsRigidBody baseRigidBody;
|
||||||
|
protected float weightThreshold = 1.0f;
|
||||||
|
protected Spatial targetModel;
|
||||||
|
protected Vector3f initPosition;
|
||||||
|
protected Quaternion initRotation;
|
||||||
|
protected Vector3f initScale;
|
||||||
|
|
||||||
|
//Normen: Think you have the system you want, with movement
|
||||||
|
//Normen: but the rootBone movement and translation is also accessible like getRootBoneLocation()
|
||||||
|
//Normen: and you can disable the applying of it
|
||||||
|
//Normen: setApplyRootBoneMovement(false)
|
||||||
|
//Normen: when you add a RigidBodyControl..
|
||||||
|
//Normen: it does this in setSpatial:
|
||||||
|
//Normen: if (spatial.getcontrol(AnimControl.class)){animControl.setApplyRootBoneMovement(false)
|
||||||
|
//Normen: and instead reads the current location and sets it to the RigidBody
|
||||||
|
//Normen: simply said
|
||||||
|
//Normen: update(){setPhysicsLocation(animControl.getRootBoneLocation())
|
||||||
public RagdollControl() {
|
public RagdollControl() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RagdollControl(float weightThreshold) {
|
||||||
|
this.weightThreshold = weightThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
public void update(float tpf) {
|
public void update(float tpf) {
|
||||||
if (!enabled) {
|
if (!enabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TempVars vars = TempVars.get();
|
TempVars vars = TempVars.get();
|
||||||
assert vars.lock();
|
assert vars.lock();
|
||||||
|
Quaternion q2 = vars.quat1;
|
||||||
skeleton.reset();
|
// skeleton.reset();
|
||||||
for (PhysicsBoneLink link : boneLinks) {
|
for (PhysicsBoneLink link : boneLinks) {
|
||||||
|
|
||||||
|
// if(link.bone==skeleton.getRoots()[0]){
|
||||||
|
// Vector3f loc=vars.vect1;
|
||||||
|
// loc.set(baseRigidBody.getMotionState().getWorldLocation());//.subtractLocal(rootBoneInit);
|
||||||
|
// ((Geometry)targetModel).setLocalTranslation(loc);
|
||||||
|
//
|
||||||
|
// }
|
||||||
Vector3f p = link.rigidBody.getMotionState().getWorldLocation();
|
Vector3f p = link.rigidBody.getMotionState().getWorldLocation();
|
||||||
Quaternion q = link.rigidBody.getMotionState().getWorldRotationQuat();
|
Quaternion q = link.rigidBody.getMotionState().getWorldRotationQuat();
|
||||||
|
|
||||||
q.toAxes(vars.tri);
|
q2.set(q).multLocal(link.initalWorldRotation).normalize();
|
||||||
|
|
||||||
Vector3f dir = vars.tri[2];
|
link.bone.setUserTransformsWorld(p, q2);
|
||||||
float len = link.length;
|
|
||||||
|
|
||||||
Vector3f parentPos = new Vector3f(p).subtractLocal(dir.mult(len / 2f));
|
|
||||||
Vector3f childPos = new Vector3f(p).addLocal(dir.mult(len / 2f));
|
|
||||||
|
|
||||||
Quaternion q2 = q.clone();
|
|
||||||
Quaternion rot = new Quaternion();
|
|
||||||
rot.fromAngles(FastMath.HALF_PI, 0, 0);
|
|
||||||
q2.multLocal(rot);
|
|
||||||
q2.normalize();
|
|
||||||
|
|
||||||
link.parentBone.setUserTransformsWorld(parentPos, q2);
|
|
||||||
if (link.childBone.getChildren().size() == 0) {
|
|
||||||
link.childBone.setUserTransformsWorld(childPos, q2.clone());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
assert vars.unlock();
|
assert vars.unlock();
|
||||||
|
|
||||||
|
//baseRigidBody.getMotionState().applyTransform(targetModel);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Control cloneForSpatial(Spatial spatial) {
|
public Control cloneForSpatial(Spatial spatial) {
|
||||||
@ -81,6 +106,7 @@ public class RagdollControl implements PhysicsControl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setSpatial(Spatial model) {
|
public void setSpatial(Spatial model) {
|
||||||
|
targetModel = model;
|
||||||
removeFromPhysicsSpace();
|
removeFromPhysicsSpace();
|
||||||
clearData();
|
clearData();
|
||||||
// put into bind pose and compute bone transforms in model space
|
// put into bind pose and compute bone transforms in model space
|
||||||
@ -97,21 +123,28 @@ public class RagdollControl implements PhysicsControl {
|
|||||||
private void scanSpatial(Spatial model) {
|
private void scanSpatial(Spatial model) {
|
||||||
AnimControl animControl = model.getControl(AnimControl.class);
|
AnimControl animControl = model.getControl(AnimControl.class);
|
||||||
|
|
||||||
|
initPosition = model.getLocalTranslation();
|
||||||
|
initRotation = model.getLocalRotation();
|
||||||
|
initScale = model.getLocalScale();
|
||||||
|
|
||||||
skeleton = animControl.getSkeleton();
|
skeleton = animControl.getSkeleton();
|
||||||
skeleton.resetAndUpdate();
|
skeleton.resetAndUpdate();
|
||||||
for (int i = 0; i < skeleton.getBoneCount(); i++) {
|
for (int i = 0; i < skeleton.getRoots().length; i++) {
|
||||||
Bone childBone = skeleton.getBone(i);
|
Bone childBone = skeleton.getRoots()[i];
|
||||||
childBone.setUserControl(true);
|
childBone.setUserControl(true);
|
||||||
if (childBone.getParent() == null) {
|
if (childBone.getParent() == null) {
|
||||||
Vector3f parentPos = childBone.getModelSpacePosition().add(model.getWorldTranslation());
|
Vector3f parentPos = childBone.getModelSpacePosition().add(initPosition);
|
||||||
|
// Quaternion parentRot= childBone.getModelSpaceRotation().mult(initRotation);
|
||||||
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(.1f)), 1);
|
baseRigidBody = new PhysicsRigidBody(new BoxCollisionShape(Vector3f.UNIT_XYZ.mult(.1f)), 1);
|
||||||
baseRigidBody.setPhysicsLocation(parentPos);
|
baseRigidBody.setPhysicsLocation(parentPos);
|
||||||
|
// baseRigidBody.setPhysicsRotation(parentRot);
|
||||||
boneLinks = boneRecursion(model, childBone, baseRigidBody, boneLinks, 1);
|
boneLinks = boneRecursion(model, childBone, baseRigidBody, boneLinks, 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// BoneAnimation myAnimation = new BoneAnimation("boneAnimation", 1000000);
|
// BoneAnimation myAnimation = new BoneAnimation("boneAnimation", 1000000);
|
||||||
// myAnimation.setTracks(new BoneTrack[0]);
|
// myAnimation.setTracks(new BoneTrack[0]);
|
||||||
// animControl.addAnim(myAnimation);
|
// animControl.addAnim(myAnimation);
|
||||||
@ -120,52 +153,47 @@ public class RagdollControl implements PhysicsControl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private List<PhysicsBoneLink> boneRecursion(Spatial model, Bone bone, PhysicsRigidBody parent, List<PhysicsBoneLink> list, int reccount) {
|
private List<PhysicsBoneLink> boneRecursion(Spatial model, Bone bone, PhysicsRigidBody parent, List<PhysicsBoneLink> list, int reccount) {
|
||||||
ArrayList<Bone> children = bone.getChildren();
|
//Allow bone's transformation change outside of animation
|
||||||
bone.setUserControl(true);
|
bone.setUserControl(true);
|
||||||
for (Iterator<Bone> it = children.iterator(); it.hasNext();) {
|
|
||||||
Bone childBone = it.next();
|
|
||||||
Bone parentBone = bone;
|
|
||||||
Vector3f parentPos = parentBone.getModelSpacePosition().add(model.getWorldTranslation());
|
|
||||||
Vector3f childPos = childBone.getModelSpacePosition().add(model.getWorldTranslation());
|
|
||||||
//get location between the two bones (physicscapsule center)
|
|
||||||
Vector3f jointCenter = parentPos.add(childPos).multLocal(0.5f);
|
|
||||||
tmp_jointRotation.lookAt(childPos.subtract(parentPos), Vector3f.UNIT_Y);
|
|
||||||
// length of the joint
|
|
||||||
float height = parentPos.distance(childPos);
|
|
||||||
|
|
||||||
// TODO: joints act funny when bone is too thin??
|
//get world space position of the bone
|
||||||
float radius = height > 2f ? 0.4f : height * .2f;
|
Vector3f pos = bone.getModelSpacePosition().add(model.getLocalTranslation());
|
||||||
CapsuleCollisionShape shape = new CapsuleCollisionShape(radius, height - (radius), 2);
|
Quaternion rot= bone.getModelSpaceRotation().mult(initRotation);
|
||||||
|
|
||||||
PhysicsRigidBody shapeNode = new PhysicsRigidBody(shape, 10.0f / (float) reccount);
|
//creating the collision shape from the bone's associated vertices
|
||||||
shapeNode.setPhysicsLocation(jointCenter);
|
PhysicsRigidBody shapeNode = new PhysicsRigidBody(makeShape(bone, model), 10.0f / (float) reccount);
|
||||||
shapeNode.setPhysicsRotation(tmp_jointRotation.toRotationMatrix());
|
shapeNode.setPhysicsLocation(pos);
|
||||||
|
// shapeNode.setPhysicsRotation(rot);
|
||||||
|
|
||||||
PhysicsBoneLink link = new PhysicsBoneLink();
|
PhysicsBoneLink link = new PhysicsBoneLink();
|
||||||
link.parentBone = parentBone;
|
link.bone = bone;
|
||||||
link.childBone = childBone;
|
link.rigidBody = shapeNode;
|
||||||
link.rigidBody = shapeNode;
|
link.initalWorldRotation = bone.getModelSpaceRotation().clone();
|
||||||
link.length = height;
|
|
||||||
|
|
||||||
//TODO: ragdoll mass 1
|
//TODO: ragdoll mass 1
|
||||||
if (parent != null) {
|
if (parent != null) {
|
||||||
//get length of parent
|
//get joint position for parent
|
||||||
float parentHeight = 0.0f;
|
Vector3f posToParent = new Vector3f();
|
||||||
if (bone.getParent() != null) {
|
if (bone.getParent() != null) {
|
||||||
parentHeight = bone.getParent().getModelSpacePosition().add(model.getWorldTranslation()).distance(parentPos);
|
bone.getModelSpacePosition().subtract(bone.getParent().getModelSpacePosition(), posToParent);
|
||||||
}
|
|
||||||
//local position from parent
|
|
||||||
link.pivotA = new Vector3f(0, 0, (parentHeight * .5f));
|
|
||||||
//local position from child
|
|
||||||
link.pivotB = new Vector3f(0, 0, -(height * .5f));
|
|
||||||
|
|
||||||
ConeJoint joint = new ConeJoint(parent, shapeNode, link.pivotA, link.pivotB);
|
|
||||||
joint.setLimit(FastMath.HALF_PI, FastMath.HALF_PI, 0.01f);
|
|
||||||
|
|
||||||
link.joint = joint;
|
|
||||||
joint.setCollisionBetweenLinkedBodys(false);
|
|
||||||
}
|
}
|
||||||
list.add(link);
|
|
||||||
|
//Joint local position from parent
|
||||||
|
link.pivotA = posToParent;
|
||||||
|
//joint local position from current bone
|
||||||
|
link.pivotB = new Vector3f(0, 0, 0f);
|
||||||
|
|
||||||
|
ConeJoint joint = new ConeJoint(parent, shapeNode, link.pivotA, link.pivotB);
|
||||||
|
//TODO make joints editable by user or find a way to correctly compute/import them
|
||||||
|
joint.setLimit(FastMath.HALF_PI, FastMath.HALF_PI, 0.01f);
|
||||||
|
|
||||||
|
link.joint = joint;
|
||||||
|
joint.setCollisionBetweenLinkedBodys(false);
|
||||||
|
}
|
||||||
|
list.add(link);
|
||||||
|
|
||||||
|
for (Iterator<Bone> it = bone.getChildren().iterator(); it.hasNext();) {
|
||||||
|
Bone childBone = it.next();
|
||||||
boneRecursion(model, childBone, shapeNode, list, reccount++);
|
boneRecursion(model, childBone, shapeNode, list, reccount++);
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
@ -194,6 +222,67 @@ public class RagdollControl implements PhysicsControl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private HullCollisionShape makeShape(Bone bone, Spatial model) {
|
||||||
|
int boneIndex = skeleton.getBoneIndex(bone);
|
||||||
|
System.out.println(boneIndex);
|
||||||
|
ArrayList<Float> points = new ArrayList<Float>();
|
||||||
|
if (model instanceof Geometry) {
|
||||||
|
Geometry g = (Geometry) model;
|
||||||
|
points.addAll(getPoints(g.getMesh(), boneIndex, 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()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
float[] p = new float[points.size()];
|
||||||
|
for (int i = 0; i < points.size(); i++) {
|
||||||
|
p[i] = points.get(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new HullCollisionShape(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected 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);
|
||||||
|
results.add(pos.x);
|
||||||
|
results.add(pos.y);
|
||||||
|
results.add(pos.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
private void removeFromPhysicsSpace() {
|
private void removeFromPhysicsSpace() {
|
||||||
if (baseRigidBody != null) {
|
if (baseRigidBody != null) {
|
||||||
space.remove(baseRigidBody);
|
space.remove(baseRigidBody);
|
||||||
@ -214,9 +303,9 @@ public class RagdollControl implements PhysicsControl {
|
|||||||
|
|
||||||
public void setEnabled(boolean enabled) {
|
public void setEnabled(boolean enabled) {
|
||||||
this.enabled = enabled;
|
this.enabled = enabled;
|
||||||
if(!enabled&&space!=null){
|
if (!enabled && space != null) {
|
||||||
removeFromPhysicsSpace();
|
removeFromPhysicsSpace();
|
||||||
}else if(enabled && space!=null){
|
} else if (enabled && space != null) {
|
||||||
addToPhysicsSpace();
|
addToPhysicsSpace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -284,14 +373,13 @@ public class RagdollControl implements PhysicsControl {
|
|||||||
throw new UnsupportedOperationException("Not supported yet.");
|
throw new UnsupportedOperationException("Not supported yet.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class PhysicsBoneLink {
|
protected static class PhysicsBoneLink {
|
||||||
|
|
||||||
Bone childBone;
|
Bone bone;
|
||||||
Bone parentBone;
|
Quaternion initalWorldRotation;
|
||||||
PhysicsJoint joint;
|
PhysicsJoint joint;
|
||||||
PhysicsRigidBody rigidBody;
|
PhysicsRigidBody rigidBody;
|
||||||
Vector3f pivotA;
|
Vector3f pivotA;
|
||||||
Vector3f pivotB;
|
Vector3f pivotB;
|
||||||
float length;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,14 +35,31 @@ package jme3test.bullet;
|
|||||||
import com.jme3.animation.AnimControl;
|
import com.jme3.animation.AnimControl;
|
||||||
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.bullet.PhysicsSpace;
|
import com.jme3.bullet.PhysicsSpace;
|
||||||
|
import com.jme3.bullet.collision.shapes.SphereCollisionShape;
|
||||||
import com.jme3.bullet.control.RagdollControl;
|
import com.jme3.bullet.control.RagdollControl;
|
||||||
|
import com.jme3.bullet.control.RigidBodyControl;
|
||||||
|
import com.jme3.font.BitmapText;
|
||||||
|
import com.jme3.input.ChaseCamera;
|
||||||
|
import com.jme3.input.KeyInput;
|
||||||
|
import com.jme3.input.MouseInput;
|
||||||
|
import com.jme3.input.controls.ActionListener;
|
||||||
|
import com.jme3.input.controls.KeyTrigger;
|
||||||
|
import com.jme3.input.controls.MouseButtonTrigger;
|
||||||
import com.jme3.light.DirectionalLight;
|
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.Quaternion;
|
||||||
import com.jme3.math.Vector3f;
|
import com.jme3.math.Vector3f;
|
||||||
|
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
|
||||||
|
import com.jme3.scene.Geometry;
|
||||||
import com.jme3.scene.Node;
|
import com.jme3.scene.Node;
|
||||||
import com.jme3.scene.debug.SkeletonDebugger;
|
import com.jme3.scene.debug.SkeletonDebugger;
|
||||||
|
import com.jme3.scene.shape.Sphere;
|
||||||
|
import com.jme3.scene.shape.Sphere.TextureMode;
|
||||||
|
import com.jme3.texture.Texture;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PHYSICS RAGDOLLS ARE NOT WORKING PROPERLY YET!
|
* PHYSICS RAGDOLLS ARE NOT WORKING PROPERLY YET!
|
||||||
@ -51,6 +68,8 @@ import com.jme3.scene.debug.SkeletonDebugger;
|
|||||||
public class TestBoneRagdoll extends SimpleApplication {
|
public class TestBoneRagdoll extends SimpleApplication {
|
||||||
|
|
||||||
private BulletAppState bulletAppState;
|
private BulletAppState bulletAppState;
|
||||||
|
Material matBullet;
|
||||||
|
Node model;
|
||||||
|
|
||||||
public static void main(String[] args){
|
public static void main(String[] args){
|
||||||
TestBoneRagdoll app = new TestBoneRagdoll();
|
TestBoneRagdoll app = new TestBoneRagdoll();
|
||||||
@ -58,13 +77,18 @@ public class TestBoneRagdoll extends SimpleApplication {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void simpleInitApp() {
|
public void simpleInitApp() {
|
||||||
|
initCrossHairs();
|
||||||
|
initMaterial();
|
||||||
bulletAppState = new BulletAppState();
|
bulletAppState = new BulletAppState();
|
||||||
|
bulletAppState.setEnabled(false);
|
||||||
stateManager.attach(bulletAppState);
|
stateManager.attach(bulletAppState);
|
||||||
bulletAppState.getPhysicsSpace().enableDebug(assetManager);
|
bulletAppState.getPhysicsSpace().enableDebug(assetManager);
|
||||||
PhysicsTestHelper.createPhysicsTestWorld(rootNode, assetManager, bulletAppState.getPhysicsSpace());
|
PhysicsTestHelper.createPhysicsTestWorld(rootNode, assetManager, bulletAppState.getPhysicsSpace());
|
||||||
setupLight();
|
setupLight();
|
||||||
|
|
||||||
Node model = (Node) assetManager.loadModel("Models/Oto/Oto.mesh.xml");
|
model = (Node) assetManager.loadModel("Models/Oto/Oto.mesh.xml");
|
||||||
|
// model.setLocalTranslation(5,5,5);
|
||||||
|
// model.setLocalRotation(new Quaternion().fromAngleAxis(FastMath.HALF_PI, Vector3f.UNIT_X));
|
||||||
|
|
||||||
//debug view
|
//debug view
|
||||||
AnimControl control= model.getControl(AnimControl.class);
|
AnimControl control= model.getControl(AnimControl.class);
|
||||||
@ -73,18 +97,62 @@ public class TestBoneRagdoll extends SimpleApplication {
|
|||||||
mat2.setColor("Color", ColorRGBA.Green);
|
mat2.setColor("Color", ColorRGBA.Green);
|
||||||
mat2.getAdditionalRenderState().setDepthTest(false);
|
mat2.getAdditionalRenderState().setDepthTest(false);
|
||||||
skeletonDebug.setMaterial(mat2);
|
skeletonDebug.setMaterial(mat2);
|
||||||
|
skeletonDebug.setLocalTranslation(model.getLocalTranslation());
|
||||||
|
control.createChannel().setAnim("Dodge");
|
||||||
|
|
||||||
//Note: PhysicsRagdollControl is still TODO, constructor will change
|
//Note: PhysicsRagdollControl is still TODO, constructor will change
|
||||||
RagdollControl ragdoll = new RagdollControl();
|
RagdollControl ragdoll = new RagdollControl();
|
||||||
|
// ragdoll.setEnabled(true);
|
||||||
|
// ragdoll.attachDebugShape(assetManager);
|
||||||
|
|
||||||
model.addControl(ragdoll);
|
ragdoll.setSpatial(model);
|
||||||
getPhysicsSpace().add(ragdoll);
|
ragdoll.setPhysicsSpace(getPhysicsSpace());
|
||||||
speed = .2f;
|
control.setRagdoll(ragdoll);
|
||||||
|
|
||||||
|
// model.addControl(ragdoll);
|
||||||
|
// getPhysicsSpace().add(ragdoll);
|
||||||
|
speed = 1f;
|
||||||
|
|
||||||
rootNode.attachChild(model);
|
rootNode.attachChild(model);
|
||||||
rootNode.attachChild(skeletonDebug);
|
rootNode.attachChild(skeletonDebug);
|
||||||
|
flyCam.setEnabled(false);
|
||||||
|
// flyCam.setMoveSpeed(10);
|
||||||
|
ChaseCamera chaseCamera=new ChaseCamera(cam, inputManager);
|
||||||
|
model.addControl(chaseCamera);
|
||||||
|
|
||||||
|
inputManager.addListener(new ActionListener() {
|
||||||
|
|
||||||
|
public void onAction(String name, boolean isPressed, float tpf) {
|
||||||
|
if(name.equals("toggle") && isPressed){
|
||||||
|
bulletAppState.setEnabled(!bulletAppState.isEnabled());
|
||||||
|
}
|
||||||
|
if (name.equals("shoot") && !isPressed) {
|
||||||
|
Geometry bulletg = new Geometry("bullet", bullet);
|
||||||
|
bulletg.setMaterial(matBullet);
|
||||||
|
bulletg.setLocalTranslation(cam.getLocation());
|
||||||
|
RigidBodyControl bulletNode = new BombControl(assetManager, bulletCollisionShape, 1);
|
||||||
|
// RigidBodyControl bulletNode = new RigidBodyControl(bulletCollisionShape, 1);
|
||||||
|
bulletNode.setLinearVelocity(cam.getDirection().mult(60));
|
||||||
|
bulletg.addControl(bulletNode);
|
||||||
|
rootNode.attachChild(bulletg);
|
||||||
|
getPhysicsSpace().add(bulletNode);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, "toggle", "shoot");
|
||||||
|
inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_SPACE));
|
||||||
|
inputManager.addMapping("shoot", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void simpleUpdate(float tpf) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void setupLight() {
|
private void setupLight() {
|
||||||
DirectionalLight dl = new DirectionalLight();
|
DirectionalLight dl = new DirectionalLight();
|
||||||
dl.setDirection(new Vector3f(-0.1f, -0.7f, -1).normalizeLocal());
|
dl.setDirection(new Vector3f(-0.1f, -0.7f, -1).normalizeLocal());
|
||||||
@ -96,4 +164,41 @@ public class TestBoneRagdoll extends SimpleApplication {
|
|||||||
return bulletAppState.getPhysicsSpace();
|
return bulletAppState.getPhysicsSpace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Material mat;
|
||||||
|
|
||||||
|
Material mat3;
|
||||||
|
|
||||||
|
private static final Sphere bullet;
|
||||||
|
private static final SphereCollisionShape bulletCollisionShape;
|
||||||
|
|
||||||
|
static {
|
||||||
|
bullet = new Sphere(32, 32, 0.4f, true, false);
|
||||||
|
bullet.setTextureMode(TextureMode.Projected);
|
||||||
|
bulletCollisionShape = new SphereCollisionShape(0.4f);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void initMaterial() {
|
||||||
|
|
||||||
|
matBullet = new Material(assetManager, "Common/MatDefs/Misc/SimpleTextured.j3md");
|
||||||
|
TextureKey key2 = new TextureKey("Textures/Terrain/Rock/Rock.PNG");
|
||||||
|
key2.setGenerateMips(true);
|
||||||
|
Texture tex2 = assetManager.loadTexture(key2);
|
||||||
|
matBullet.setTexture("ColorMap", tex2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
protected void initCrossHairs() {
|
||||||
|
guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
|
||||||
|
BitmapText ch = new BitmapText(guiFont, false);
|
||||||
|
ch.setSize(guiFont.getCharSet().getRenderedSize() * 2);
|
||||||
|
ch.setText("+"); // crosshairs
|
||||||
|
ch.setLocalTranslation( // center
|
||||||
|
settings.getWidth() / 2 - guiFont.getCharSet().getRenderedSize() / 3 * 2,
|
||||||
|
settings.getHeight() / 2 + ch.getLineHeight() / 2, 0);
|
||||||
|
guiNode.attachChild(ch);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user