view org/test-creature.org @ 85:00ab1f10266f

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