view org/test-creature.org @ 77:1f84f425e05d

first draft of automatic constraints from blender
author Robert McIntyre <rlm@mit.edu>
date Wed, 04 Jan 2012 08:36:42 -0700
parents f4c77512808e
children 77b506ac64f3
line wrap: on
line source
1 #+title: First attempt at a creature!
2 #+author: Robert McIntyre
3 #+email: rlm@mit.edu
4 #+description:
5 #+keywords: simulation, jMonkeyEngine3, clojure
6 #+SETUPFILE: ../../aurellem/org/setup.org
7 #+INCLUDE: ../../aurellem/org/level-0.org
9 * Intro
10 So far, I've made the following senses --
11 - Vision
12 - Hearing
13 - Touch
14 - Proprioception
16 And one effector:
17 - Movement
19 However, the code so far has only enabled these senses, but has not
20 actually implemented them. For example, there is still a lot of work
21 to be done for vision. I need to be able to create an /eyeball/ in
22 simulation that can be moved around and see the world from different
23 angles. I also need to determine weather to use log-polar or cartesian
24 for the visual input, and I need to determine how/wether to
25 disceritise the visual input.
27 I also want to be able to visualize both the sensors and the
28 effectors in pretty pictures. This semi-retarted creature will by my
29 first attempt at bringing everything together.
31 * The creature's body
33 Still going to do an eve-like body in blender, but due to problems
34 importing the joints, etc into jMonkeyEngine3, I',m going to do all
35 the connecting here in clojure code, using the names of the individual
36 components and trial and error. Later, I'll maybe make some sort of
37 creature-building modifications to blender that support whatever
38 discreitized senses I'm going to make.
40 #+name: body-1
41 #+begin_src clojure
42 (ns cortex.silly
43 "let's play!"
44 {:author "Robert McIntyre"})
46 ;; TODO remove this!
47 (require 'cortex.import)
48 (cortex.import/mega-import-jme3)
49 (use '(cortex world util body hearing touch vision))
51 (use '[clojure.contrib [seq :only [find-first]]])
54 (rlm.rlm-commands/help)
56 (defn load-blender-model
57 "Load a .blend file using an asset folder relative path."
58 [^String model]
59 (.loadModel
60 (doto (asset-manager)
61 (.registerLoader BlenderModelLoader (into-array String ["blend"])))
62 model))
64 (defn meta-data [blender-node key]
65 (if-let [data (.getUserData blender-node "properties")]
66 (.findValue data key)
67 nil))
70 (defn hand []
71 (load-blender-model "Models/creature1/one.blend"))
75 (def hand-names
76 #{
77 "middle-1"
78 "middle-2"
79 "middle-3"
80 "palm"
81 "pinky-1"
82 "pinky-2"
83 "pinky-3"
84 "pointer-1"
85 "pointer-2"
86 "pointer-3"
87 "ring-1"
88 "ring-2"
89 "ring-3"
90 "thumb-1"
91 "thumb-2"})
93 (defn hand-pieces []
94 (filter
95 (comp hand-names #(apply str (drop-last (.getName %)))) (node-seq (hand))))
97 (defn hand-joints []
98 (map #(.getWorldTranslation %)
99 (filter #(re-matches #"joint\.\d\d\d" (.getName %))
100 (node-seq (hand)))))
101 (defn worm []
102 (load-blender-model "Models/creature1/try-again.blend"))
105 (defn worm-pieces []
106 (filter
107 (comp #{"worm-2" "worm-1"}
108 #(apply str (drop-last (.getName %))))
109 (node-seq (worm))))
111 (defn worm-joints []
112 (filter #(re-matches #"joint\.\d\d\d" (.getName %))
113 (node-seq (worm))))
115 (defn bullet-trans []
116 (let [obj-a (sphere 0.5 :color ColorRGBA/Red
117 :position (Vector3f. -10 5 0))
118 obj-b (sphere 0.5 :color ColorRGBA/Blue
119 :position (Vector3f. -10 -5 0)
120 :mass 0)
121 control-a (.getControl obj-a RigidBodyControl)
122 control-b (.getControl obj-b RigidBodyControl)
123 swivel
124 (.toRotationMatrix
125 (doto (Quaternion.)
126 (.fromAngleAxis (/ Math/PI 2)
127 Vector3f/UNIT_X)))]
128 (doto
129 (ConeJoint.
130 control-a control-b
131 (Vector3f. 0 5 0)
132 (Vector3f. 0 -5 0)
133 swivel swivel)
134 (.setLimit (* 0.6 (/ Math/PI 4))
135 (/ Math/PI 4)
136 (* Math/PI 0.8)))
137 (world (nodify
138 [obj-a obj-b])
139 standard-debug-controls
140 enable-debug
141 no-op)))
144 (defn bullet-trans* []
145 (let [obj-a (box 1.5 0.5 0.5 :color ColorRGBA/Red
146 :position (Vector3f. 5 0 0)
147 :mass 90)
148 obj-b (sphere 0.5 :color ColorRGBA/Blue
149 :position (Vector3f. -5 0 0)
150 :mass 0)
151 control-a (.getControl obj-a RigidBodyControl)
152 control-b (.getControl obj-b RigidBodyControl)
153 move-up? (atom nil)
154 move-down? (atom nil)
155 move-left? (atom nil)
156 move-right? (atom nil)
157 roll-left? (atom nil)
158 roll-right? (atom nil)
159 force 100
160 swivel
161 (.toRotationMatrix
162 (doto (Quaternion.)
163 (.fromAngleAxis (/ Math/PI 2)
164 Vector3f/UNIT_X)))
165 x-move
166 (doto (Matrix3f.)
167 (.fromStartEndVectors Vector3f/UNIT_X
168 (.normalize (Vector3f. 1 1 0))))
170 timer (atom 0)]
171 (doto
172 (ConeJoint.
173 control-a control-b
174 (Vector3f. -8 0 0)
175 (Vector3f. 2 0 0)
176 ;;swivel swivel
177 ;;Matrix3f/IDENTITY Matrix3f/IDENTITY
178 x-move Matrix3f/IDENTITY
179 )
180 (.setCollisionBetweenLinkedBodys false)
181 (.setLimit (* 1 (/ Math/PI 4)) ;; twist
182 (* 1 (/ Math/PI 4)) ;; swing span in X-Y plane
183 (* 0 (/ Math/PI 4)))) ;; swing span in Y-Z plane
184 (world (nodify
185 [obj-a obj-b])
186 (merge standard-debug-controls
187 {"key-r" (fn [_ pressed?] (reset! move-up? pressed?))
188 "key-t" (fn [_ pressed?] (reset! move-down? pressed?))
189 "key-f" (fn [_ pressed?] (reset! move-left? pressed?))
190 "key-g" (fn [_ pressed?] (reset! move-right? pressed?))
191 "key-v" (fn [_ pressed?] (reset! roll-left? pressed?))
192 "key-b" (fn [_ pressed?] (reset! roll-right? pressed?))})
194 (fn [world]
195 (enable-debug world)
196 (set-gravity world Vector3f/ZERO)
197 )
199 (fn [world _]
201 (if @move-up?
202 (.applyForce control-a
203 (Vector3f. force 0 0)
204 (Vector3f. 0 0 0)))
205 (if @move-down?
206 (.applyForce control-a
207 (Vector3f. (- force) 0 0)
208 (Vector3f. 0 0 0)))
209 (if @move-left?
210 (.applyForce control-a
211 (Vector3f. 0 force 0)
212 (Vector3f. 0 0 0)))
213 (if @move-right?
214 (.applyForce control-a
215 (Vector3f. 0 (- force) 0)
216 (Vector3f. 0 0 0)))
218 (if @roll-left?
219 (.applyForce control-a
220 (Vector3f. 0 0 force)
221 (Vector3f. 0 0 0)))
222 (if @roll-right?
223 (.applyForce control-a
224 (Vector3f. 0 0 (- force))
225 (Vector3f. 0 0 0)))
227 (if (zero? (rem (swap! timer inc) 100))
228 (.attachChild
229 (.getRootNode world)
230 (sphere 0.05 :color ColorRGBA/Yellow
231 :physical? false :position
232 (.getWorldTranslation obj-a)))))
233 )
234 ))
246 (defn world-setup [joint]
247 (let [top (doto
248 (sphere 0.1 :physical? false :color ColorRGBA/Yellow
249 :position (Vector3f. 0 7 0))
250 (.addControl
251 (RigidBodyControl.
252 (CapsuleCollisionShape. 0.5 1.5 1) (float 15))))
253 bottom (doto
254 (sphere 0.1 :physical? false :color ColorRGBA/DarkGray
255 :position (Vector3f. 0 -1 0))
256 (.addControl
257 (RigidBodyControl.
258 (CapsuleCollisionShape. 0.5 1.5 1) (float 0))))
259 table (box 10 2 10 :position (Vector3f. 0 -6 0)
260 :color ColorRGBA/Gray :mass 0)
261 a (.getControl top RigidBodyControl)
262 b (.getControl bottom RigidBodyControl)]
263 (cond
264 (= joint :point)
265 (doto
266 (Point2PointJoint. a b
267 (Vector3f. 0 -2 0)
268 (Vector3f. 0 2 0))
269 (.setCollisionBetweenLinkedBodys false))
270 (= joint :hinge)
271 (doto
272 (HingeJoint.
273 a b
274 (Vector3f. 0 -2 0)
275 (Vector3f. 0 2 0)
276 (Vector3f. 0 0 1)
277 (Vector3f. 0 0 1)
279 )
280 (.setCollisionBetweenLinkedBodys false)
281 ;;(.setLimit (- Math/PI) Math/PI)
282 )
283 (= joint :cone)
284 ;; note to self -- jbullet does NOT implement cone joints
285 ;; correctly. You must use plain ol' bullet for this to work.
286 ;; It's faster anyway, so whatever.
288 (doto (ConeJoint.
289 a b
290 (Vector3f. 0 -5 0)
291 (Vector3f. 0 2 0)
293 (doto (Matrix3f.)
294 (.fromStartEndVectors Vector3f/UNIT_X
295 Vector3f/UNIT_Y))
296 (doto (Matrix3f.)
297 (.fromStartEndVectors Vector3f/UNIT_X
298 Vector3f/UNIT_Y))
299 )
300 ;;(.setAngularOnly true)
302 (.setCollisionBetweenLinkedBodys false)
303 (.setLimit (* 1 (/ Math/PI 4))
304 (* 1 (/ Math/PI 4))
305 (* 0 (/ Math/PI 4)))
307 )
308 (= joint :six)
309 (doto
310 (SixDofJoint.
311 a b
312 (Vector3f. 0 -2 0)
313 (Vector3f. 0 2 0)
314 ;;(doto (Matrix3f.)
315 ;; (.fromStartEndVectors Vector3f/UNIT_X
316 ;; Vector3f/UNIT_Y))
317 ;;(doto (Matrix3f.)
318 ;; (.fromStartEndVectors Vector3f/UNIT_X
319 ;; Vector3f/UNIT_Y))
320 true)
321 (.setCollisionBetweenLinkedBodys false)
322 (.setAngularLowerLimit (Vector3f. 0
323 (- (/ Math/PI 2))
324 0))
326 (.setAngularUpperLimit (Vector3f. 0
327 (/ Math/PI 2)
328 0))
329 (.setLinearLowerLimit (Vector3f. 0 0 0))
330 (.setLinearUpperLimit (Vector3f. 0 0 0))
332 )
338 )
340 [top bottom table]))
342 (defn speed-up [world]
343 (.setMoveSpeed (.getFlyByCamera world)
344 (float 100))
345 (.setRotationSpeed (.getFlyByCamera world)
346 (float 20))
347 world)
350 (defn test-joint [joint]
351 (let [[top bottom floor] (world-setup joint)
352 control (.getControl top RigidBodyControl)
353 move-up? (atom false)
354 move-down? (atom false)
355 move-left? (atom false)
356 move-right? (atom false)
357 roll-left? (atom false)
358 roll-right? (atom false)
359 timer (atom 0)]
361 (world
362 (nodify [top bottom floor])
363 (merge standard-debug-controls
364 {"key-r" (fn [_ pressed?] (reset! move-up? pressed?))
365 "key-t" (fn [_ pressed?] (reset! move-down? pressed?))
366 "key-f" (fn [_ pressed?] (reset! move-left? pressed?))
367 "key-g" (fn [_ pressed?] (reset! move-right? pressed?))
368 "key-v" (fn [_ pressed?] (reset! roll-left? pressed?))
369 "key-b" (fn [_ pressed?] (reset! roll-right? pressed?))})
371 (fn [world]
372 (light-up-everything world)
373 (enable-debug world)
374 (set-gravity world (Vector3f. 0 0 0))
375 )
377 (fn [world _]
378 (if (zero? (rem (swap! timer inc) 100))
379 (do
380 ;; (println-repl @timer)
381 (.attachChild (.getRootNode world)
382 (sphere 0.05 :color ColorRGBA/Yellow
383 :position (.getWorldTranslation top)
384 :physical? false))))
385 (if @move-up?
386 (.applyTorque control
387 (.mult (.getPhysicsRotation control)
388 (Vector3f. 0 0 10))))
389 (if @move-down?
390 (.applyTorque control
391 (.mult (.getPhysicsRotation control)
392 (Vector3f. 0 0 -10))))
393 (if @move-left?
394 (.applyTorque control
395 (.mult (.getPhysicsRotation control)
396 (Vector3f. 0 10 0))))
397 (if @move-right?
398 (.applyTorque control
399 (.mult (.getPhysicsRotation control)
400 (Vector3f. 0 -10 0))))
401 (if @roll-left?
402 (.applyTorque control
403 (.mult (.getPhysicsRotation control)
404 (Vector3f. -1 0 0))))
405 (if @roll-right?
406 (.applyTorque control
407 (.mult (.getPhysicsRotation control)
408 (Vector3f. 1 0 0))))))))
412 (defn run [joint] (.start (test-joint joint)))
413 (defn look [joint] (view (nodify (world-setup joint))))
415 (defn blender-to-jme
416 "Convert from Blender coordinates to JME coordinates"
417 [#^Vector3f in]
418 (Vector3f. (.getX in)
419 (.getZ in)
420 (- (.getY in))))
423 (defn joint-targets
424 "Return the two closest two objects to the joint object, ordered
425 from bottom to top according to the joint's rotation."
426 [#^Node parts #^Node joint]
427 ;;(println (meta-data joint "joint"))
428 (.getWorldRotation joint)
429 (loop [radius (float 0.01)]
430 (let [results (CollisionResults.)]
431 (.collideWith
432 parts
433 (BoundingBox. (.getWorldTranslation joint)
434 radius radius radius)
435 results)
436 (let [targets
437 (distinct
438 (map #(.getGeometry %) results))]
439 (if (>= (count targets) 2)
440 (sort-by
441 #(.getY
442 (.mult
443 (.inverse (.getWorldRotation joint))
444 (.subtract (.getWorldTranslation %)
445 (.getWorldTranslation joint))))
446 (take 2 targets))
447 (recur (float (* radius 2))))))))
449 (defn connect
450 "here are some examples:
451 {:type :point}
452 {:type :hinge :limit [0 (/ Math/PI 2)] :axis (Vector3f. 0 1 0)}
453 (:axis defaults to (Vector3f. 1 0 0) if not provided for hinge joints)
455 {:type :cone :limit-xz 0]
456 :limit-yz 0]
457 :twist 0]}
458 "
459 ([#^Node obj-a #^Node obj-b #^Node joint]
460 (let [center-a (.getWorldTranslation obj-a)
461 center-b (.getWorldTranslation obj-b)
462 joint-center (.getWorldTranslation joint)
463 pivot-a (.subtract joint-center center-a)
464 pivot-b (.subtract joint-center center-b)
465 control-a (.getControl obj-a RigidBodyControl)
466 control-b (.getControl obj-b RigidBodyControl)]
467 ;; A side-effect of creating a joint registers
468 ;; it with both physics objects which in turn
469 ;; will register the joint with the physics system
470 ;; when the simulation is started.
471 (if-let [constraints
472 (map-vals
473 eval
474 (read-string
475 (meta-data (first (worm-joints)) "joint")))]
477 (let [joint-type (:type constraints)]
478 (cond (= :point joint-type)
479 (do
480 (println-repl "creating POINT joint")
481 (Point2PointJoint.
482 control-a
483 control-b
484 pivot-a
485 pivot-b))
486 (= :hinge joint-type)
487 (do
488 (println-repl "creating HINGE joint")
489 (let [axis (if-let
490 [axis (:axis constraints)]
491 axis
492 Vector3f/UNIT_X)
493 [limit-1 limit-2] (:limit constraints)
494 hinge-axis
495 (.mult
496 (.getWorldRotation joint)
497 (blender-to-jme axis))]
498 (doto
499 (HingeJoint.
500 control-a
501 control-b
502 pivot-a
503 pivot-b
504 hinge-axis
505 hinge-axis)
506 (.setLimit limit-1 limit-2))))
507 (= :cone joint-type)
508 (do
509 (let [limit-xy (:limit-xz constraints)
510 limit-yz (:limit-yz constraints)
511 twist (:twist constraints)]
513 (println-repl "creating CONE joint")
514 (doto
515 (ConeJoint.
516 control-a
517 control-b
518 pivot-a
519 pivot-b
520 (doto (Matrix3f.)
521 (.fromStartEndVectors
522 Vector3f/UNIT_X
523 (.normalize
524 (.subtract (.getWorldTranslation joint)
525 (.getWorldTranslation obj-a)))))
526 (doto (Matrix3f.)
527 (.fromStartEndVectors
528 Vector3f/UNIT_X
529 (.normalize
530 (.subtract
531 (.getWorldTranslation obj-b)
532 (.getWorldTranslation joint))))))
533 (.setLimit (float limit-xy)
534 (float limit-yz)
535 (float twist)))))
536 true
537 (println-repl
538 "joint-type " joint-type " not recognized")))
540 (println-repl "could not find joint meta-data!")))))
544 (defn physical-worm [#^Node pieces joints]
545 (dorun
546 (map
547 (fn [geom]
548 (let [physics-control
549 (RigidBodyControl.
550 (HullCollisionShape.
551 (.getMesh geom))
552 (if-let [mass (meta-data geom "mass")]
553 (do
554 (println-repl
555 "setting mass to " (float mass))
556 (float mass))
557 (float 1)))]
559 (.addControl geom physics-control)))
560 (filter #(isa? (class %) Geometry )
561 (node-seq pieces))))
563 (dorun
564 (map
565 (fn [joint]
566 (let [[obj-a obj-b]
567 (joint-targets pieces joint)]
568 (connect obj-a obj-b joint)))
569 joints))
570 pieces)
572 (defn the-worm []
573 (physical-worm (worm) (worm-joints)))
575 (defn test-worm []
576 (world
577 (nodify [(the-worm)
578 (box 10 2 10 :position (Vector3f. 0 -5 0)
579 :color ColorRGBA/Gray :mass 0)])
580 standard-debug-controls
581 (comp light-up-everything enable-debug
582 (fn [world]
583 (.setTimer world (NanoTimer.))
584 (speed-up world)
585 ;;(set-gravity world (Vector3f. 0 0 0))
586 world
587 ))
588 no-op))
590 #+end_src
592 #+results: body-1
593 : #'cortex.silly/test-try-again
597 * COMMENT generate source
598 #+begin_src clojure :tangle ../src/cortex/silly.clj
599 <<body-1>>
600 #+end_src