view org/body.org @ 132:3206d5e20bee

still trying to fix proprioception
author Robert McIntyre <rlm@mit.edu>
date Tue, 31 Jan 2012 01:40:47 -0700
parents e98850b83c2c
children 2ed7e60d3821
line wrap: on
line source
1 #+title: The BODY!!!
2 #+author: Robert McIntyre
3 #+email: rlm@mit.edu
4 #+description: Simulating a body (movement, touch, propioception) in jMonkeyEngine3.
5 #+SETUPFILE: ../../aurellem/org/setup.org
6 #+INCLUDE: ../../aurellem/org/level-0.org
8 * Proprioception
9 #+name: proprioception
10 #+begin_src clojure
11 (ns cortex.body
12 (:use (cortex world util))
13 (:import
14 com.jme3.math.Vector3f
15 com.jme3.math.Quaternion
16 com.jme3.math.Vector2f
17 com.jme3.math.Matrix3f
18 com.jme3.bullet.control.RigidBodyControl))
22 (defn quaternion-decompose [#^Quaternion q]
23 (map
24 #(arc-between % (.rotate q %))
25 [Vector3f/UNIT_X
26 Vector3f/UNIT_Y
27 Vector3f/UNIT_Z]))
29 (defn any-orthogonal
30 "Generate an arbitray (but stable) orthogonal vector to a given
31 vector."
32 [vector]
33 (let [x (.getX vector)
34 y (.getY vector)
35 z (.getZ vector)]
36 (cond
37 (not= x (float 0)) (Vector3f. (- z) 0 x)
38 (not= y (float 0)) (Vector3f. 0 (- z) y)
39 (not= z (float 0)) (Vector3f. 0 (- z) y)
40 true Vector3f/ZERO)))
42 (defn project-quaternion
43 "From http://stackoverflow.com/questions/3684269/
44 component-of-a-quaternion-rotation-around-an-axis.
46 Determine the amount of rotation a quaternion will
47 cause about a given axis."
48 [#^Quaternion q #^Vector3f axis]
49 (let [basis-1 (any-orthogonal axis)
50 basis-2 (.cross axis basis-1)
51 rotated (.mult q basis-1)
52 alpha (.dot basis-1 (.project rotated basis-1))
53 beta (.dot basis-2 (.project rotated basis-2))]
54 (Math/atan2 beta alpha)))
56 (defn right-handed? [vec1 vec2 vec3]
57 (< 0 (.dot (.cross vec1 vec2) vec3)))
59 (defn project-quaternion
60 "From http://stackoverflow.com/questions/3684269/
61 component-of-a-quaternion-rotation-around-an-axis.
63 Determine the amount of rotation a quaternion will
64 cause about a given axis."
65 [#^Quaternion q #^Vector3f axis]
66 (let [axis (.normalize axis)
67 basis-1 (any-orthogonal axis)
68 basis-2 (.cross axis basis-1)
69 rotated (.mult q basis-1)
70 rotated-in-plane (.add (.project rotated basis-1)
71 (.project rotated basis-2))]
73 ;; be sure to get sign from cross product
74 (if (right-handed? basis-1 rotated-in-plane axis)
75 (.angleBetween rotated-in-plane basis-1)
76 (- (* 2 Math/PI) (.angleBetween rotated-in-plane basis-1)))))
80 (defn joint-proprioception
81 "Relative position information for a two-part system connected by a
82 joint. Gives the pitch, yaw, and roll of the 'B' object relative to
83 the 'A' object, as determined by the joint."
84 [joint]
85 (let [object-a (.getUserObject (.getBodyA joint))
86 object-b (.getUserObject (.getBodyB joint))
87 arm-a
88 (.normalize
89 (.subtract
90 (.localToWorld object-a (.getPivotA joint) nil)
91 (.getWorldTranslation object-a)))
93 ;; this is probably wrong!
94 rotate-a
95 (doto (Matrix3f.)
96 (.fromStartEndVectors arm-a Vector3f/UNIT_X))
98 arm-b
99 (.mult
100 rotate-a
101 (.normalize
102 (.subtract
103 (.localToWorld object-b (.getPivotB joint) nil)
104 (.getWorldTranslation object-b))))
105 pitch
106 (.angleBetween
107 (.normalize (Vector2f. (.getX arm-b) (.getY arm-b)))
108 (Vector2f. 1 0))
109 yaw
110 (.angleBetween
111 (.normalize (Vector2f. (.getX arm-b) (.getZ arm-b)))
112 (Vector2f. 1 0))
114 roll
115 (project-quaternion
116 (.mult
117 (.getLocalRotation object-b)
118 (doto (Quaternion.)
119 (.fromRotationMatrix rotate-a)))
120 arm-b)]
121 ;;(println-repl (.getName object-a) (.getName object-b))
122 [pitch yaw roll]))
127 (defn absolute-angle-between
128 [vec-1 vec-2]
133 (defn joint-proprioception
134 [joint]
135 (let [object-a (.getUserObject (.getBodyA joint))
136 object-b (.getUserObject (.getBodyB joint))
138 arm-a
139 (.normalize
140 (.subtract
141 (.localToWorld object-a (.getPivotA joint) nil)
142 (.getWorldTranslation object-a)))
143 arm-b
144 (.normalize
145 (.subtract
146 (.localToWorld object-b (.getPivotB joint) nil)
147 (.getWorldTranslation object-b)))
149 rotate-a (.clone (.getWorldRotation object-a))
150 unrotate-a (.inverse (.getWorldRotation object-a))
152 canonical-arm-a (.mult unrotate-a arm-a)
154 basis-1 (any-orthogonal canonical-arm-a)
155 basis-2 (.normalize (.cross basis-1 canonical-arm-a))
157 pitch (.angleBetween arm-b basis-1)
158 yaw (.angleBetween arm-b basis-2)
160 twist-a
161 (project-quaternion
162 (.getWorldRotation object-a) arm-a)
164 twist-b
165 (project-quaternion
166 (.getWorldRotation object-b) arm-b)
168 roll (- twist-b 0)
169 ;; "un-rotate" arm-a to it's canonical position, get two
170 ;; orthogonal basis vectors. Rotate those two vectors back to
171 ;; the correct position get the rotations between them.
173 ;; twist is the rotation about arm-a of obj-b minus the
174 ;; rotation about arm-a of obj-a
175 ]
176 ;; object-a == hand
177 ;; object-b == finger
178 [pitch yaw roll]))
180 ;; (defn joint-proprioception*
181 ;; [joint]
182 ;; (let [object-a (.getUserObject (.getBodyA joint))
183 ;; object-b (.getUserObject (.getBodyB joint))
185 ;; rotate-a (.clone (.getWorldRotation object-a))
186 ;; rotate-b (.clone (.getWorldRotation object-b))
188 ;; rotate-rel (.mult rotate-b (.inverse rotate-a))
189 ;; ]
190 ;; ((comp vec map) (partial project-quaternion rotate-rel)
191 ;; [Vector3f/UNIT_X
192 ;; Vector3f/UNIT_Y
193 ;; Vector3f/UNIT_Z])))
196 (defn proprioception
197 "Create a function that provides proprioceptive information about an
198 entire body."
199 [body]
200 ;; extract the body's joints
201 (let [joints
202 (distinct
203 (reduce
204 concat
205 (map #(.getJoints %)
206 (keep
207 #(.getControl % RigidBodyControl)
208 (node-seq body)))))]
209 (fn []
210 (map joint-proprioception joints))))
212 #+end_src
214 * Motor Control
215 #+name: motor-control
216 #+begin_src clojure
217 (in-ns 'cortex.body)
219 ;; surprisingly enough, terristerial creatures only move by using
220 ;; torque applied about their joints. There's not a single straight
221 ;; line of force in the human body at all! (A straight line of force
222 ;; would correspond to some sort of jet or rocket propulseion.)
224 (defn vector-motor-control
225 "Create a function that accepts a sequence of Vector3f objects that
226 describe the torque to be applied to each part of the body."
227 [body]
228 (let [nodes (node-seq body)
229 controls (keep #(.getControl % RigidBodyControl) nodes)]
230 (fn [torques]
231 (map #(.applyTorque %1 %2)
232 controls torques))))
233 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
234 #+end_src
236 ## note -- might want to add a lower dimensional, discrete version of
237 ## this if it proves useful from a x-modal clustering perspective.
239 * Examples
241 #+name: test-body
242 #+begin_src clojure
243 (ns cortex.test.body
244 (:use (cortex world util body))
245 (:import
246 com.jme3.math.Vector3f
247 com.jme3.math.ColorRGBA
248 com.jme3.bullet.joints.Point2PointJoint
249 com.jme3.bullet.control.RigidBodyControl
250 com.jme3.system.NanoTimer))
252 (defn worm-segments
253 "Create multiple evenly spaced box segments. They're fabulous!"
254 [segment-length num-segments interstitial-space radius]
255 (letfn [(nth-segment
256 [n]
257 (box segment-length radius radius :mass 0.1
258 :position
259 (Vector3f.
260 (* 2 n (+ interstitial-space segment-length)) 0 0)
261 :name (str "worm-segment" n)
262 :color (ColorRGBA/randomColor)))]
263 (map nth-segment (range num-segments))))
265 (defn connect-at-midpoint
266 "Connect two physics objects with a Point2Point joint constraint at
267 the point equidistant from both objects' centers."
268 [segmentA segmentB]
269 (let [centerA (.getWorldTranslation segmentA)
270 centerB (.getWorldTranslation segmentB)
271 midpoint (.mult (.add centerA centerB) (float 0.5))
272 pivotA (.subtract midpoint centerA)
273 pivotB (.subtract midpoint centerB)
275 ;; A side-effect of creating a joint registers
276 ;; it with both physics objects which in turn
277 ;; will register the joint with the physics system
278 ;; when the simulation is started.
279 joint (Point2PointJoint.
280 (.getControl segmentA RigidBodyControl)
281 (.getControl segmentB RigidBodyControl)
282 pivotA
283 pivotB)]
284 segmentB))
286 (defn eve-worm
287 "Create a worm-like body bound by invisible joint constraints."
288 []
289 (let [segments (worm-segments 0.2 5 0.1 0.1)]
290 (dorun (map (partial apply connect-at-midpoint)
291 (partition 2 1 segments)))
292 (nodify "worm" segments)))
294 (defn worm-pattern
295 "This is a simple, mindless motor control pattern that drives the
296 second segment of the worm's body at an offset angle with
297 sinusoidally varying strength."
298 [time]
299 (let [angle (* Math/PI (/ 9 20))
300 direction (Vector3f. 0 (Math/sin angle) (Math/cos angle))]
301 [Vector3f/ZERO
302 (.mult
303 direction
304 (float (* 2 (Math/sin (* Math/PI 2 (/ (rem time 300 ) 300))))))
305 Vector3f/ZERO
306 Vector3f/ZERO
307 Vector3f/ZERO]))
309 (defn test-motor-control
310 "Testing motor-control:
311 You should see a multi-segmented worm-like object fall onto the
312 table and begin writhing and moving."
313 []
314 (let [worm (eve-worm)
315 time (atom 0)
316 worm-motor-map (vector-motor-control worm)]
317 (world
318 (nodify [worm
319 (box 10 0.5 10 :position (Vector3f. 0 -5 0) :mass 0
320 :color ColorRGBA/Gray)])
321 standard-debug-controls
322 (fn [world]
323 (enable-debug world)
324 (light-up-everything world)
325 (comment
326 (com.aurellem.capture.Capture/captureVideo
327 world
328 (file-str "/home/r/proj/cortex/tmp/moving-worm")))
329 )
331 (fn [_ _]
332 (swap! time inc)
333 (Thread/sleep 20)
334 (dorun (worm-motor-map
335 (worm-pattern @time)))))))
338 (require 'cortex.silly)
339 (defn join-at-point [obj-a obj-b world-pivot]
340 (cortex.silly/joint-dispatch
341 {:type :point}
342 (.getControl obj-a RigidBodyControl)
343 (.getControl obj-b RigidBodyControl)
344 (cortex.silly/world-to-local obj-a world-pivot)
345 (cortex.silly/world-to-local obj-b world-pivot)
346 nil
347 ))
351 (defn blab-* []
352 (let [hand (box 0.5 0.2 0.2 :position (Vector3f. 0 0 0)
353 :mass 0 :color ColorRGBA/Green)
354 finger (box 0.5 0.2 0.2 :position (Vector3f. 2.4 0 0)
355 :mass 1 :color ColorRGBA/Red)
356 connection-point (Vector3f. 1.2 0 0)
357 root (nodify [hand finger])]
359 (join-at-point hand finger (Vector3f. 1.2 0 0))
361 (.setCollisionGroup
362 (.getControl hand RigidBodyControl)
363 PhysicsCollisionObject/COLLISION_GROUP_NONE)
364 (world
365 root
366 standard-debug-controls
367 (fn [world]
368 (enable-debug world)
369 (.setTimer world (com.aurellem.capture.RatchetTimer. 60))
370 (set-gravity world Vector3f/ZERO)
371 )
372 no-op)))
373 (import java.awt.image.BufferedImage)
375 (defn draw-sprite [image sprite x y color ]
376 (dorun
377 (for [[u v] sprite]
378 (.setRGB image (+ u x) (+ v y) color))))
380 (defn view-angle
381 "create a debug view of an angle"
382 [color]
383 (let [image (BufferedImage. 50 50 BufferedImage/TYPE_INT_RGB)
384 previous (atom [25 25])
385 sprite [[0 0] [0 1]
386 [0 -1] [-1 0] [1 0]]]
387 (fn [angle]
388 (let [angle (float angle)]
389 (let [position
390 [(+ 25 (int (* 20 (Math/cos angle))))
391 (+ 25 (int (* 20(Math/sin angle))))]]
392 (draw-sprite image sprite (@previous 0) (@previous 1) 0x000000)
393 (draw-sprite image sprite (position 0) (position 1) color)
394 (reset! previous position))
395 image))))
397 (defn proprioception-debug-window
398 []
399 (let [yaw (view-angle 0xFF0000)
400 pitch (view-angle 0x00FF00)
401 roll (view-angle 0xFFFFFF)
402 v-yaw (view-image)
403 v-pitch (view-image)
404 v-roll (view-image)
405 ]
406 (fn [prop-data]
407 (dorun
408 (map
409 (fn [[p y r]]
410 (v-yaw (yaw y))
411 (v-roll (roll r))
412 (v-pitch (pitch p)))
413 prop-data)))))
415 (comment
416 (dorun
417 (map
418 (comp
419 println-repl
420 (fn [[p y r]]
421 (format
422 "pitch: %1.2f\nyaw: %1.2f\nroll: %1.2f\n"
423 p y r)))
424 prop-data)))
430 (defn test-proprioception
431 "Testing proprioception:
432 You should see two foating bars, and a printout of pitch, yaw, and
433 roll. Pressing key-r/key-t should move the blue bar up and down and
434 change only the value of pitch. key-f/key-g moves it side to side
435 and changes yaw. key-v/key-b will spin the blue segment clockwise
436 and counterclockwise, and only affect roll."
437 []
438 (let [hand (box 1 0.2 0.2 :position (Vector3f. 0 2 0)
439 :mass 0 :color ColorRGBA/Green :name "hand")
440 finger (box 1 0.2 0.2 :position (Vector3f. 2.4 2 0)
441 :mass 1 :color ColorRGBA/Red :name "finger")
442 floor (box 10 0.5 10 :position (Vector3f. 0 -5 0)
443 :mass 0 :color ColorRGBA/Gray)
445 move-up? (atom false)
446 move-down? (atom false)
447 move-left? (atom false)
448 move-right? (atom false)
449 roll-left? (atom false)
450 roll-right? (atom false)
451 control (.getControl finger RigidBodyControl)
452 time (atom 0)
453 joint (join-at-point hand finger (Vector3f. 1.2 2 0 ))
454 creature (nodify [hand finger])
455 prop (proprioception creature)
457 prop-view (proprioception-debug-window)
460 ]
464 (.setCollisionGroup
465 (.getControl hand RigidBodyControl)
466 PhysicsCollisionObject/COLLISION_GROUP_NONE)
469 (world
470 (nodify [hand finger floor])
471 (merge standard-debug-controls
472 {"key-r" (fn [_ pressed?] (reset! move-up? pressed?))
473 "key-t" (fn [_ pressed?] (reset! move-down? pressed?))
474 "key-f" (fn [_ pressed?] (reset! move-left? pressed?))
475 "key-g" (fn [_ pressed?] (reset! move-right? pressed?))
476 "key-v" (fn [_ pressed?] (reset! roll-left? pressed?))
477 "key-b" (fn [_ pressed?] (reset! roll-right? pressed?))})
478 (fn [world]
479 (.setTimer world (com.aurellem.capture.RatchetTimer. 60))
480 (set-gravity world (Vector3f. 0 0 0))
481 (light-up-everything world))
482 (fn [_ _]
483 (if @move-up?
484 (.applyTorque control
485 (.mult (.getPhysicsRotation control)
486 (Vector3f. 0 0 10))))
487 (if @move-down?
488 (.applyTorque control
489 (.mult (.getPhysicsRotation control)
490 (Vector3f. 0 0 -10))))
491 (if @move-left?
492 (.applyTorque control
493 (.mult (.getPhysicsRotation control)
494 (Vector3f. 0 10 0))))
495 (if @move-right?
496 (.applyTorque control
497 (.mult (.getPhysicsRotation control)
498 (Vector3f. 0 -10 0))))
499 (if @roll-left?
500 (.applyTorque control
501 (.mult (.getPhysicsRotation control)
502 (Vector3f. -1 0 0))))
503 (if @roll-right?
504 (.applyTorque control
505 (.mult (.getPhysicsRotation control)
506 (Vector3f. 1 0 0))))
508 ;;(if (= 0 (rem (swap! time inc) 20))
509 (prop-view (prop))))))
511 #+end_src
513 #+results: test-body
514 : #'cortex.test.body/test-proprioception
517 * COMMENT code-limbo
518 #+begin_src clojure
519 ;;(.loadModel
520 ;; (doto (asset-manager)
521 ;; (.registerLoader BlenderModelLoader (into-array String ["blend"])))
522 ;; "Models/person/person.blend")
525 (defn load-blender-model
526 "Load a .blend file using an asset folder relative path."
527 [^String model]
528 (.loadModel
529 (doto (asset-manager)
530 (.registerLoader BlenderModelLoader (into-array String ["blend"])))
531 model))
534 (defn view-model [^String model]
535 (view
536 (.loadModel
537 (doto (asset-manager)
538 (.registerLoader BlenderModelLoader (into-array String ["blend"])))
539 model)))
541 (defn load-blender-scene [^String model]
542 (.loadModel
543 (doto (asset-manager)
544 (.registerLoader BlenderLoader (into-array String ["blend"])))
545 model))
547 (defn worm
548 []
549 (.loadModel (asset-manager) "Models/anim2/Cube.mesh.xml"))
551 (defn oto
552 []
553 (.loadModel (asset-manager) "Models/Oto/Oto.mesh.xml"))
555 (defn sinbad
556 []
557 (.loadModel (asset-manager) "Models/Sinbad/Sinbad.mesh.xml"))
559 (defn worm-blender
560 []
561 (first (seq (.getChildren (load-blender-model
562 "Models/anim2/simple-worm.blend")))))
564 (defn body
565 "given a node with a SkeletonControl, will produce a body sutiable
566 for AI control with movement and proprioception."
567 [node]
568 (let [skeleton-control (.getControl node SkeletonControl)
569 krc (KinematicRagdollControl.)]
570 (comment
571 (dorun
572 (map #(.addBoneName krc %)
573 ["mid2" "tail" "head" "mid1" "mid3" "mid4" "Dummy-Root" ""]
574 ;;"mid2" "mid3" "tail" "head"]
575 )))
576 (.addControl node krc)
577 (.setRagdollMode krc)
578 )
579 node
580 )
581 (defn show-skeleton [node]
582 (let [sd
584 (doto
585 (SkeletonDebugger. "aurellem-skel-debug"
586 (skel node))
587 (.setMaterial (green-x-ray)))]
588 (.attachChild node sd)
589 node))
593 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
595 ;; this could be a good way to give objects special properties like
596 ;; being eyes and the like
598 (.getUserData
599 (.getChild
600 (load-blender-model "Models/property/test.blend") 0)
601 "properties")
603 ;; the properties are saved along with the blender file.
604 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
609 (defn init-debug-skel-node
610 [f debug-node skeleton]
611 (let [bones
612 (map #(.getBone skeleton %)
613 (range (.getBoneCount skeleton)))]
614 (dorun (map #(.setUserControl % true) bones))
615 (dorun (map (fn [b]
616 (println (.getName b)
617 " -- " (f b)))
618 bones))
619 (dorun
620 (map #(.attachChild
621 debug-node
622 (doto
623 (sphere 0.1
624 :position (f %)
625 :physical? false)
626 (.setMaterial (green-x-ray))))
627 bones)))
628 debug-node)
630 (import jme3test.bullet.PhysicsTestHelper)
633 (defn test-zzz [the-worm world value]
634 (if (not value)
635 (let [skeleton (skel the-worm)]
636 (println-repl "enabling bones")
637 (dorun
638 (map
639 #(.setUserControl (.getBone skeleton %) true)
640 (range (.getBoneCount skeleton))))
643 (let [b (.getBone skeleton 2)]
644 (println-repl "moving " (.getName b))
645 (println-repl (.getLocalPosition b))
646 (.setUserTransforms b
647 Vector3f/UNIT_X
648 Quaternion/IDENTITY
649 ;;(doto (Quaternion.)
650 ;; (.fromAngles (/ Math/PI 2)
651 ;; 0
652 ;; 0
654 (Vector3f. 1 1 1))
655 )
657 (println-repl "hi! <3"))))
660 (defn test-ragdoll []
662 (let [the-worm
664 ;;(.loadModel (asset-manager) "Models/anim2/Cube.mesh.xml")
665 (doto (show-skeleton (worm-blender))
666 (.setLocalTranslation (Vector3f. 0 10 0))
667 ;;(worm)
668 ;;(oto)
669 ;;(sinbad)
670 )
671 ]
674 (.start
675 (world
676 (doto (Node.)
677 (.attachChild the-worm))
678 {"key-return" (fire-cannon-ball)
679 "key-space" (partial test-zzz the-worm)
680 }
681 (fn [world]
682 (light-up-everything world)
683 (PhysicsTestHelper/createPhysicsTestWorld
684 (.getRootNode world)
685 (asset-manager)
686 (.getPhysicsSpace
687 (.getState (.getStateManager world) BulletAppState)))
688 (set-gravity world Vector3f/ZERO)
689 ;;(.setTimer world (NanoTimer.))
690 ;;(org.lwjgl.input.Mouse/setGrabbed false)
691 )
692 no-op
693 )
696 )))
699 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
700 ;;; here is the ragdoll stuff
702 (def worm-mesh (.getMesh (.getChild (worm-blender) 0)))
703 (def mesh worm-mesh)
705 (.getFloatBuffer mesh VertexBuffer$Type/Position)
706 (.getFloatBuffer mesh VertexBuffer$Type/BoneWeight)
707 (.getData (.getBuffer mesh VertexBuffer$Type/BoneIndex))
710 (defn position [index]
711 (.get
712 (.getFloatBuffer worm-mesh VertexBuffer$Type/Position)
713 index))
715 (defn bones [index]
716 (.get
717 (.getData (.getBuffer mesh VertexBuffer$Type/BoneIndex))
718 index))
720 (defn bone-weights [index]
721 (.get
722 (.getFloatBuffer mesh VertexBuffer$Type/BoneWeight)
723 index))
727 (defn vertex-bones [vertex]
728 (vec (map (comp int bones) (range (* vertex 4) (+ (* vertex 4) 4)))))
730 (defn vertex-weights [vertex]
731 (vec (map (comp float bone-weights) (range (* vertex 4) (+ (* vertex 4) 4)))))
733 (defn vertex-position [index]
734 (let [offset (* index 3)]
735 (Vector3f. (position offset)
736 (position (inc offset))
737 (position (inc(inc offset))))))
739 (def vertex-info (juxt vertex-position vertex-bones vertex-weights))
741 (defn bone-control-color [index]
742 (get {[1 0 0 0] ColorRGBA/Red
743 [1 2 0 0] ColorRGBA/Magenta
744 [2 0 0 0] ColorRGBA/Blue}
745 (vertex-bones index)
746 ColorRGBA/White))
748 (defn influence-color [index bone-num]
749 (get
750 {(float 0) ColorRGBA/Blue
751 (float 0.5) ColorRGBA/Green
752 (float 1) ColorRGBA/Red}
753 ;; find the weight of the desired bone
754 ((zipmap (vertex-bones index)(vertex-weights index))
755 bone-num)
756 ColorRGBA/Blue))
758 (def worm-vertices (set (map vertex-info (range 60))))
761 (defn test-info []
762 (let [points (Node.)]
763 (dorun
764 (map #(.attachChild points %)
765 (map #(sphere 0.01
766 :position (vertex-position %)
767 :color (influence-color % 1)
768 :physical? false)
769 (range 60))))
770 (view points)))
773 (defrecord JointControl [joint physics-space]
774 PhysicsControl
775 (setPhysicsSpace [this space]
776 (dosync
777 (ref-set (:physics-space this) space))
778 (.addJoint space (:joint this)))
779 (update [this tpf])
780 (setSpatial [this spatial])
781 (render [this rm vp])
782 (getPhysicsSpace [this] (deref (:physics-space this)))
783 (isEnabled [this] true)
784 (setEnabled [this state]))
786 (defn add-joint
787 "Add a joint to a particular object. When the object is added to the
788 PhysicsSpace of a simulation, the joint will also be added"
789 [object joint]
790 (let [control (JointControl. joint (ref nil))]
791 (.addControl object control))
792 object)
795 (defn hinge-world
796 []
797 (let [sphere1 (sphere)
798 sphere2 (sphere 1 :position (Vector3f. 3 3 3))
799 joint (Point2PointJoint.
800 (.getControl sphere1 RigidBodyControl)
801 (.getControl sphere2 RigidBodyControl)
802 Vector3f/ZERO (Vector3f. 3 3 3))]
803 (add-joint sphere1 joint)
804 (doto (Node. "hinge-world")
805 (.attachChild sphere1)
806 (.attachChild sphere2))))
809 (defn test-joint []
810 (view (hinge-world)))
812 ;; (defn copier-gen []
813 ;; (let [count (atom 0)]
814 ;; (fn [in]
815 ;; (swap! count inc)
816 ;; (clojure.contrib.duck-streams/copy
817 ;; in (File. (str "/home/r/tmp/mao-test/clojure-images/"
818 ;; ;;/home/r/tmp/mao-test/clojure-images
819 ;; (format "%08d.png" @count)))))))
820 ;; (defn decrease-framerate []
821 ;; (map
822 ;; (copier-gen)
823 ;; (sort
824 ;; (map first
825 ;; (partition
826 ;; 4
827 ;; (filter #(re-matches #".*.png$" (.getCanonicalPath %))
828 ;; (file-seq
829 ;; (file-str
830 ;; "/home/r/media/anime/mao-temp/images"))))))))
834 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
836 (defn proprioception
837 "Create a proprioception map that reports the rotations of the
838 various limbs of the creature's body"
839 [creature]
840 [#^Node creature]
841 (let [
842 nodes (node-seq creature)
843 joints
844 (map
845 :joint
846 (filter
847 #(isa? (class %) JointControl)
848 (reduce
849 concat
850 (map (fn [node]
851 (map (fn [num] (.getControl node num))
852 (range (.getNumControls node))))
853 nodes))))]
854 (fn []
855 (reduce concat (map relative-positions (list (first joints)))))))
858 (defn skel [node]
859 (doto
860 (.getSkeleton
861 (.getControl node SkeletonControl))
862 ;; this is necessary to force the skeleton to have accurate world
863 ;; transforms before it is rendered to the screen.
864 (.resetAndUpdate)))
866 (defn green-x-ray []
867 (doto (Material. (asset-manager)
868 "Common/MatDefs/Misc/Unshaded.j3md")
869 (.setColor "Color" ColorRGBA/Green)
870 (-> (.getAdditionalRenderState)
871 (.setDepthTest false))))
873 (defn test-worm []
874 (.start
875 (world
876 (doto (Node.)
877 ;;(.attachChild (point-worm))
878 (.attachChild (load-blender-model
879 "Models/anim2/joint-worm.blend"))
881 (.attachChild (box 10 1 10
882 :position (Vector3f. 0 -2 0) :mass 0
883 :color (ColorRGBA/Gray))))
884 {
885 "key-space" (fire-cannon-ball)
886 }
887 (fn [world]
888 (enable-debug world)
889 (light-up-everything world)
890 ;;(.setTimer world (NanoTimer.))
891 )
892 no-op)))
896 ;; defunct movement stuff
897 (defn torque-controls [control]
898 (let [torques
899 (concat
900 (map #(Vector3f. 0 (Math/sin %) (Math/cos %))
901 (range 0 (* Math/PI 2) (/ (* Math/PI 2) 20)))
902 [Vector3f/UNIT_X])]
903 (map (fn [torque-axis]
904 (fn [torque]
905 (.applyTorque
906 control
907 (.mult (.mult (.getPhysicsRotation control)
908 torque-axis)
909 (float
910 (* (.getMass control) torque))))))
911 torques)))
913 (defn motor-map
914 "Take a creature and generate a function that will enable fine
915 grained control over all the creature's limbs."
916 [#^Node creature]
917 (let [controls (keep #(.getControl % RigidBodyControl)
918 (node-seq creature))
919 limb-controls (reduce concat (map torque-controls controls))
920 body-control (partial map #(%1 %2) limb-controls)]
921 body-control))
923 (defn test-motor-map
924 "see how torque works."
925 []
926 (let [finger (box 3 0.5 0.5 :position (Vector3f. 0 2 0)
927 :mass 1 :color ColorRGBA/Green)
928 motor-map (motor-map finger)]
929 (world
930 (nodify [finger
931 (box 10 0.5 10 :position (Vector3f. 0 -5 0) :mass 0
932 :color ColorRGBA/Gray)])
933 standard-debug-controls
934 (fn [world]
935 (set-gravity world Vector3f/ZERO)
936 (light-up-everything world)
937 (.setTimer world (NanoTimer.)))
938 (fn [_ _]
939 (dorun (motor-map [0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0]))))))
940 #+end_src
948 * COMMENT generate Source
949 #+begin_src clojure :tangle ../src/cortex/body.clj
950 <<proprioception>>
951 <<motor-control>>
952 #+end_src
954 #+begin_src clojure :tangle ../src/cortex/test/body.clj
955 <<test-body>>
956 #+end_src