Skip to content

Commit

Permalink
fix for issue #740 (#906)
Browse files Browse the repository at this point in the history
  • Loading branch information
stephengold committed Dec 22, 2018
1 parent 7e17cdc commit 5bbc6bc
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
import com.jme3.math.Vector3f;
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.scene.control.Control;
Expand Down Expand Up @@ -212,6 +213,7 @@ public PhysicsRigidBody getRigidBody() {
* @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);
Expand All @@ -229,6 +231,7 @@ public void write(JmeExporter ex) throws IOException {
* @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);
Expand Down Expand Up @@ -288,6 +291,7 @@ public KinematicRagdollControl(RagdollPreset preset) {
*
* @param tpf the time interval between frames (in seconds, ≥0)
*/
@Override
public void update(float tpf) {
if (!enabled) {
return;
Expand Down Expand Up @@ -348,15 +352,9 @@ protected void ragDollUpdate(float tpf) {
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();
Expand Down Expand Up @@ -391,17 +389,8 @@ protected void kinematicUpdate(float tpf) {
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);
Expand Down Expand Up @@ -589,6 +578,22 @@ protected void createSpatialData(Spatial model) {
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);
Expand All @@ -608,6 +613,25 @@ protected void createSpatialData(Spatial model) {
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.
Expand Down Expand Up @@ -669,7 +693,7 @@ protected void scanSpatial(Spatial model) {
*/
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@
*/
public class RagdollUtils {

/**
* A private constructor to inhibit instantiation of this class.
*/
private RagdollUtils() {
}

/**
* Alter the limits of the specified 6-DOF joint.
*
Expand Down Expand Up @@ -172,12 +178,12 @@ public static HullCollisionShape makeShapeFromPointMap(Map<Integer, List<Float>>
}
}

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);
}

Expand Down Expand Up @@ -235,12 +241,13 @@ public static HullCollisionShape makeShapeFromVerticeWeights(Spatial model, List
}
}
}

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);
}

Expand Down Expand Up @@ -343,4 +350,39 @@ public static void setUserControl(Bone bone, boolean bool) {
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;
}
}

0 comments on commit 5bbc6bc

Please sign in to comment.