view org/body.org @ 175:0b9ae09eaec3

renamed functions in body
author Robert McIntyre <rlm@mit.edu>
date Sat, 04 Feb 2012 06:47:07 -0700
parents 33278bf028e7
children 026f69582022
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 * Making a solid, connected body.
9 #+name: joints
10 #+begin_src clojure
11 (ns cortex.body
12 (:use (cortex world util sense))
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
19 com.jme3.collision.CollisionResults
20 com.jme3.bounding.BoundingBox
21 com.jme3.scene.Node))
23 (use 'clojure.contrib.def)
24 (cortex.import/mega-import-jme3)
26 (defn joint-targets
27 "Return the two closest two objects to the joint object, ordered
28 from bottom to top according to the joint's rotation."
29 [#^Node parts #^Node joint]
30 (loop [radius (float 0.01)]
31 (let [results (CollisionResults.)]
32 (.collideWith
33 parts
34 (BoundingBox. (.getWorldTranslation joint)
35 radius radius radius)
36 results)
37 (let [targets
38 (distinct
39 (map #(.getGeometry %) results))]
40 (if (>= (count targets) 2)
41 (sort-by
42 #(let [v
43 (jme-to-blender
44 (.mult
45 (.inverse (.getWorldRotation joint))
46 (.subtract (.getWorldTranslation %)
47 (.getWorldTranslation joint))))]
48 (println-repl (.getName %) ":" v)
49 (.dot (Vector3f. 1 1 1)
50 v))
51 (take 2 targets))
52 (recur (float (* radius 2))))))))
54 (defmulti joint-dispatch
55 "Translate blender pseudo-joints into real JME joints."
56 (fn [constraints & _]
57 (:type constraints)))
59 (defmethod joint-dispatch :point
60 [constraints control-a control-b pivot-a pivot-b rotation]
61 (println-repl "creating POINT2POINT joint")
62 ;; bullet's point2point joints are BROKEN, so we must use the
63 ;; generic 6DOF joint instead of an actual Point2Point joint!
65 ;; should be able to do this:
66 (comment
67 (Point2PointJoint.
68 control-a
69 control-b
70 pivot-a
71 pivot-b))
73 ;; but instead we must do this:
74 (println-repl "substuting 6DOF joint for POINT2POINT joint!")
75 (doto
76 (SixDofJoint.
77 control-a
78 control-b
79 pivot-a
80 pivot-b
81 false)
82 (.setLinearLowerLimit Vector3f/ZERO)
83 (.setLinearUpperLimit Vector3f/ZERO)
84 ;;(.setAngularLowerLimit (Vector3f. 1 1 1))
85 ;;(.setAngularUpperLimit (Vector3f. 0 0 0))
87 ))
90 (defmethod joint-dispatch :hinge
91 [constraints control-a control-b pivot-a pivot-b rotation]
92 (println-repl "creating HINGE joint")
93 (let [axis
94 (if-let
95 [axis (:axis constraints)]
96 axis
97 Vector3f/UNIT_X)
98 [limit-1 limit-2] (:limit constraints)
99 hinge-axis
100 (.mult
101 rotation
102 (blender-to-jme axis))]
103 (doto
104 (HingeJoint.
105 control-a
106 control-b
107 pivot-a
108 pivot-b
109 hinge-axis
110 hinge-axis)
111 (.setLimit limit-1 limit-2))))
113 (defmethod joint-dispatch :cone
114 [constraints control-a control-b pivot-a pivot-b rotation]
115 (let [limit-xz (:limit-xz constraints)
116 limit-xy (:limit-xy constraints)
117 twist (:twist constraints)]
119 (println-repl "creating CONE joint")
120 (println-repl rotation)
121 (println-repl
122 "UNIT_X --> " (.mult rotation (Vector3f. 1 0 0)))
123 (println-repl
124 "UNIT_Y --> " (.mult rotation (Vector3f. 0 1 0)))
125 (println-repl
126 "UNIT_Z --> " (.mult rotation (Vector3f. 0 0 1)))
127 (doto
128 (ConeJoint.
129 control-a
130 control-b
131 pivot-a
132 pivot-b
133 rotation
134 rotation)
135 (.setLimit (float limit-xz)
136 (float limit-xy)
137 (float twist)))))
139 (defn connect
140 "Create a joint between 'obj-a and 'obj-b at the location of
141 'joint. The type of joint is determined by the metadata on 'joint.
143 Here are some examples:
144 {:type :point}
145 {:type :hinge :limit [0 (/ Math/PI 2)] :axis (Vector3f. 0 1 0)}
146 (:axis defaults to (Vector3f. 1 0 0) if not provided for hinge joints)
148 {:type :cone :limit-xz 0]
149 :limit-xy 0]
150 :twist 0]} (use XZY rotation mode in blender!)"
151 [#^Node obj-a #^Node obj-b #^Node joint]
152 (let [control-a (.getControl obj-a RigidBodyControl)
153 control-b (.getControl obj-b RigidBodyControl)
154 joint-center (.getWorldTranslation joint)
155 joint-rotation (.toRotationMatrix (.getWorldRotation joint))
156 pivot-a (world-to-local obj-a joint-center)
157 pivot-b (world-to-local obj-b joint-center)]
159 (if-let [constraints
160 (map-vals
161 eval
162 (read-string
163 (meta-data joint "joint")))]
164 ;; A side-effect of creating a joint registers
165 ;; it with both physics objects which in turn
166 ;; will register the joint with the physics system
167 ;; when the simulation is started.
168 (do
169 (println-repl "creating joint between"
170 (.getName obj-a) "and" (.getName obj-b))
171 (joint-dispatch constraints
172 control-a control-b
173 pivot-a pivot-b
174 joint-rotation))
175 (println-repl "could not find joint meta-data!"))))
177 (defvar
178 ^{:arglists '([creature])}
179 joints
180 (sense-nodes "joints")
181 "Return the children of the creature's \"joints\" node.")
183 (defn physical!
184 "Iterate through the nodes in creature and make them real physical
185 objects in the simulation."
186 [#^Node creature]
187 (dorun
188 (map
189 (fn [geom]
190 (let [physics-control
191 (RigidBodyControl.
192 (HullCollisionShape.
193 (.getMesh geom))
194 (if-let [mass (meta-data geom "mass")]
195 (do
196 (println-repl
197 "setting" (.getName geom) "mass to" (float mass))
198 (float mass))
199 (float 1)))]
201 (.addControl geom physics-control)))
202 (filter #(isa? (class %) Geometry )
203 (node-seq creature)))))
205 (defn joints!
206 "Connect the solid parts of the creature with physical joints. The
207 joints are taken from the \"joints\" node in the creature."
208 [#^Node creature]
209 (dorun
210 (map
211 (fn [joint]
212 (let [[obj-a obj-b] (joint-targets creature joint)]
213 (connect obj-a obj-b joint)))
214 (joints creature))))
216 (defn body!
217 "Endow the creature with a physical body connected with joints. The
218 particulars of the joints and the masses of each pody part are
219 determined in blender."
220 [#^Node creature]
221 (physical! creature)
222 (joints! creature))
227 #+end_src
229 #+results: joints
230 : #'cortex.body/body!
232 #+results: proprioception
233 : #'cortex.body/proprioception-debug-window
235 * Examples
237 #+name: test-body
238 #+begin_src clojure
239 (ns cortex.test.body
240 (:use (cortex world util body))
241 (:require cortex.silly)
242 (:import
243 com.jme3.math.Vector3f
244 com.jme3.math.ColorRGBA
245 com.jme3.bullet.joints.Point2PointJoint
246 com.jme3.bullet.control.RigidBodyControl
247 com.jme3.system.NanoTimer
248 com.jme3.math.Quaternion))
250 (defn worm-segments
251 "Create multiple evenly spaced box segments. They're fabulous!"
252 [segment-length num-segments interstitial-space radius]
253 (letfn [(nth-segment
254 [n]
255 (box segment-length radius radius :mass 0.1
256 :position
257 (Vector3f.
258 (* 2 n (+ interstitial-space segment-length)) 0 0)
259 :name (str "worm-segment" n)
260 :color (ColorRGBA/randomColor)))]
261 (map nth-segment (range num-segments))))
263 (defn connect-at-midpoint
264 "Connect two physics objects with a Point2Point joint constraint at
265 the point equidistant from both objects' centers."
266 [segmentA segmentB]
267 (let [centerA (.getWorldTranslation segmentA)
268 centerB (.getWorldTranslation segmentB)
269 midpoint (.mult (.add centerA centerB) (float 0.5))
270 pivotA (.subtract midpoint centerA)
271 pivotB (.subtract midpoint centerB)
273 ;; A side-effect of creating a joint registers
274 ;; it with both physics objects which in turn
275 ;; will register the joint with the physics system
276 ;; when the simulation is started.
277 joint (Point2PointJoint.
278 (.getControl segmentA RigidBodyControl)
279 (.getControl segmentB RigidBodyControl)
280 pivotA
281 pivotB)]
282 segmentB))
284 (defn eve-worm
285 "Create a worm-like body bound by invisible joint constraints."
286 []
287 (let [segments (worm-segments 0.2 5 0.1 0.1)]
288 (dorun (map (partial apply connect-at-midpoint)
289 (partition 2 1 segments)))
290 (nodify "worm" segments)))
292 (defn worm-pattern
293 "This is a simple, mindless motor control pattern that drives the
294 second segment of the worm's body at an offset angle with
295 sinusoidally varying strength."
296 [time]
297 (let [angle (* Math/PI (/ 9 20))
298 direction (Vector3f. 0 (Math/sin angle) (Math/cos angle))]
299 [Vector3f/ZERO
300 (.mult
301 direction
302 (float (* 2 (Math/sin (* Math/PI 2 (/ (rem time 300 ) 300))))))
303 Vector3f/ZERO
304 Vector3f/ZERO
305 Vector3f/ZERO]))
307 (defn test-motor-control
308 "Testing motor-control:
309 You should see a multi-segmented worm-like object fall onto the
310 table and begin writhing and moving."
311 []
312 (let [worm (eve-worm)
313 time (atom 0)
314 worm-motor-map (vector-motor-control worm)]
315 (world
316 (nodify [worm
317 (box 10 0.5 10 :position (Vector3f. 0 -5 0) :mass 0
318 :color ColorRGBA/Gray)])
319 standard-debug-controls
320 (fn [world]
321 (enable-debug world)
322 (light-up-everything world)
323 (comment
324 (com.aurellem.capture.Capture/captureVideo
325 world
326 (file-str "/home/r/proj/cortex/tmp/moving-worm")))
327 )
329 (fn [_ _]
330 (swap! time inc)
331 (Thread/sleep 20)
332 (dorun (worm-motor-map
333 (worm-pattern @time)))))))
337 (defn join-at-point [obj-a obj-b world-pivot]
338 (cortex.silly/joint-dispatch
339 {:type :point}
340 (.getControl obj-a RigidBodyControl)
341 (.getControl obj-b RigidBodyControl)
342 (cortex.silly/world-to-local obj-a world-pivot)
343 (cortex.silly/world-to-local obj-b world-pivot)
344 nil
345 ))
347 (import com.jme3.bullet.collision.PhysicsCollisionObject)
349 (defn blab-* []
350 (let [hand (box 0.5 0.2 0.2 :position (Vector3f. 0 0 0)
351 :mass 0 :color ColorRGBA/Green)
352 finger (box 0.5 0.2 0.2 :position (Vector3f. 2.4 0 0)
353 :mass 1 :color ColorRGBA/Red)
354 connection-point (Vector3f. 1.2 0 0)
355 root (nodify [hand finger])]
357 (join-at-point hand finger (Vector3f. 1.2 0 0))
359 (.setCollisionGroup
360 (.getControl hand RigidBodyControl)
361 PhysicsCollisionObject/COLLISION_GROUP_NONE)
362 (world
363 root
364 standard-debug-controls
365 (fn [world]
366 (enable-debug world)
367 (.setTimer world (com.aurellem.capture.RatchetTimer. 60))
368 (set-gravity world Vector3f/ZERO)
369 )
370 no-op)))
371 (comment
373 (defn proprioception-debug-window
374 []
375 (let [time (atom 0)]
376 (fn [prop-data]
377 (if (= 0 (rem (swap! time inc) 40))
378 (println-repl prop-data)))))
379 )
381 (comment
382 (dorun
383 (map
384 (comp
385 println-repl
386 (fn [[p y r]]
387 (format
388 "pitch: %1.2f\nyaw: %1.2f\nroll: %1.2f\n"
389 p y r)))
390 prop-data)))
395 (defn test-proprioception
396 "Testing proprioception:
397 You should see two foating bars, and a printout of pitch, yaw, and
398 roll. Pressing key-r/key-t should move the blue bar up and down and
399 change only the value of pitch. key-f/key-g moves it side to side
400 and changes yaw. key-v/key-b will spin the blue segment clockwise
401 and counterclockwise, and only affect roll."
402 []
403 (let [hand (box 0.2 1 0.2 :position (Vector3f. 0 0 0)
404 :mass 0 :color ColorRGBA/Green :name "hand")
405 finger (box 0.2 1 0.2 :position (Vector3f. 0 2.4 0)
406 :mass 1 :color ColorRGBA/Red :name "finger")
407 joint-node (box 0.1 0.05 0.05 :color ColorRGBA/Yellow
408 :position (Vector3f. 0 1.2 0)
409 :rotation (doto (Quaternion.)
410 (.fromAngleAxis
411 (/ Math/PI 2)
412 (Vector3f. 0 0 1)))
413 :physical? false)
414 joint (join-at-point hand finger (Vector3f. 0 1.2 0 ))
415 creature (nodify [hand finger joint-node])
416 finger-control (.getControl finger RigidBodyControl)
417 hand-control (.getControl hand RigidBodyControl)]
420 (let
421 ;; *******************************************
423 [floor (box 10 10 10 :position (Vector3f. 0 -15 0)
424 :mass 0 :color ColorRGBA/Gray)
426 root (nodify [creature floor])
427 prop (joint-proprioception creature joint-node)
428 prop-view (proprioception-debug-window)
430 controls
431 (merge standard-debug-controls
432 {"key-o"
433 (fn [_ _] (.setEnabled finger-control true))
434 "key-p"
435 (fn [_ _] (.setEnabled finger-control false))
436 "key-k"
437 (fn [_ _] (.setEnabled hand-control true))
438 "key-l"
439 (fn [_ _] (.setEnabled hand-control false))
440 "key-i"
441 (fn [world _] (set-gravity world (Vector3f. 0 0 0)))
442 "key-period"
443 (fn [world _]
444 (.setEnabled finger-control false)
445 (.setEnabled hand-control false)
446 (.rotate creature (doto (Quaternion.)
447 (.fromAngleAxis
448 (float (/ Math/PI 15))
449 (Vector3f. 0 0 -1))))
451 (.setEnabled finger-control true)
452 (.setEnabled hand-control true)
453 (set-gravity world (Vector3f. 0 0 0))
454 )
457 }
458 )
460 ]
461 (comment
462 (.setCollisionGroup
463 (.getControl hand RigidBodyControl)
464 PhysicsCollisionObject/COLLISION_GROUP_NONE)
465 )
466 (apply
467 world
468 (with-movement
469 hand
470 ["key-y" "key-u" "key-h" "key-j" "key-n" "key-m"]
471 [10 10 10 10 1 1]
472 (with-movement
473 finger
474 ["key-r" "key-t" "key-f" "key-g" "key-v" "key-b"]
475 [1 1 10 10 10 10]
476 [root
477 controls
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 [_ _] (prop-view (list (prop))))]))))))
484 #+end_src
486 #+results: test-body
487 : #'cortex.test.body/test-proprioception
490 * COMMENT code-limbo
491 #+begin_src clojure
492 ;;(.loadModel
493 ;; (doto (asset-manager)
494 ;; (.registerLoader BlenderModelLoader (into-array String ["blend"])))
495 ;; "Models/person/person.blend")
498 (defn load-blender-model
499 "Load a .blend file using an asset folder relative path."
500 [^String model]
501 (.loadModel
502 (doto (asset-manager)
503 (.registerLoader BlenderModelLoader (into-array String ["blend"])))
504 model))
507 (defn view-model [^String model]
508 (view
509 (.loadModel
510 (doto (asset-manager)
511 (.registerLoader BlenderModelLoader (into-array String ["blend"])))
512 model)))
514 (defn load-blender-scene [^String model]
515 (.loadModel
516 (doto (asset-manager)
517 (.registerLoader BlenderLoader (into-array String ["blend"])))
518 model))
520 (defn worm
521 []
522 (.loadModel (asset-manager) "Models/anim2/Cube.mesh.xml"))
524 (defn oto
525 []
526 (.loadModel (asset-manager) "Models/Oto/Oto.mesh.xml"))
528 (defn sinbad
529 []
530 (.loadModel (asset-manager) "Models/Sinbad/Sinbad.mesh.xml"))
532 (defn worm-blender
533 []
534 (first (seq (.getChildren (load-blender-model
535 "Models/anim2/simple-worm.blend")))))
537 (defn body
538 "given a node with a SkeletonControl, will produce a body sutiable
539 for AI control with movement and proprioception."
540 [node]
541 (let [skeleton-control (.getControl node SkeletonControl)
542 krc (KinematicRagdollControl.)]
543 (comment
544 (dorun
545 (map #(.addBoneName krc %)
546 ["mid2" "tail" "head" "mid1" "mid3" "mid4" "Dummy-Root" ""]
547 ;;"mid2" "mid3" "tail" "head"]
548 )))
549 (.addControl node krc)
550 (.setRagdollMode krc)
551 )
552 node
553 )
554 (defn show-skeleton [node]
555 (let [sd
557 (doto
558 (SkeletonDebugger. "aurellem-skel-debug"
559 (skel node))
560 (.setMaterial (green-x-ray)))]
561 (.attachChild node sd)
562 node))
566 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
568 ;; this could be a good way to give objects special properties like
569 ;; being eyes and the like
571 (.getUserData
572 (.getChild
573 (load-blender-model "Models/property/test.blend") 0)
574 "properties")
576 ;; the properties are saved along with the blender file.
577 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
582 (defn init-debug-skel-node
583 [f debug-node skeleton]
584 (let [bones
585 (map #(.getBone skeleton %)
586 (range (.getBoneCount skeleton)))]
587 (dorun (map #(.setUserControl % true) bones))
588 (dorun (map (fn [b]
589 (println (.getName b)
590 " -- " (f b)))
591 bones))
592 (dorun
593 (map #(.attachChild
594 debug-node
595 (doto
596 (sphere 0.1
597 :position (f %)
598 :physical? false)
599 (.setMaterial (green-x-ray))))
600 bones)))
601 debug-node)
603 (import jme3test.bullet.PhysicsTestHelper)
606 (defn test-zzz [the-worm world value]
607 (if (not value)
608 (let [skeleton (skel the-worm)]
609 (println-repl "enabling bones")
610 (dorun
611 (map
612 #(.setUserControl (.getBone skeleton %) true)
613 (range (.getBoneCount skeleton))))
616 (let [b (.getBone skeleton 2)]
617 (println-repl "moving " (.getName b))
618 (println-repl (.getLocalPosition b))
619 (.setUserTransforms b
620 Vector3f/UNIT_X
621 Quaternion/IDENTITY
622 ;;(doto (Quaternion.)
623 ;; (.fromAngles (/ Math/PI 2)
624 ;; 0
625 ;; 0
627 (Vector3f. 1 1 1))
628 )
630 (println-repl "hi! <3"))))
633 (defn test-ragdoll []
635 (let [the-worm
637 ;;(.loadModel (asset-manager) "Models/anim2/Cube.mesh.xml")
638 (doto (show-skeleton (worm-blender))
639 (.setLocalTranslation (Vector3f. 0 10 0))
640 ;;(worm)
641 ;;(oto)
642 ;;(sinbad)
643 )
644 ]
647 (.start
648 (world
649 (doto (Node.)
650 (.attachChild the-worm))
651 {"key-return" (fire-cannon-ball)
652 "key-space" (partial test-zzz the-worm)
653 }
654 (fn [world]
655 (light-up-everything world)
656 (PhysicsTestHelper/createPhysicsTestWorld
657 (.getRootNode world)
658 (asset-manager)
659 (.getPhysicsSpace
660 (.getState (.getStateManager world) BulletAppState)))
661 (set-gravity world Vector3f/ZERO)
662 ;;(.setTimer world (NanoTimer.))
663 ;;(org.lwjgl.input.Mouse/setGrabbed false)
664 )
665 no-op
666 )
669 )))
672 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
673 ;;; here is the ragdoll stuff
675 (def worm-mesh (.getMesh (.getChild (worm-blender) 0)))
676 (def mesh worm-mesh)
678 (.getFloatBuffer mesh VertexBuffer$Type/Position)
679 (.getFloatBuffer mesh VertexBuffer$Type/BoneWeight)
680 (.getData (.getBuffer mesh VertexBuffer$Type/BoneIndex))
683 (defn position [index]
684 (.get
685 (.getFloatBuffer worm-mesh VertexBuffer$Type/Position)
686 index))
688 (defn bones [index]
689 (.get
690 (.getData (.getBuffer mesh VertexBuffer$Type/BoneIndex))
691 index))
693 (defn bone-weights [index]
694 (.get
695 (.getFloatBuffer mesh VertexBuffer$Type/BoneWeight)
696 index))
700 (defn vertex-bones [vertex]
701 (vec (map (comp int bones) (range (* vertex 4) (+ (* vertex 4) 4)))))
703 (defn vertex-weights [vertex]
704 (vec (map (comp float bone-weights) (range (* vertex 4) (+ (* vertex 4) 4)))))
706 (defn vertex-position [index]
707 (let [offset (* index 3)]
708 (Vector3f. (position offset)
709 (position (inc offset))
710 (position (inc(inc offset))))))
712 (def vertex-info (juxt vertex-position vertex-bones vertex-weights))
714 (defn bone-control-color [index]
715 (get {[1 0 0 0] ColorRGBA/Red
716 [1 2 0 0] ColorRGBA/Magenta
717 [2 0 0 0] ColorRGBA/Blue}
718 (vertex-bones index)
719 ColorRGBA/White))
721 (defn influence-color [index bone-num]
722 (get
723 {(float 0) ColorRGBA/Blue
724 (float 0.5) ColorRGBA/Green
725 (float 1) ColorRGBA/Red}
726 ;; find the weight of the desired bone
727 ((zipmap (vertex-bones index)(vertex-weights index))
728 bone-num)
729 ColorRGBA/Blue))
731 (def worm-vertices (set (map vertex-info (range 60))))
734 (defn test-info []
735 (let [points (Node.)]
736 (dorun
737 (map #(.attachChild points %)
738 (map #(sphere 0.01
739 :position (vertex-position %)
740 :color (influence-color % 1)
741 :physical? false)
742 (range 60))))
743 (view points)))
746 (defrecord JointControl [joint physics-space]
747 PhysicsControl
748 (setPhysicsSpace [this space]
749 (dosync
750 (ref-set (:physics-space this) space))
751 (.addJoint space (:joint this)))
752 (update [this tpf])
753 (setSpatial [this spatial])
754 (render [this rm vp])
755 (getPhysicsSpace [this] (deref (:physics-space this)))
756 (isEnabled [this] true)
757 (setEnabled [this state]))
759 (defn add-joint
760 "Add a joint to a particular object. When the object is added to the
761 PhysicsSpace of a simulation, the joint will also be added"
762 [object joint]
763 (let [control (JointControl. joint (ref nil))]
764 (.addControl object control))
765 object)
768 (defn hinge-world
769 []
770 (let [sphere1 (sphere)
771 sphere2 (sphere 1 :position (Vector3f. 3 3 3))
772 joint (Point2PointJoint.
773 (.getControl sphere1 RigidBodyControl)
774 (.getControl sphere2 RigidBodyControl)
775 Vector3f/ZERO (Vector3f. 3 3 3))]
776 (add-joint sphere1 joint)
777 (doto (Node. "hinge-world")
778 (.attachChild sphere1)
779 (.attachChild sphere2))))
782 (defn test-joint []
783 (view (hinge-world)))
785 ;; (defn copier-gen []
786 ;; (let [count (atom 0)]
787 ;; (fn [in]
788 ;; (swap! count inc)
789 ;; (clojure.contrib.duck-streams/copy
790 ;; in (File. (str "/home/r/tmp/mao-test/clojure-images/"
791 ;; ;;/home/r/tmp/mao-test/clojure-images
792 ;; (format "%08d.png" @count)))))))
793 ;; (defn decrease-framerate []
794 ;; (map
795 ;; (copier-gen)
796 ;; (sort
797 ;; (map first
798 ;; (partition
799 ;; 4
800 ;; (filter #(re-matches #".*.png$" (.getCanonicalPath %))
801 ;; (file-seq
802 ;; (file-str
803 ;; "/home/r/media/anime/mao-temp/images"))))))))
807 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
809 (defn proprioception
810 "Create a proprioception map that reports the rotations of the
811 various limbs of the creature's body"
812 [creature]
813 [#^Node creature]
814 (let [
815 nodes (node-seq creature)
816 joints
817 (map
818 :joint
819 (filter
820 #(isa? (class %) JointControl)
821 (reduce
822 concat
823 (map (fn [node]
824 (map (fn [num] (.getControl node num))
825 (range (.getNumControls node))))
826 nodes))))]
827 (fn []
828 (reduce concat (map relative-positions (list (first joints)))))))
831 (defn skel [node]
832 (doto
833 (.getSkeleton
834 (.getControl node SkeletonControl))
835 ;; this is necessary to force the skeleton to have accurate world
836 ;; transforms before it is rendered to the screen.
837 (.resetAndUpdate)))
839 (defn green-x-ray []
840 (doto (Material. (asset-manager)
841 "Common/MatDefs/Misc/Unshaded.j3md")
842 (.setColor "Color" ColorRGBA/Green)
843 (-> (.getAdditionalRenderState)
844 (.setDepthTest false))))
846 (defn test-worm []
847 (.start
848 (world
849 (doto (Node.)
850 ;;(.attachChild (point-worm))
851 (.attachChild (load-blender-model
852 "Models/anim2/joint-worm.blend"))
854 (.attachChild (box 10 1 10
855 :position (Vector3f. 0 -2 0) :mass 0
856 :color (ColorRGBA/Gray))))
857 {
858 "key-space" (fire-cannon-ball)
859 }
860 (fn [world]
861 (enable-debug world)
862 (light-up-everything world)
863 ;;(.setTimer world (NanoTimer.))
864 )
865 no-op)))
869 ;; defunct movement stuff
870 (defn torque-controls [control]
871 (let [torques
872 (concat
873 (map #(Vector3f. 0 (Math/sin %) (Math/cos %))
874 (range 0 (* Math/PI 2) (/ (* Math/PI 2) 20)))
875 [Vector3f/UNIT_X])]
876 (map (fn [torque-axis]
877 (fn [torque]
878 (.applyTorque
879 control
880 (.mult (.mult (.getPhysicsRotation control)
881 torque-axis)
882 (float
883 (* (.getMass control) torque))))))
884 torques)))
886 (defn motor-map
887 "Take a creature and generate a function that will enable fine
888 grained control over all the creature's limbs."
889 [#^Node creature]
890 (let [controls (keep #(.getControl % RigidBodyControl)
891 (node-seq creature))
892 limb-controls (reduce concat (map torque-controls controls))
893 body-control (partial map #(%1 %2) limb-controls)]
894 body-control))
896 (defn test-motor-map
897 "see how torque works."
898 []
899 (let [finger (box 3 0.5 0.5 :position (Vector3f. 0 2 0)
900 :mass 1 :color ColorRGBA/Green)
901 motor-map (motor-map finger)]
902 (world
903 (nodify [finger
904 (box 10 0.5 10 :position (Vector3f. 0 -5 0) :mass 0
905 :color ColorRGBA/Gray)])
906 standard-debug-controls
907 (fn [world]
908 (set-gravity world Vector3f/ZERO)
909 (light-up-everything world)
910 (.setTimer world (NanoTimer.)))
911 (fn [_ _]
912 (dorun (motor-map [0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
913 0]))))))
915 (defn joint-proprioception [#^Node parts #^Node joint]
916 (let [[obj-a obj-b] (joint-targets parts joint)
917 joint-rot (.getWorldRotation joint)
918 pre-inv-a (.inverse (.getWorldRotation obj-a))
919 x (.mult pre-inv-a (.mult joint-rot Vector3f/UNIT_X))
920 y (.mult pre-inv-a (.mult joint-rot Vector3f/UNIT_Y))
921 z (.mult pre-inv-a (.mult joint-rot Vector3f/UNIT_Z))
923 x Vector3f/UNIT_Y
924 y Vector3f/UNIT_Z
925 z Vector3f/UNIT_X
928 tmp-rot-a (.getWorldRotation obj-a)]
929 (println-repl "x:" (.mult tmp-rot-a x))
930 (println-repl "y:" (.mult tmp-rot-a y))
931 (println-repl "z:" (.mult tmp-rot-a z))
932 (println-repl "rot-a" (.getWorldRotation obj-a))
933 (println-repl "rot-b" (.getWorldRotation obj-b))
934 (println-repl "joint-rot" joint-rot)
935 ;; this function will report proprioceptive information for the
936 ;; joint.
937 (fn []
938 ;; x is the "twist" axis, y and z are the "bend" axes
939 (let [rot-a (.getWorldRotation obj-a)
940 ;;inv-a (.inverse rot-a)
941 rot-b (.getWorldRotation obj-b)
942 ;;relative (.mult rot-b inv-a)
943 basis (doto (Matrix3f.)
944 (.setColumn 0 (.mult rot-a x))
945 (.setColumn 1 (.mult rot-a y))
946 (.setColumn 2 (.mult rot-a z)))
947 rotation-about-joint
948 (doto (Quaternion.)
949 (.fromRotationMatrix
950 (.mult (.invert basis)
951 (.toRotationMatrix rot-b))))
952 [yaw roll pitch]
953 (seq (.toAngles rotation-about-joint nil))]
954 ;;return euler angles of the quaternion around the new basis
955 [yaw roll pitch]))))
957 #+end_src
965 * COMMENT generate Source
966 #+begin_src clojure :tangle ../src/cortex/body.clj
967 <<joints>>
968 #+end_src
970 #+begin_src clojure :tangle ../src/cortex/test/body.clj
971 <<test-body>>
972 #+end_src