Mercurial > cortex
comparison org/body.org @ 203:0e5d5ee5a914
first draft of body.org complete
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Wed, 08 Feb 2012 08:53:12 -0700 |
parents | d5c597a7aed4 |
children | 162b24a82712 |
comparison
equal
deleted
inserted
replaced
202:d5c597a7aed4 | 203:0e5d5ee5a914 |
---|---|
36 #+caption: EVE from the movie WALL-E. This body plan turns out to be much better suited to my purposes than a more human-like one. | 36 #+caption: EVE from the movie WALL-E. This body plan turns out to be much better suited to my purposes than a more human-like one. |
37 [[../images/Eve.jpg]] | 37 [[../images/Eve.jpg]] |
38 | 38 |
39 The main reason that I use eve-style bodies is so that there will be | 39 The main reason that I use eve-style bodies is so that there will be |
40 correspondence between the AI's vision and the physical presence of | 40 correspondence between the AI's vision and the physical presence of |
41 its body. | 41 its body. Each individual section is simulated by a separate rigid |
42 body that corresponds exactly with its visual representation and does | |
43 not change. Sections are connected by invisible joints that are well | |
44 supported in jMonkyeEngine. Bullet, the physics backend for | |
45 jMonkeyEngine, can efficiently simulate hundreds of rigid bodies | |
46 connected by joints. Sections do not have to stay as one piece | |
47 forever; they can be dynamically replaced with multiple sections to | |
48 simulate splitting in two. This could be used to simulate retractable | |
49 claws or EVE's hands, which could coalece into one object in the | |
50 movie. | |
42 | 51 |
43 * Solidifying the Body | 52 * Solidifying the Body |
44 | 53 |
45 Here is a hand designed eve-style in blender. | 54 Here is a hand designed eve-style in blender. |
46 | 55 |
47 | 56 #+attr_html: width="755" |
48 #+attr_html: width="500" | |
49 [[../images/hand-screenshot0.png]] | 57 [[../images/hand-screenshot0.png]] |
50 | 58 |
51 If we load it directly into jMonkeyEngine, we get this: | 59 If we load it directly into jMonkeyEngine, we get this: |
52 | 60 |
53 #+name: test-0 | 61 #+name: test-0 |
90 #+begin_src clojure :results silent | 98 #+begin_src clojure :results silent |
91 (.start (cortex.test.body/test-one)) | 99 (.start (cortex.test.body/test-one)) |
92 #+end_src | 100 #+end_src |
93 | 101 |
94 #+begin_html | 102 #+begin_html |
95 <video controls="controls" width="755"> | 103 <div class="figure"> |
104 <center> | |
105 <video controls="controls" width="640"> | |
96 <source src="../video/ghost-hand.ogg" type="video/ogg" | 106 <source src="../video/ghost-hand.ogg" type="video/ogg" |
97 preload="none" poster="../images/aurellem-1280x480.png" /> | 107 preload="none" poster="../images/aurellem-1280x480.png" /> |
98 </video> | 108 </video> |
109 </center> | |
110 <p>The hand model directly loaded from blender. It has no physical | |
111 presense in the simulation. </p> | |
112 </div> | |
99 #+end_html | 113 #+end_html |
100 | 114 |
101 You will notice that the hand has no physical presence -- it's a | 115 You will notice that the hand has no physical presence -- it's a |
102 hologram through witch everything passes. Therefore, the first thing | 116 hologram through witch everything passes. Therefore, the first thing |
103 to do is to make it solid. Blender has physics simulation on par with | 117 to do is to make it solid. Blender has physics simulation on par with |
104 jMonkeyEngine (they both use bullet as their physics backend), but it | 118 jMonkeyEngine (they both use bullet as their physics backend), but it |
105 can be difficult to translate between the two systems, so for now I | 119 can be difficult to translate between the two systems, so for now I |
106 specify the mass of each object in blender and construct the physics | 120 specify the mass of each object in blender and construct the physics |
107 shape based on the mesh in jMonkeyEngine. | 121 shape based on the mesh in jMonkeyEngine. |
108 | 122 |
109 #+name: joints-1 | 123 #+name: body-1 |
110 #+begin_src clojure | 124 #+begin_src clojure |
111 (defn physical! | 125 (defn physical! |
112 "Iterate through the nodes in creature and make them real physical | 126 "Iterate through the nodes in creature and make them real physical |
113 objects in the simulation." | 127 objects in the simulation." |
114 [#^Node creature] | 128 [#^Node creature] |
132 | 146 |
133 =(physical!)= iterates through a creature's node structure, creating | 147 =(physical!)= iterates through a creature's node structure, creating |
134 CollisionShapes for each geometry with the mass specified in that | 148 CollisionShapes for each geometry with the mass specified in that |
135 geometry's meta-data. | 149 geometry's meta-data. |
136 | 150 |
151 #+name: test-1 | |
137 #+begin_src clojure | 152 #+begin_src clojure |
138 (in-ns 'cortex.test.body) | 153 (in-ns 'cortex.test.body) |
139 | 154 |
140 (def normal-gravity | 155 (def normal-gravity |
141 {"key-g" (fn [world _] | 156 {"key-g" (fn [world _] |
158 setup) | 173 setup) |
159 no-op)) | 174 no-op)) |
160 #+end_src | 175 #+end_src |
161 | 176 |
162 #+begin_html | 177 #+begin_html |
163 <video controls="controls" width="755"> | 178 <div class="figure"> |
179 <center> | |
180 <video controls="controls" width="640"> | |
164 <source src="../video/crumbly-hand.ogg" type="video/ogg" | 181 <source src="../video/crumbly-hand.ogg" type="video/ogg" |
165 preload="none" poster="../images/aurellem-1280x480.png" /> | 182 preload="none" poster="../images/aurellem-1280x480.png" /> |
166 </video> | 183 </video> |
184 </center> | |
185 <p>The hand now has a physical presence, but there is nothing to hold | |
186 it together.</p> | |
187 </div> | |
167 #+end_html | 188 #+end_html |
168 | 189 |
169 Now that's some progress. | 190 Now that's some progress. |
170 | 191 |
171 | 192 |
186 So, I will use the same system for specifying joints as I will do for | 207 So, I will use the same system for specifying joints as I will do for |
187 some senses. Each joint is specified by an empty node whose parent | 208 some senses. Each joint is specified by an empty node whose parent |
188 has the name "joints". Their orientation and meta-data determine what | 209 has the name "joints". Their orientation and meta-data determine what |
189 joint is created. | 210 joint is created. |
190 | 211 |
212 #+attr_html: width="755" | |
213 #+caption: joints hack in blender. Each empty node here will be transformed into a joint in jMonkeyEngine | |
191 [[../images/hand-screenshot1.png]] | 214 [[../images/hand-screenshot1.png]] |
192 | 215 |
193 | 216 The empty node in the upper right, highlighted in yellow, is the |
194 | 217 parent node of all the emptys which represent joints. The following |
195 | 218 functions must do three things to translate these into real joints: |
196 #+name: joints-2 | 219 |
220 - Find the children of the "joints" node. | |
221 - Determine the two spatials the joint it meant to connect. | |
222 - Create the joint based on the meta-data of the empty node. | |
223 | |
224 ** Finding the Joints | |
225 #+name: joints-2 | |
226 #+begin_src clojure | |
227 (defvar | |
228 ^{:arglists '([creature])} | |
229 joints | |
230 (sense-nodes "joints") | |
231 "Return the children of the creature's \"joints\" node.") | |
232 #+end_src | |
233 | |
234 The higher order function =(sense-nodes)= from cortex.sense makes our | |
235 first task very easy. | |
236 | |
237 ** Joint Targets and Orientation | |
238 | |
239 This technique for finding a joint's targets is very similiar to | |
240 =(cortex.sense/closest-node)=. A small cube, centered around the | |
241 empty-node, grows exponentially until it intersects two /physical/ | |
242 objects. The objects are ordered according to the joint's rotation, | |
243 with the first one being the object that has more negative coordinates | |
244 in the joint's reference frame. Since the objects must be physical, | |
245 the empty-node itself escapes detection. Because the objects must be | |
246 physical, =(joint-targets)= must be called /after/ =(physical!)= is | |
247 called. | |
248 | |
249 #+name: joints-3 | |
197 #+begin_src clojure | 250 #+begin_src clojure |
198 (defn joint-targets | 251 (defn joint-targets |
199 "Return the two closest two objects to the joint object, ordered | 252 "Return the two closest two objects to the joint object, ordered |
200 from bottom to top according to the joint's rotation." | 253 from bottom to top according to the joint's rotation." |
201 [#^Node parts #^Node joint] | 254 [#^Node parts #^Node joint] |
220 (println-repl (.getName %) ":" v) | 273 (println-repl (.getName %) ":" v) |
221 (.dot (Vector3f. 1 1 1) | 274 (.dot (Vector3f. 1 1 1) |
222 v)) | 275 v)) |
223 (take 2 targets)) | 276 (take 2 targets)) |
224 (recur (float (* radius 2)))))))) | 277 (recur (float (* radius 2)))))))) |
225 | 278 #+end_src |
279 | |
280 ** Generating Joints | |
281 | |
282 This long chunk of code iterates through all the different ways of | |
283 specifying joints using blender meta-data and converts each one to the | |
284 appropriate jMonkyeEngine joint. | |
285 | |
286 #+name: joints-4 | |
287 #+begin_src clojure | |
226 (defmulti joint-dispatch | 288 (defmulti joint-dispatch |
227 "Translate blender pseudo-joints into real JME joints." | 289 "Translate blender pseudo-joints into real JME joints." |
228 (fn [constraints & _] | 290 (fn [constraints & _] |
229 (:type constraints))) | 291 (:type constraints))) |
230 | 292 |
250 control-b | 312 control-b |
251 pivot-a | 313 pivot-a |
252 pivot-b | 314 pivot-b |
253 false) | 315 false) |
254 (.setLinearLowerLimit Vector3f/ZERO) | 316 (.setLinearLowerLimit Vector3f/ZERO) |
255 (.setLinearUpperLimit Vector3f/ZERO) | 317 (.setLinearUpperLimit Vector3f/ZERO))) |
256 ;;(.setAngularLowerLimit (Vector3f. 1 1 1)) | |
257 ;;(.setAngularUpperLimit (Vector3f. 0 0 0)) | |
258 | |
259 )) | |
260 | |
261 | 318 |
262 (defmethod joint-dispatch :hinge | 319 (defmethod joint-dispatch :hinge |
263 [constraints control-a control-b pivot-a pivot-b rotation] | 320 [constraints control-a control-b pivot-a pivot-b rotation] |
264 (println-repl "creating HINGE joint") | 321 (println-repl "creating HINGE joint") |
265 (let [axis | 322 (let [axis |
343 (joint-dispatch constraints | 400 (joint-dispatch constraints |
344 control-a control-b | 401 control-a control-b |
345 pivot-a pivot-b | 402 pivot-a pivot-b |
346 joint-rotation)) | 403 joint-rotation)) |
347 (println-repl "could not find joint meta-data!")))) | 404 (println-repl "could not find joint meta-data!")))) |
348 | 405 #+end_src |
349 (defvar | 406 |
350 ^{:arglists '([creature])} | 407 Creating joints is now a matter applying =(connect)= to each joint |
351 joints | 408 node. |
352 (sense-nodes "joints") | 409 |
353 "Return the children of the creature's \"joints\" node.") | 410 #+begin_src clojure |
354 | |
355 (defn joints! | 411 (defn joints! |
356 "Connect the solid parts of the creature with physical joints. The | 412 "Connect the solid parts of the creature with physical joints. The |
357 joints are taken from the \"joints\" node in the creature." | 413 joints are taken from the \"joints\" node in the creature." |
358 [#^Node creature] | 414 [#^Node creature] |
359 (dorun | 415 (dorun |
360 (map | 416 (map |
361 (fn [joint] | 417 (fn [joint] |
362 (let [[obj-a obj-b] (joint-targets creature joint)] | 418 (let [[obj-a obj-b] (joint-targets creature joint)] |
363 (connect obj-a obj-b joint))) | 419 (connect obj-a obj-b joint))) |
364 (joints creature)))) | 420 (joints creature)))) |
365 | 421 #+end_src |
422 | |
423 | |
424 ** Round 3 | |
425 | |
426 Now we can test the hand in all its glory. | |
427 | |
428 #+begin_src clojure | |
429 (in-ns 'cortex.test.body) | |
430 | |
431 (def debug-control | |
432 {"key-h" (fn [world val] | |
433 (if val (enable-debug world))) | |
434 | |
435 "key-u" (fn [world _] (set-gravity world Vector3f/ZERO)) | |
436 }) | |
437 | |
438 (defn test-three [] | |
439 (world (nodify | |
440 [(doto (hand) | |
441 (physical!) | |
442 (joints!) ) | |
443 (floor)]) | |
444 (merge standard-debug-controls debug-control | |
445 normal-gravity) | |
446 (comp | |
447 #(Capture/captureVideo | |
448 % (File. "/home/r/proj/cortex/render/body/3")) | |
449 #(do (set-gravity % Vector3f/ZERO) %) | |
450 setup) | |
451 no-op)) | |
452 #+end_src | |
453 | |
454 =(physical!)= makes the hand solid, then =(joints!)= connects each | |
455 piece together. | |
456 | |
457 | |
458 #+begin_html | |
459 <div class="figure"> | |
460 <center> | |
461 <video controls="controls" width="640"> | |
462 <source src="../video/full-hand.ogg" type="video/ogg" | |
463 preload="none" poster="../images/aurellem-1280x480.png" /> | |
464 </video> | |
465 </center> | |
466 <p>Now the hand is physical and has joints.</p> | |
467 </div> | |
468 #+end_html | |
469 | |
470 The joints are visualized as green connections between each segment | |
471 for debug purposes. You can see that they correspond to the empty | |
472 nodes in the blender file. | |
473 | |
474 * Wrap-Up! | |
475 | |
476 It is convienent to combine =(physical!)= and =(joints!)= into one | |
477 function that completely creates the creature's physical body. | |
478 | |
479 #+name: joints-4 | |
480 #+begin_src clojure | |
366 (defn body! | 481 (defn body! |
367 "Endow the creature with a physical body connected with joints. The | 482 "Endow the creature with a physical body connected with joints. The |
368 particulars of the joints and the masses of each pody part are | 483 particulars of the joints and the masses of each pody part are |
369 determined in blender." | 484 determined in blender." |
370 [#^Node creature] | 485 [#^Node creature] |
371 (physical! creature) | 486 (physical! creature) |
372 (joints! creature)) | 487 (joints! creature)) |
373 #+end_src | 488 #+end_src |
374 | 489 |
375 * Bookkeeping | 490 * Bookkeeping |
491 | |
492 Header; here for completeness. | |
376 | 493 |
377 #+name: body-0 | 494 #+name: body-0 |
378 #+begin_src clojure | 495 #+begin_src clojure |
379 (ns cortex.body | 496 (ns cortex.body |
380 "Assemble a physical creature using the definitions found in a | 497 "Assemble a physical creature using the definitions found in a |
394 com.jme3.scene.Geometry | 511 com.jme3.scene.Geometry |
395 com.jme3.bullet.collision.shapes.HullCollisionShape)) | 512 com.jme3.bullet.collision.shapes.HullCollisionShape)) |
396 #+end_src | 513 #+end_src |
397 | 514 |
398 * Source | 515 * Source |
516 | |
517 Dylan -- I'll fill these in later | |
518 - cortex.body | |
519 - cortex.test.body | |
520 - blender files | |
399 | 521 |
400 * COMMENT Examples | 522 * COMMENT Examples |
401 | 523 |
402 #+name: test-body | 524 #+name: test-body |
403 #+begin_src clojure | 525 #+begin_src clojure |