Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@
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;
Expand Down Expand Up @@ -198,6 +198,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 @@ -215,6 +216,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 @@ -274,6 +276,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 @@ -334,15 +337,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 @@ -377,17 +374,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 @@ -575,6 +563,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 @@ -594,6 +598,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 @@ -655,7 +678,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;
}
}