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