fix for issue #740 (#906)

accellbaker
Stephen Gold 6 years ago committed by GitHub
parent 1c5c5e85c0
commit 84a103fbe4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 67
      jme3-bullet/src/common/java/com/jme3/bullet/control/KinematicRagdollControl.java
  2. 46
      jme3-bullet/src/common/java/com/jme3/bullet/control/ragdoll/RagdollUtils.java

@ -43,11 +43,11 @@ import com.jme3.export.*;
import com.jme3.math.*;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.util.TempVars;
import com.jme3.util.clone.JmeCloneable;
import java.io.IOException;
import java.util.*;
import java.util.logging.Level;
@ -198,6 +198,7 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
* @param ex exporter (not null)
* @throws IOException from exporter
*/
@Override
public void write(JmeExporter ex) throws IOException {
OutputCapsule oc = ex.getCapsule(this);
oc.write(rigidBody, "rigidBody", null);
@ -215,6 +216,7 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
* @param im importer (not null)
* @throws IOException from importer
*/
@Override
public void read(JmeImporter im) throws IOException {
InputCapsule ic = im.getCapsule(this);
rigidBody = (PhysicsRigidBody) ic.readSavable("rigidBody", null);
@ -274,6 +276,7 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
*
* @param tpf the time interval between frames (in seconds, ≥0)
*/
@Override
public void update(float tpf) {
if (!enabled) {
return;
@ -334,15 +337,9 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
link.bone.setUserTransformsInModelSpace(position, tmpRot1);
} else {
//If boneList is empty, every bone has a collision shape,
//so we simply update the bone position.
if (boneList.isEmpty()) {
link.bone.setUserTransformsInModelSpace(position, tmpRot1);
} else {
//boneList is not empty, this means some bones of the skeleton might not be associated with a collision shape.
//So we update them recusively
RagdollUtils.setTransform(link.bone, position, tmpRot1, false, boneList);
}
//some bones of the skeleton might not be associated with a collision shape.
//So we update them recusively
RagdollUtils.setTransform(link.bone, position, tmpRot1, false, boneList);
}
}
vars.release();
@ -377,17 +374,8 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
tmpRot1.set(tmpRot2);
position.set(position2);
//updating bones transforms
if (boneList.isEmpty()) {
//we ensure we have the control to update the bone
link.bone.setUserControl(true);
link.bone.setUserTransformsInModelSpace(position, tmpRot1);
//we give control back to the key framed animation.
link.bone.setUserControl(false);
} else {
RagdollUtils.setTransform(link.bone, position, tmpRot1, true, boneList);
}
//update bone transforms
RagdollUtils.setTransform(link.bone, position, tmpRot1, true, boneList);
}
//setting skeleton transforms to the ragdoll
matchPhysicObjectToBone(link, position, tmpRot1);
@ -575,6 +563,22 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
model.removeControl(sc);
model.addControl(sc);
if (boneList.isEmpty()) {
// add all bones to the list
skeleton = sc.getSkeleton();
for (int boneI = 0; boneI < skeleton.getBoneCount(); boneI++) {
String boneName = skeleton.getBone(boneI).getName();
boneList.add(boneName);
}
}
// filter out bones without vertices
filterBoneList(sc);
if (boneList.isEmpty()) {
throw new IllegalArgumentException(
"No suitable bones were found in the model's skeleton.");
}
// put into bind pose and compute bone transforms in model space
// maybe don't reset to ragdoll out of animations?
scanSpatial(model);
@ -594,6 +598,25 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
logger.log(Level.FINE, "Created physics ragdoll for skeleton {0}", skeleton);
}
/**
* Remove any bones without vertices from the boneList, so that every hull
* shape will contain at least 1 vertex.
*/
private void filterBoneList(SkeletonControl skeletonControl) {
Mesh[] targets = skeletonControl.getTargets();
Skeleton skel = skeletonControl.getSkeleton();
for (int boneI = 0; boneI < skel.getBoneCount(); boneI++) {
String boneName = skel.getBone(boneI).getName();
if (boneList.contains(boneName)) {
boolean hasVertices = RagdollUtils.hasVertices(boneI, targets,
weightThreshold);
if (!hasVertices) {
boneList.remove(boneName);
}
}
}
}
/**
* Destroy spatial-dependent data. Invoked when this control is removed from
* a spatial.
@ -655,7 +678,7 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
*/
protected void boneRecursion(Spatial model, Bone bone, PhysicsRigidBody parent, int reccount, Map<Integer, List<Float>> pointsMap) {
PhysicsRigidBody parentShape = parent;
if (boneList.isEmpty() || boneList.contains(bone.getName())) {
if (boneList.contains(bone.getName())) {
PhysicsBoneLink link = new PhysicsBoneLink();
link.bone = bone;

@ -56,6 +56,12 @@ import java.util.*;
*/
public class RagdollUtils {
/**
* A private constructor to inhibit instantiation of this class.
*/
private RagdollUtils() {
}
/**
* Alter the limits of the specified 6-DOF joint.
*
@ -172,12 +178,12 @@ public class RagdollUtils {
}
}
assert !points.isEmpty();
float[] p = new float[points.size()];
for (int i = 0; i < points.size(); i++) {
p[i] = points.get(i);
}
return new HullCollisionShape(p);
}
@ -235,12 +241,13 @@ public class RagdollUtils {
}
}
}
assert !points.isEmpty();
float[] p = new float[points.size()];
for (int i = 0; i < points.size(); i++) {
p[i] = points.get(i);
}
return new HullCollisionShape(p);
}
@ -343,4 +350,39 @@ public class RagdollUtils {
setUserControl(child, bool);
}
}
/**
* Test whether the indexed bone has at least one vertex in the specified
* meshes with a weight greater than the specified threshold.
*
* @param boneIndex the index of the bone (&ge;0)
* @param targets the meshes to search (not null, no null elements)
* @param weightThreshold the threshold (&ge;0, &le;1)
* @return true if at least 1 vertex found, otherwise false
*/
public static boolean hasVertices(int boneIndex, Mesh[] targets,
float weightThreshold) {
for (Mesh mesh : targets) {
ByteBuffer boneIndices
= (ByteBuffer) mesh.getBuffer(Type.BoneIndex).getData();
FloatBuffer boneWeight
= (FloatBuffer) mesh.getBuffer(Type.BoneWeight).getData();
boneIndices.rewind();
boneWeight.rewind();
int vertexComponents = mesh.getVertexCount() * 3;
for (int i = 0; i < vertexComponents; i += 3) {
int start = i / 3 * 4;
for (int k = start; k < start + 4; k++) {
if (boneIndices.get(k) == boneIndex
&& boneWeight.get(k) >= weightThreshold) {
return true;
}
}
}
}
return false;
}
}

Loading…
Cancel
Save