view org/test-creature.org @ 83:14b604e955ed

still testing joints... Dylan is helping
author Robert McIntyre <rlm@mit.edu>
date Sat, 07 Jan 2012 00:58:47 -0700
parents 6b4ca076285e
children 4f5e2c629e45
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 (rlm.rlm-commands/help)
53 (declare joint-create get-subjective-position)
55 (defn load-bullet []
56 (.start (world (Node.) {} no-op no-op)))
58 (defn load-blender-model
59 "Load a .blend file using an asset folder relative path."
60 [^String model]
61 (.loadModel
62 (doto (asset-manager)
63 (.registerLoader BlenderModelLoader (into-array String ["blend"])))
64 model))
66 (defn meta-data [blender-node key]
67 (if-let [data (.getUserData blender-node "properties")]
68 (.findValue data key)
69 nil))
71 (defn blender-to-jme
72 "Convert from Blender coordinates to JME coordinates"
73 [#^Vector3f in]
74 (Vector3f. (.getX in)
75 (.getZ in)
76 (- (.getY in))))
78 (defn jme-to-blender
79 "Convert from JME coordinates to Blender coordinates"
80 [#^Vector3f in]
81 (Vector3f. (.getX in)
82 (- (.getZ in))
83 (.getY in)))
85 (defn joint-targets
86 "Return the two closest two objects to the joint object, ordered
87 from bottom to top according to the joint's rotation."
88 [#^Node parts #^Node joint]
89 ;;(println (meta-data joint "joint"))
90 (.getWorldRotation joint)
91 (loop [radius (float 0.01)]
92 (let [results (CollisionResults.)]
93 (.collideWith
94 parts
95 (BoundingBox. (.getWorldTranslation joint)
96 radius radius radius)
97 results)
98 (let [targets
99 (distinct
100 (map #(.getGeometry %) results))]
101 (if (>= (count targets) 2)
102 (sort-by
103 #(let [v
104 (jme-to-blender
105 (.mult
106 (.inverse (.getWorldRotation joint))
107 (.subtract (.getWorldTranslation %)
108 (.getWorldTranslation joint))))]
109 (println-repl (.getName %) ":" v)
110 (.dot (Vector3f. 1 1 1)
111 v))
112 (take 2 targets))
113 (recur (float (* radius 2))))))))
115 (defn connect
116 "here are some examples:
117 {:type :point}
118 {:type :hinge :limit [0 (/ Math/PI 2)] :axis (Vector3f. 0 1 0)}
119 (:axis defaults to (Vector3f. 1 0 0) if not provided for hinge joints)
121 {:type :cone :limit-xz 0]
122 :limit-xy 0]
123 :twist 0]} (use XZY rotation mode in blender!)"
124 [#^Node obj-a #^Node obj-b #^Node joint]
125 (let [center-a (.getWorldTranslation obj-a)
126 center-b (.getWorldTranslation obj-b)
127 joint-center (.getWorldTranslation joint)
128 pivot-a (.subtract joint-center center-a)
129 pivot-b (.subtract joint-center center-b)
130 control-a (.getControl obj-a RigidBodyControl)
131 control-b (.getControl obj-b RigidBodyControl)]
132 ;; A side-effect of creating a joint registers
133 ;; it with both physics objects which in turn
134 ;; will register the joint with the physics system
135 ;; when the simulation is started.
136 (if-let [constraints
137 (map-vals
138 eval
139 (read-string
140 (meta-data joint "joint")))]
142 (let [joint-type (:type constraints)]
143 (println-repl "creating joint between"
144 (.getName obj-a) "and" (.getName obj-b))
145 (cond (= :point joint-type)
146 (do
147 (println-repl "creating POINT joint")
148 (Point2PointJoint.
149 control-a
150 control-b
151 pivot-a
152 pivot-b))
153 (= :hinge joint-type)
154 (do
155 (println-repl "creating HINGE joint")
156 (let [axis (if-let
157 [axis (:axis constraints)]
158 axis
159 Vector3f/UNIT_X)
160 [limit-1 limit-2] (:limit constraints)
161 hinge-axis
162 (.mult
163 (.getWorldRotation joint)
164 (blender-to-jme axis))]
165 (doto
166 (HingeJoint.
167 control-a
168 control-b
169 pivot-a
170 pivot-b
171 hinge-axis
172 hinge-axis)
173 (.setLimit limit-1 limit-2))))
174 (= :cone joint-type)
175 (do
176 (let [limit-xz (:limit-xz constraints)
177 limit-xy (:limit-xy constraints)
178 twist (:twist constraints)]
180 (println-repl "creating CONE joint")
181 (let [frame-a
182 (.toRotationMatrix
183 (doto (Quaternion.)
184 (.fromAngleAxis
185 (float
186 (.angleBetween
187 (.normalize pivot-a) Vector3f/UNIT_X))
188 (.normalize
189 (.cross pivot-a
190 Vector3f/UNIT_X)))))
191 ]
192 (println-repl "pivot-a" pivot-a)
193 (println-repl
194 "angle between pivot-a and UNIT_X is"
195 (.angleBetween Vector3f/UNIT_X (.normalize pivot-a)))
196 (println-repl "frame-a:" frame-a)
197 (println-repl
198 "frame-a moves Vector3f/UNIT_X to"
199 (.mult frame-a Vector3f/UNIT_X ))
202 (doto
203 (ConeJoint.
204 control-a
205 control-b
206 pivot-a
207 pivot-b
210 ;; frame-in-A
211 ;;frame-a
212 ;;frame-a
214 (.toRotationMatrix
215 (doto (Quaternion.)
216 (.fromAngles
217 0 0 (* -0.5 (/ Math/PI 2)))))
220 ;; frame-in-B
221 (.toRotationMatrix
222 (doto (Quaternion.)
223 (.fromAngles
224 0 0 (* -0.5 (/ Math/PI 2)))))
227 )
228 (.setLimit (float limit-xz)
229 (float limit-xy)
230 (float twist))))))
231 true
232 (println-repl
233 "joint-type" joint-type "not recognized")))
235 (println-repl "could not find joint meta-data!"))))
238 (defn assemble-creature [#^Node pieces joints]
239 (dorun
240 (map
241 (fn [geom]
242 (let [physics-control
243 (RigidBodyControl.
244 (HullCollisionShape.
245 (.getMesh geom))
246 (if-let [mass (meta-data geom "mass")]
247 (do
248 (println-repl
249 "setting" (.getName geom) "mass to" (float mass))
250 (float mass))
251 (float 1)))]
253 (.addControl geom physics-control)))
254 (filter #(isa? (class %) Geometry )
255 (node-seq pieces))))
257 (dorun
258 (map
259 (fn [joint]
260 (let [[obj-a obj-b]
261 (joint-targets pieces joint)]
262 (connect obj-a obj-b joint)))
263 joints))
264 pieces)
266 (defn blender-creature [blender-path]
267 (let [model (load-blender-model blender-path)
268 joints
269 (if-let [joint-node (.getChild model "joints")]
270 (seq (.getChildren joint-node))
271 (do (println-repl "could not find joints node")
272 []))]
273 (assemble-creature model joints)))
275 (def hand "Models/creature1/one.blend")
277 (def worm "Models/creature1/try-again.blend")
279 (defn x-ray [#^ColorRGBA color]
280 (doto (Material. (asset-manager)
281 "Common/MatDefs/Misc/Unshaded.j3md")
282 (.setColor "Color" color)
283 (-> (.getAdditionalRenderState)
284 (.setDepthTest false))))
286 (defn test-creature [thing]
287 (let [x-axis
288 (box 1 0.01 0.01 :physical? false :color ColorRGBA/Red)
289 y-axis
290 (box 0.01 1 0.01 :physical? false :color ColorRGBA/Green)
291 z-axis
292 (box 0.01 0.01 1 :physical? false :color ColorRGBA/Blue)]
293 (world
294 (nodify [(blender-creature thing)
295 (box 10 2 10 :position (Vector3f. 0 -9 0)
296 :color ColorRGBA/Gray :mass 0)
297 x-axis y-axis z-axis
298 ])
299 standard-debug-controls
300 (comp light-up-everything enable-debug
301 (fn [world]
302 (.setTimer world (NanoTimer.))
303 (set-gravity world (Vector3f. 0 0 0))
304 (speed-up world)
305 world
306 ))
307 no-op)))
309 (defn world-setup [joint]
310 (let [
312 joint-position (Vector3f. 0 4 0)
313 joint-rotation
314 (.toRotationMatrix
315 (.mult
316 (doto (Quaternion.)
317 (.fromAngleAxis
318 (* 1 (/ Math/PI 4))
319 (Vector3f. -1 0 0)))
320 (doto (Quaternion.)
321 (.fromAngleAxis
322 (/ Math/PI 2)
323 (Vector3f. 0 0 1)))))
325 origin (doto
326 (sphere 0.1 :physical? false :color ColorRGBA/Cyan
327 :position (Vector3f. 0 0 0)))
328 top (doto
329 (sphere 0.1 :physical? false :color ColorRGBA/Yellow
330 :position (.mult joint-rotation (Vector3f. 8 0 0)))
332 (.addControl
333 (RigidBodyControl.
334 (CapsuleCollisionShape. 0.5 1.5 1) (float 20))))
335 bottom (doto
336 (sphere 0.1 :physical? false :color ColorRGBA/DarkGray
337 :position (Vector3f. 0 0 0))
338 (.addControl
339 (RigidBodyControl.
340 (CapsuleCollisionShape. 0.5 1.5 1) (float 0))))
341 table (box 10 2 10 :position (Vector3f. 0 -20 0)
342 :color ColorRGBA/Gray :mass 0)
343 a (.getControl top RigidBodyControl)
344 b (.getControl bottom RigidBodyControl)]
346 (cond
347 (= joint :cone)
349 (doto (ConeJoint.
350 a b
351 (get-subjective-position joint-position top)
352 (get-subjective-position joint-position bottom)
353 joint-rotation
354 joint-rotation
355 )
358 (.setLimit (* (/ 10) Math/PI)
359 (* (/ 4) Math/PI)
360 0)))
361 [origin top bottom table]))
365 (defn test-joint [joint]
366 (let [[origin top bottom floor] (world-setup joint)
367 control (.getControl top RigidBodyControl)
368 move-up? (atom false)
369 move-down? (atom false)
370 move-left? (atom false)
371 move-right? (atom false)
372 roll-left? (atom false)
373 roll-right? (atom false)
374 timer (atom 0)]
376 (world
377 (nodify [top bottom floor origin])
378 (merge standard-debug-controls
379 {"key-r" (fn [_ pressed?] (reset! move-up? pressed?))
380 "key-t" (fn [_ pressed?] (reset! move-down? pressed?))
381 "key-f" (fn [_ pressed?] (reset! move-left? pressed?))
382 "key-g" (fn [_ pressed?] (reset! move-right? pressed?))
383 "key-v" (fn [_ pressed?] (reset! roll-left? pressed?))
384 "key-b" (fn [_ pressed?] (reset! roll-right? pressed?))})
386 (fn [world]
387 (light-up-everything world)
388 (enable-debug world)
389 (set-gravity world (Vector3f. 0 0 0))
390 )
392 (fn [world _]
393 (if (zero? (rem (swap! timer inc) 100))
394 (do
395 ;; (println-repl @timer)
396 (.attachChild (.getRootNode world)
397 (sphere 0.05 :color ColorRGBA/Yellow
398 :position (.getWorldTranslation top)
399 :physical? false))
400 (.attachChild (.getRootNode world)
401 (sphere 0.05 :color ColorRGBA/LightGray
402 :position (.getWorldTranslation bottom)
403 :physical? false))))
405 (if @move-up?
406 (.applyTorque control
407 (.mult (.getPhysicsRotation control)
408 (Vector3f. 0 0 10))))
409 (if @move-down?
410 (.applyTorque control
411 (.mult (.getPhysicsRotation control)
412 (Vector3f. 0 0 -10))))
413 (if @move-left?
414 (.applyTorque control
415 (.mult (.getPhysicsRotation control)
416 (Vector3f. 0 10 0))))
417 (if @move-right?
418 (.applyTorque control
419 (.mult (.getPhysicsRotation control)
420 (Vector3f. 0 -10 0))))
421 (if @roll-left?
422 (.applyTorque control
423 (.mult (.getPhysicsRotation control)
424 (Vector3f. -1 0 0))))
425 (if @roll-right?
426 (.applyTorque control
427 (.mult (.getPhysicsRotation control)
428 (Vector3f. 1 0 0))))))))
442 ;; please validate these.
444 (defn get-subjective-position
445 "Convert the world coordinates into coordinates relative to
446 object (i.e. local coordinates), taking into account the rotation
447 of object."
448 [#^Vector3f world-coordinates object]
449 ;; I don't know if it's important to take into account the rotation
450 ;; of the object. If it isn't, then remove the multiplication-by-inverse.
451 (.mult (.inverse (.getWorldRotation object))
452 (.subtract world-coordinates (.getWorldTranslation object))))
455 (defn get-subjective-rotation
456 "cf get-subjective-position. Converts a rotation specified relative
457 to the world's axes into a rotation specified in terms of the object's
458 coordinate system."
459 [#^Quaternion world-rotation object]
460 (.mult (.inverse (.getWorldRotation object)) world-rotation))
465 (defn joint-create "Connect objects 1 and 2 using a joint constraint. If
466 only position is specified, creates a point-to-point joint at the
467 given location
468 in world coordinates. etc. etc. for other joints.
469 To ensure consistency, I may alter this function
470 so that it moves obj-1 to be at the apex of the cone.
472 NOTE:
473 In the usual construction method, you create a joint and, if your
474 contraints are consistent, all the objects snap into position and
475 orientation around it, otherwise the systen explodes.
477 This construction method assumes that you have in mind a position and
478 rotation for the joint, and that you have already put your objects
479 at the required distances from that joint so that no snapping needs
480 to occur. The radial distances ('pivot lengths') are therefore just set to be
481 the pre-existing distances between the objects and the joint."
482 [#^Node obj-1
483 #^Node obj-2
484 #^Vector3f joint-position
485 #^Quaternion joint-rotation
486 span-1
487 span-2
488 twist
489 ]
491 (let
492 [body-1 (.getControl obj-1 RigidBodyControl)
493 body-2 (.getControl obj-2 RigidBodyControl)
494 ]
495 (doto (ConeJoint.
496 body-1
497 body-2
498 (get-subjective-position joint-position body-1)
499 (get-subjective-position joint-position body-2)
500 ;; ALIGN X-AXIS OF OBJECT-1 WITH THE CENTRAL AXIS OF THE CONE TO
501 ;;LOWER THE RISK OF INCONSISTENCY
502 ;;(Matrix3f/IDENTITY)
503 (.toRotationMatrix (get-subjective-rotation joint-rotation body-1))
504 (.toRotationMatrix (get-subjective-rotation joint-rotation body-2))
505 )
506 (.setLimit
507 span-1
508 span-2
509 twist))))
516 #+end_src
519 * COMMENT purgatory
520 #+begin_src clojure
521 (defn bullet-trans []
522 (let [obj-a (sphere 0.5 :color ColorRGBA/Red
523 :position (Vector3f. -10 5 0))
524 obj-b (sphere 0.5 :color ColorRGBA/Blue
525 :position (Vector3f. -10 -5 0)
526 :mass 0)
527 control-a (.getControl obj-a RigidBodyControl)
528 control-b (.getControl obj-b RigidBodyControl)
529 swivel
530 (.toRotationMatrix
531 (doto (Quaternion.)
532 (.fromAngleAxis (/ Math/PI 2)
533 Vector3f/UNIT_X)))]
534 (doto
535 (ConeJoint.
536 control-a control-b
537 (Vector3f. 0 5 0)
538 (Vector3f. 0 -5 0)
539 swivel swivel)
540 (.setLimit (* 0.6 (/ Math/PI 4))
541 (/ Math/PI 4)
542 (* Math/PI 0.8)))
543 (world (nodify
544 [obj-a obj-b])
545 standard-debug-controls
546 enable-debug
547 no-op)))
550 (defn bullet-trans* []
551 (let [obj-a (box 1.5 0.5 0.5 :color ColorRGBA/Red
552 :position (Vector3f. 5 0 0)
553 :mass 90)
554 obj-b (sphere 0.5 :color ColorRGBA/Blue
555 :position (Vector3f. -5 0 0)
556 :mass 0)
557 control-a (.getControl obj-a RigidBodyControl)
558 control-b (.getControl obj-b RigidBodyControl)
559 move-up? (atom nil)
560 move-down? (atom nil)
561 move-left? (atom nil)
562 move-right? (atom nil)
563 roll-left? (atom nil)
564 roll-right? (atom nil)
565 force 100
566 swivel
567 (.toRotationMatrix
568 (doto (Quaternion.)
569 (.fromAngleAxis (/ Math/PI 2)
570 Vector3f/UNIT_X)))
571 x-move
572 (doto (Matrix3f.)
573 (.fromStartEndVectors Vector3f/UNIT_X
574 (.normalize (Vector3f. 1 1 0))))
576 timer (atom 0)]
577 (doto
578 (ConeJoint.
579 control-a control-b
580 (Vector3f. -8 0 0)
581 (Vector3f. 2 0 0)
582 ;;swivel swivel
583 ;;Matrix3f/IDENTITY Matrix3f/IDENTITY
584 x-move Matrix3f/IDENTITY
585 )
586 (.setCollisionBetweenLinkedBodys false)
587 (.setLimit (* 1 (/ Math/PI 4)) ;; twist
588 (* 1 (/ Math/PI 4)) ;; swing span in X-Y plane
589 (* 0 (/ Math/PI 4)))) ;; swing span in Y-Z plane
590 (world (nodify
591 [obj-a obj-b])
592 (merge standard-debug-controls
593 {"key-r" (fn [_ pressed?] (reset! move-up? pressed?))
594 "key-t" (fn [_ pressed?] (reset! move-down? pressed?))
595 "key-f" (fn [_ pressed?] (reset! move-left? pressed?))
596 "key-g" (fn [_ pressed?] (reset! move-right? pressed?))
597 "key-v" (fn [_ pressed?] (reset! roll-left? pressed?))
598 "key-b" (fn [_ pressed?] (reset! roll-right? pressed?))})
600 (fn [world]
601 (enable-debug world)
602 (set-gravity world Vector3f/ZERO)
603 )
605 (fn [world _]
607 (if @move-up?
608 (.applyForce control-a
609 (Vector3f. force 0 0)
610 (Vector3f. 0 0 0)))
611 (if @move-down?
612 (.applyForce control-a
613 (Vector3f. (- force) 0 0)
614 (Vector3f. 0 0 0)))
615 (if @move-left?
616 (.applyForce control-a
617 (Vector3f. 0 force 0)
618 (Vector3f. 0 0 0)))
619 (if @move-right?
620 (.applyForce control-a
621 (Vector3f. 0 (- force) 0)
622 (Vector3f. 0 0 0)))
624 (if @roll-left?
625 (.applyForce control-a
626 (Vector3f. 0 0 force)
627 (Vector3f. 0 0 0)))
628 (if @roll-right?
629 (.applyForce control-a
630 (Vector3f. 0 0 (- force))
631 (Vector3f. 0 0 0)))
633 (if (zero? (rem (swap! timer inc) 100))
634 (.attachChild
635 (.getRootNode world)
636 (sphere 0.05 :color ColorRGBA/Yellow
637 :physical? false :position
638 (.getWorldTranslation obj-a)))))
639 )
640 ))
644 #+end_src
647 * COMMENT generate source
648 #+begin_src clojure :tangle ../src/cortex/silly.clj
649 <<body-1>>
650 #+end_src