Home | History | Annotate | Download | only in ragdoll
      1 /*
      2  * To change this template, choose Tools | Templates
      3  * and open the template in the editor.
      4  */
      5 package com.jme3.bullet.control.ragdoll;
      6 
      7 import com.jme3.animation.Bone;
      8 import com.jme3.animation.Skeleton;
      9 import com.jme3.bullet.collision.shapes.HullCollisionShape;
     10 import com.jme3.bullet.joints.SixDofJoint;
     11 import com.jme3.math.Quaternion;
     12 import com.jme3.math.Transform;
     13 import com.jme3.math.Vector3f;
     14 import com.jme3.scene.Geometry;
     15 import com.jme3.scene.Mesh;
     16 import com.jme3.scene.Node;
     17 import com.jme3.scene.Spatial;
     18 import com.jme3.scene.VertexBuffer.Type;
     19 import java.nio.ByteBuffer;
     20 import java.nio.FloatBuffer;
     21 import java.util.*;
     22 
     23 /**
     24  *
     25  * @author Nehon
     26  */
     27 public class RagdollUtils {
     28 
     29     public static void setJointLimit(SixDofJoint joint, float maxX, float minX, float maxY, float minY, float maxZ, float minZ) {
     30 
     31         joint.getRotationalLimitMotor(0).setHiLimit(maxX);
     32         joint.getRotationalLimitMotor(0).setLoLimit(minX);
     33         joint.getRotationalLimitMotor(1).setHiLimit(maxY);
     34         joint.getRotationalLimitMotor(1).setLoLimit(minY);
     35         joint.getRotationalLimitMotor(2).setHiLimit(maxZ);
     36         joint.getRotationalLimitMotor(2).setLoLimit(minZ);
     37     }
     38 
     39     public static Map<Integer, List<Float>> buildPointMap(Spatial model) {
     40 
     41 
     42         Map<Integer, List<Float>> map = new HashMap<Integer, List<Float>>();
     43         if (model instanceof Geometry) {
     44             Geometry g = (Geometry) model;
     45             buildPointMapForMesh(g.getMesh(), map);
     46         } else if (model instanceof Node) {
     47             Node node = (Node) model;
     48             for (Spatial s : node.getChildren()) {
     49                 if (s instanceof Geometry) {
     50                     Geometry g = (Geometry) s;
     51                     buildPointMapForMesh(g.getMesh(), map);
     52                 }
     53             }
     54         }
     55         return map;
     56     }
     57 
     58     private static Map<Integer, List<Float>> buildPointMapForMesh(Mesh mesh, Map<Integer, List<Float>> map) {
     59 
     60         FloatBuffer vertices = mesh.getFloatBuffer(Type.Position);
     61         ByteBuffer boneIndices = (ByteBuffer) mesh.getBuffer(Type.BoneIndex).getData();
     62         FloatBuffer boneWeight = (FloatBuffer) mesh.getBuffer(Type.BoneWeight).getData();
     63 
     64         vertices.rewind();
     65         boneIndices.rewind();
     66         boneWeight.rewind();
     67 
     68         int vertexComponents = mesh.getVertexCount() * 3;
     69         int k, start, index;
     70         float maxWeight = 0;
     71 
     72         for (int i = 0; i < vertexComponents; i += 3) {
     73 
     74 
     75             start = i / 3 * 4;
     76             index = 0;
     77             maxWeight = -1;
     78             for (k = start; k < start + 4; k++) {
     79                 float weight = boneWeight.get(k);
     80                 if (weight > maxWeight) {
     81                     maxWeight = weight;
     82                     index = boneIndices.get(k);
     83                 }
     84             }
     85             List<Float> points = map.get(index);
     86             if (points == null) {
     87                 points = new ArrayList<Float>();
     88                 map.put(index, points);
     89             }
     90             points.add(vertices.get(i));
     91             points.add(vertices.get(i + 1));
     92             points.add(vertices.get(i + 2));
     93         }
     94         return map;
     95     }
     96 
     97     /**
     98      * Create a hull collision shape from linked vertices to this bone.
     99      * Vertices have to be previoulsly gathered in a map using buildPointMap method
    100      * @param link
    101      * @param model
    102      * @return
    103      */
    104     public static HullCollisionShape makeShapeFromPointMap(Map<Integer, List<Float>> pointsMap, List<Integer> boneIndices, Vector3f initialScale, Vector3f initialPosition) {
    105 
    106         ArrayList<Float> points = new ArrayList<Float>();
    107         for (Integer index : boneIndices) {
    108             List<Float> l = pointsMap.get(index);
    109             if (l != null) {
    110 
    111                 for (int i = 0; i < l.size(); i += 3) {
    112                     Vector3f pos = new Vector3f();
    113                     pos.x = l.get(i);
    114                     pos.y = l.get(i + 1);
    115                     pos.z = l.get(i + 2);
    116                     pos.subtractLocal(initialPosition).multLocal(initialScale);
    117                     points.add(pos.x);
    118                     points.add(pos.y);
    119                     points.add(pos.z);
    120                 }
    121             }
    122         }
    123 
    124         float[] p = new float[points.size()];
    125         for (int i = 0; i < points.size(); i++) {
    126             p[i] = points.get(i);
    127         }
    128 
    129 
    130         return new HullCollisionShape(p);
    131     }
    132 
    133     //retruns the list of bone indices of the given bone and its child(if they are not in the boneList)
    134     public static List<Integer> getBoneIndices(Bone bone, Skeleton skeleton, Set<String> boneList) {
    135         List<Integer> list = new LinkedList<Integer>();
    136         if (boneList.isEmpty()) {
    137             list.add(skeleton.getBoneIndex(bone));
    138         } else {
    139             list.add(skeleton.getBoneIndex(bone));
    140             for (Bone chilBone : bone.getChildren()) {
    141                 if (!boneList.contains(chilBone.getName())) {
    142                     list.addAll(getBoneIndices(chilBone, skeleton, boneList));
    143                 }
    144             }
    145         }
    146         return list;
    147     }
    148 
    149     /**
    150      * Create a hull collision shape from linked vertices to this bone.
    151      *
    152      * @param link
    153      * @param model
    154      * @return
    155      */
    156     public static HullCollisionShape makeShapeFromVerticeWeights(Spatial model, List<Integer> boneIndices, Vector3f initialScale, Vector3f initialPosition, float weightThreshold) {
    157 
    158         ArrayList<Float> points = new ArrayList<Float>();
    159         if (model instanceof Geometry) {
    160             Geometry g = (Geometry) model;
    161             for (Integer index : boneIndices) {
    162                 points.addAll(getPoints(g.getMesh(), index, initialScale, initialPosition, weightThreshold));
    163             }
    164         } else if (model instanceof Node) {
    165             Node node = (Node) model;
    166             for (Spatial s : node.getChildren()) {
    167                 if (s instanceof Geometry) {
    168                     Geometry g = (Geometry) s;
    169                     for (Integer index : boneIndices) {
    170                         points.addAll(getPoints(g.getMesh(), index, initialScale, initialPosition, weightThreshold));
    171                     }
    172 
    173                 }
    174             }
    175         }
    176         float[] p = new float[points.size()];
    177         for (int i = 0; i < points.size(); i++) {
    178             p[i] = points.get(i);
    179         }
    180 
    181 
    182         return new HullCollisionShape(p);
    183     }
    184 
    185     /**
    186      * returns a list of points for the given bone
    187      * @param mesh
    188      * @param boneIndex
    189      * @param offset
    190      * @param link
    191      * @return
    192      */
    193     private static List<Float> getPoints(Mesh mesh, int boneIndex, Vector3f initialScale, Vector3f offset, float weightThreshold) {
    194 
    195         FloatBuffer vertices = mesh.getFloatBuffer(Type.Position);
    196         ByteBuffer boneIndices = (ByteBuffer) mesh.getBuffer(Type.BoneIndex).getData();
    197         FloatBuffer boneWeight = (FloatBuffer) mesh.getBuffer(Type.BoneWeight).getData();
    198 
    199         vertices.rewind();
    200         boneIndices.rewind();
    201         boneWeight.rewind();
    202 
    203         ArrayList<Float> results = new ArrayList<Float>();
    204 
    205         int vertexComponents = mesh.getVertexCount() * 3;
    206 
    207         for (int i = 0; i < vertexComponents; i += 3) {
    208             int k;
    209             boolean add = false;
    210             int start = i / 3 * 4;
    211             for (k = start; k < start + 4; k++) {
    212                 if (boneIndices.get(k) == boneIndex && boneWeight.get(k) >= weightThreshold) {
    213                     add = true;
    214                     break;
    215                 }
    216             }
    217             if (add) {
    218 
    219                 Vector3f pos = new Vector3f();
    220                 pos.x = vertices.get(i);
    221                 pos.y = vertices.get(i + 1);
    222                 pos.z = vertices.get(i + 2);
    223                 pos.subtractLocal(offset).multLocal(initialScale);
    224                 results.add(pos.x);
    225                 results.add(pos.y);
    226                 results.add(pos.z);
    227 
    228             }
    229         }
    230 
    231         return results;
    232     }
    233 
    234     /**
    235      * Updates a bone position and rotation.
    236      * if the child bones are not in the bone list this means, they are not associated with a physic shape.
    237      * So they have to be updated
    238      * @param bone the bone
    239      * @param pos the position
    240      * @param rot the rotation
    241      */
    242     public static void setTransform(Bone bone, Vector3f pos, Quaternion rot, boolean restoreBoneControl, Set<String> boneList) {
    243         //we ensure that we have the control
    244         if (restoreBoneControl) {
    245             bone.setUserControl(true);
    246         }
    247         //we set te user transforms of the bone
    248         bone.setUserTransformsWorld(pos, rot);
    249         for (Bone childBone : bone.getChildren()) {
    250             //each child bone that is not in the list is updated
    251             if (!boneList.contains(childBone.getName())) {
    252                 Transform t = childBone.getCombinedTransform(pos, rot);
    253                 setTransform(childBone, t.getTranslation(), t.getRotation(), restoreBoneControl, boneList);
    254             }
    255         }
    256         //we give back the control to the keyframed animation
    257         if (restoreBoneControl) {
    258             bone.setUserControl(false);
    259         }
    260     }
    261 
    262     public static void setUserControl(Bone bone, boolean bool) {
    263         bone.setUserControl(bool);
    264         for (Bone child : bone.getChildren()) {
    265             setUserControl(child, bool);
    266         }
    267     }
    268 }
    269