• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
setJointLimit(SixDofJoint joint, float maxX, float minX, float maxY, float minY, float maxZ, float minZ)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 
buildPointMap(Spatial model)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 
buildPointMapForMesh(Mesh mesh, Map<Integer, List<Float>> map)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      */
makeShapeFromPointMap(Map<Integer, List<Float>> pointsMap, List<Integer> boneIndices, Vector3f initialScale, Vector3f initialPosition)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)
getBoneIndices(Bone bone, Skeleton skeleton, Set<String> 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      */
makeShapeFromVerticeWeights(Spatial model, List<Integer> boneIndices, Vector3f initialScale, Vector3f initialPosition, float weightThreshold)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      */
getPoints(Mesh mesh, int boneIndex, Vector3f initialScale, Vector3f offset, float weightThreshold)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      */
setTransform(Bone bone, Vector3f pos, Quaternion rot, boolean restoreBoneControl, Set<String> boneList)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 
setUserControl(Bone bone, boolean bool)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