diff org/body.org @ 63:7f2653ad3199

cleaning
author Robert McIntyre <rlm@mit.edu>
date Tue, 29 Nov 2011 02:46:46 -0700
parents 2b9d81017cb7
children ab1fee4280c3
line wrap: on
line diff
     1.1 --- a/org/body.org	Mon Nov 28 21:28:46 2011 -0700
     1.2 +++ b/org/body.org	Tue Nov 29 02:46:46 2011 -0700
     1.3 @@ -5,7 +5,7 @@
     1.4  #+SETUPFILE: ../../aurellem/org/setup.org
     1.5  #+INCLUDE: ../../aurellem/org/level-0.org
     1.6  
     1.7 -* Body  
     1.8 +* COMMENT Body  
     1.9  
    1.10  #+srcname: body-main
    1.11  #+begin_src clojure 
    1.12 @@ -16,35 +16,21 @@
    1.13  (cortex.import/mega-import-jme3)
    1.14  (rlm.rlm-commands/help)
    1.15  
    1.16 -(defn load-blender-model 
    1.17 +(defn load-blender-model
    1.18 +  "Load a .blend file using an asset folder relative path."
    1.19    [^String model]
    1.20    (.loadModel
    1.21     (doto (asset-manager)
    1.22       (.registerLoader BlenderModelLoader (into-array String ["blend"])))
    1.23     model))
    1.24  
    1.25 -(defn skel [node]
    1.26 -  (doto
    1.27 -      (.getSkeleton
    1.28 -       (.getControl node SkeletonControl))
    1.29 -    ;; this is necessary to force the skeleton to have accurate world
    1.30 -    ;; transforms before it is rendered to the screen. 
    1.31 -    (.resetAndUpdate)))
    1.32 -
    1.33 -
    1.34 -(defn green-x-ray []
    1.35 -  (doto (Material. (asset-manager)
    1.36 -                   "Common/MatDefs/Misc/Unshaded.j3md")
    1.37 -    (.setColor "Color" ColorRGBA/Green)
    1.38 -    (-> (.getAdditionalRenderState)
    1.39 -        (.setDepthTest false))))
    1.40 -
    1.41 -
    1.42  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    1.43  
    1.44  ;;;;;;;;;;;;  eve-style bodies  ;;;;;;;;
    1.45  
    1.46 -(defn worm [segment-length num-segments interstitial-space radius]
    1.47 +(defn worm-segments
    1.48 +  "Create multiple evenly spaced box segments. They're fabulous!"
    1.49 +  [segment-length num-segments interstitial-space radius]
    1.50    (letfn [(nth-segment
    1.51              [n]
    1.52              (box segment-length radius radius :mass 0.1
    1.53 @@ -55,14 +41,20 @@
    1.54                   :color (ColorRGBA/randomColor)))]
    1.55      (map nth-segment (range num-segments))))
    1.56  
    1.57 -
    1.58  (defn connect-at-midpoint
    1.59 +  "Connect two physics objects with a Point2Point joint constraint at
    1.60 +  the point equidistant from both objects' centers."
    1.61    [segmentA segmentB]
    1.62    (let [centerA (.getWorldTranslation segmentA)
    1.63          centerB (.getWorldTranslation segmentB)
    1.64          midpoint (.mult (.add centerA centerB) (float 0.5))
    1.65          pivotA (.subtract midpoint centerA)
    1.66          pivotB (.subtract midpoint centerB)
    1.67 +
    1.68 +        ;; A side-effect of creating a joint registers
    1.69 +        ;; it with both physics objects which in turn
    1.70 +        ;; will register the joint with the physics system
    1.71 +        ;; when the simulation is started.
    1.72          joint (Point2PointJoint.
    1.73                 (.getControl segmentA RigidBodyControl)
    1.74                 (.getControl segmentB RigidBodyControl)
    1.75 @@ -71,146 +63,34 @@
    1.76    segmentB))
    1.77  
    1.78  (defn point-worm []
    1.79 -  (let [segments (worm 0.2 5 0.1 0.1)]
    1.80 +  (let [segments (worm-segments 0.2 5 0.1 0.1)]
    1.81      (dorun (map (partial apply connect-at-midpoint)
    1.82                  (partition 2 1 segments)))
    1.83 -    (nodify "worm"  segments)))
    1.84 +    (nodify "worm" segments)))
    1.85  
    1.86 -(defn test-worm []
    1.87 -  (.start
    1.88 -   (world
    1.89 -    (doto (Node.)
    1.90 -      ;;(.attachChild (point-worm))
    1.91 -      (.attachChild (load-blender-model
    1.92 -                     "Models/anim2/joint-worm.blend"))
    1.93 -                      
    1.94 -      (.attachChild (box 10 1 10
    1.95 -                         :position (Vector3f. 0 -2 0) :mass 0
    1.96 -                         :color (ColorRGBA/Gray))))
    1.97 -    {
    1.98 -     "key-space" (fire-cannon-ball)
    1.99 -     }
   1.100 -    (fn [world]
   1.101 -      (enable-debug world)
   1.102 -      (light-up-everything world)
   1.103 -      ;;(.setTimer world (NanoTimer.))
   1.104 -      )
   1.105 -    no-op)))
   1.106 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.107 +;;;;;;;;;  Proprioception  ;;;;;;;;;;;;;
   1.108 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.109  
   1.110 -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.111 +(declare
   1.112 + ;; generate an arbitray (but stable) orthogonal vector
   1.113 + ;; to a given vector.
   1.114 + some-orthogonal
   1.115  
   1.116 + ;; determine the amount of rotation a quaternion will
   1.117 + ;; cause about a given axis
   1.118 + project-quaternion
   1.119  
   1.120 -;;;;;;;;;  Mortor Control  ;;;;;;;;;;;;;
   1.121 + ;; proprioception for a single joint
   1.122 + joint-proprioception
   1.123 + 
   1.124 + ;; create a function that provides proprioceptive information
   1.125 + ;; about an entire body.
   1.126 + proprioception)
   1.127  
   1.128 -
   1.129 -;; surprisingly ehough, terristerial creatures only move by using
   1.130 -;; torque applied to their joints.  There's not a single straight line
   1.131 -;; of force in the human body at all!  (a straight line of force would
   1.132 -;; correspond to some sort of jet or rocket propulseion)
   1.133 -  
   1.134 -(defn torque-controls [control]
   1.135 -  (let [torques
   1.136 -        (concat
   1.137 -         (map #(Vector3f. 0 (Math/sin %) (Math/cos %))
   1.138 -              (range 0 (* Math/PI 2) (/ (* Math/PI 2) 20)))
   1.139 -         [Vector3f/UNIT_X])]
   1.140 -    (map (fn [torque-axis]
   1.141 -           (fn [torque]
   1.142 -             (.applyTorque
   1.143 -              control
   1.144 -              (.mult (.mult (.getPhysicsRotation control)
   1.145 -                            torque-axis)
   1.146 -                     (float
   1.147 -                      (* (.getMass control) torque))))))
   1.148 -         torques)))
   1.149 -
   1.150 -(defn motor-map
   1.151 -  "Take a creature and generate a function that will enable fine
   1.152 -   grained control over all the creature's limbs."  
   1.153 -  [#^Node creature]
   1.154 -  (let [controls (keep #(.getControl % RigidBodyControl)
   1.155 -                       (node-seq creature))
   1.156 -        limb-controls (reduce concat (map torque-controls controls))
   1.157 -        body-control  (partial map #(%1 %2) limb-controls)]
   1.158 -    body-control))
   1.159 -
   1.160 -(defn test-motor-map
   1.161 -  "see how torque works."
   1.162 -  []
   1.163 -  (let [finger (box 3 0.5 0.5 :position (Vector3f. 0 2 0)
   1.164 -                    :mass 1 :color ColorRGBA/Green)
   1.165 -        motor-map (motor-map finger)]
   1.166 -    (world
   1.167 -     (nodify [finger
   1.168 -              (box 10 0.5 10 :position (Vector3f. 0 -5 0) :mass 0
   1.169 -                   :color ColorRGBA/Gray)])
   1.170 -     standard-debug-controls
   1.171 -     (fn [world]
   1.172 -       (set-gravity world Vector3f/ZERO)
   1.173 -       (light-up-everything world)
   1.174 -       (.setTimer world (NanoTimer.)))
   1.175 -     (fn [_ _]
   1.176 -       (dorun (motor-map [0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0]))))))
   1.177 -
   1.178 -(defn test-torque
   1.179 -  "see how torque works."
   1.180 -  []
   1.181 -  (let [finger (box 3 0.5 0.5 :position (Vector3f. 0 2 0)
   1.182 -                    :mass 1 :color ColorRGBA/Green)
   1.183 -        move-left? (atom false)
   1.184 -        move-right? (atom false)
   1.185 -        control (.getControl finger RigidBodyControl)]
   1.186 -    (world
   1.187 -     (nodify [finger
   1.188 -              (box 10 0.5 10 :position (Vector3f. 0 -5 0) :mass 0
   1.189 -                   :color ColorRGBA/Gray)])
   1.190 -     (merge standard-debug-controls
   1.191 -            {"key-k" (fn [_ pressed?] (reset! move-left? pressed?))
   1.192 -             "key-l" (fn [_ pressed?] (reset! move-right? pressed?))})
   1.193 -     (fn [world]
   1.194 -       (set-gravity world Vector3f/ZERO)
   1.195 -       (light-up-everything world)
   1.196 -       (.setTimer world (NanoTimer.)))
   1.197 -     (fn [_ _]
   1.198 -       (if @move-left?
   1.199 -         (.applyTorque control
   1.200 -                       (.mult (.getPhysicsRotation control)
   1.201 -                       (Vector3f. -3 20 0))))
   1.202 -       (if @move-right?
   1.203 -         (.applyTorque control (Vector3f. 0 0 1)))))))
   1.204 -
   1.205 -(defn worm-pattern [time]
   1.206 -  [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
   1.207 -
   1.208 -   0 0 0 0 0 0 0 0 0 0 0
   1.209 -
   1.210 -   (* 20 (Math/sin (* Math/PI 2 (/ (rem time 300 ) 300))))
   1.211 -
   1.212 -   0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
   1.213 -  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
   1.214 -  0 0 0 0 0 0 0 0 0 0 0 0 0 0
   1.215 -
   1.216 -   ])
   1.217 -
   1.218 -;;;;;;;;;;;;;;;;;;  Proprioception  ;;;;;;;;;;;;;;;;;;;;;;;;
   1.219 -
   1.220 -;; this is not used as just getting the rotation would be simpler.
   1.221 -(defn proprioception-senses 
   1.222 -  "given a control , create a sequence of thunks that will report the
   1.223 -  rotation of the control's object along the same axes as the motor-control map."
   1.224 -  [control]
   1.225 -  (let [torques
   1.226 -        (concat
   1.227 -         (map #(Vector3f. 0 (Math/sin %) (Math/cos %))
   1.228 -              (range 0 (* Math/PI 2) (/ (* Math/PI 2) 20)))
   1.229 -         [Vector3f/UNIT_X])]
   1.230 -    (map (fn [torque-axis]
   1.231 -           (fn []
   1.232 -             (.getPhysicsRotation control)))
   1.233 -           torques)))
   1.234 -
   1.235 -(defn orthogonal-vect
   1.236 -  "Return a vector orthogonal to the current one"
   1.237 +(defn some-orthogonal
   1.238 +  "Generate an arbitray (but stable) orthogonal vector to a given
   1.239 +   vector."
   1.240    [vector]
   1.241    (let [x (.getX vector)
   1.242          y (.getY vector)
   1.243 @@ -221,10 +101,13 @@
   1.244       (not= z (float 0)) (Vector3f. 0 (- z) y)
   1.245       true Vector3f/ZERO)))
   1.246  
   1.247 -;; from
   1.248 -;; http://stackoverflow.com/questions/3684269/ \\
   1.249 -;;   component-of-a-quaternion-rotation-around-an-axis
   1.250 -(defn rot-about-axis [#^Quaternion q #^Vector3f axis]
   1.251 +(defn project-quaternion
   1.252 +  "From http://stackoverflow.com/questions/3684269/
   1.253 +   component-of-a-quaternion-rotation-around-an-axis.
   1.254 +
   1.255 +   Determine the amount of rotation a quaternion will
   1.256 +   cause about a given axis."
   1.257 +  [#^Quaternion q #^Vector3f axis]
   1.258    (let [basis-1 (orthogonal-vect axis)
   1.259          basis-2 (.cross axis basis-1)
   1.260          rotated (.mult q basis-1)
   1.261 @@ -232,15 +115,11 @@
   1.262          beta  (.dot basis-2 (.project rotated basis-2))]
   1.263      (Math/atan2 beta alpha)))
   1.264  
   1.265 -
   1.266 -(defn check-rot [a]
   1.267 -  (rot-about-axis
   1.268 -   (doto (Quaternion.)
   1.269 -     (.fromAngleAxis
   1.270 -      (float a)
   1.271 -      (Vector3f. 1 0 0))) (Vector3f. 1 0 0)))
   1.272 -
   1.273 -(defn relative-positions [joint]
   1.274 +(defn joint-proprioception
   1.275 +  "Relative position information for a two-part system connected by a
   1.276 +   joint. Gives the pitch, yaw, and roll of the 'B' object relative to
   1.277 +   the 'A' object, as determined by the joint."
   1.278 +  [joint]
   1.279    (let [object-a (.getUserObject (.getBodyA joint))
   1.280          object-b (.getUserObject (.getBodyB joint))
   1.281          arm-a
   1.282 @@ -273,80 +152,105 @@
   1.283            (.getLocalRotation object-b)
   1.284            (doto (Quaternion.)
   1.285              (.fromRotationMatrix rotate-a)))
   1.286 -         arm-b)
   1.287 -         ]
   1.288 -         
   1.289 -                
   1.290 -
   1.291 -    ;;(println-repl
   1.292 -    ;; "arm-b is " arm-b)
   1.293 -    ;;(println-repl
   1.294 -    ;; "pivot-b is " (.getPivotB joint))
   1.295 -    ;;(println-repl
   1.296 -    ;; (format "pitch: %1.2f\nyaw: %1.2f\nroll: %1.2f\n"
   1.297 -    ;;         pitch yaw roll))
   1.298 +         arm-b)]
   1.299      [pitch yaw roll]))
   1.300  
   1.301 -        
   1.302 -    
   1.303 -        
   1.304 +(defn proprioception
   1.305 +  "Create a function that provides proprioceptive information about an
   1.306 +  entire body."
   1.307 +  [body]
   1.308 +  ;; extract the body's joints
   1.309 +  (let [joints 
   1.310 +        (distinct
   1.311 +         (reduce
   1.312 +          concat
   1.313 +          (map #(.getJoints %)
   1.314 +               (keep
   1.315 +                #(.getControl % RigidBodyControl)
   1.316 +                (node-seq body)))))]
   1.317 +    (fn []
   1.318 +      (map joint-proprioception joints))))
   1.319    
   1.320 -        
   1.321 +
   1.322 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.323 +;;;;;;;;;  Mortor Control  ;;;;;;;;;;;;;
   1.324 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.325 +
   1.326 +
   1.327 +;; surprisingly enough, terristerial creatures only move by using
   1.328 +;; torque applied about their joints.  There's not a single straight
   1.329 +;; line of force in the human body at all!  (A straight line of force
   1.330 +;; would correspond to some sort of jet or rocket propulseion.)
   1.331 +
   1.332 +(defn vector-motor-control
   1.333 +  "Create a function that accepts a sequence of Vector3f objects that
   1.334 +   describe the torque to be applied to each part of the body."
   1.335 +  [body]
   1.336 +  (let [nodes (node-seq body)
   1.337 +        controls (keep #(.getControl % RigidBodyControl) nodes)]
   1.338 +    (fn [torques]
   1.339 +      (map #(.applyTorque %1 %2)
   1.340 +           controls torques))))
   1.341 +
   1.342 +;; note -- might want to add a lower dimensional, discrete version of
   1.343 +;; this if it proves usefull from a x-modal clustering perspective.
   1.344 +
   1.345 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.346 +
   1.347 +
   1.348 +
   1.349 +(defn worm-pattern [time]
   1.350 +  [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
   1.351 +
   1.352 +   0 0 0 0 0 0 0 0 0 0 0
   1.353 +
   1.354 +   (* 20 (Math/sin (* Math/PI 2 (/ (rem time 300 ) 300))))
   1.355 +
   1.356 +   0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
   1.357 +  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
   1.358 +  0 0 0 0 0 0 0 0 0 0 0 0 0 0
   1.359 +
   1.360 +   ])
   1.361 +
   1.362 +(defn worm-pattern [time]
   1.363 +  (let [angle (* Math/PI (/ 4 20))
   1.364 +        direction (Vector3f. 0 (Math/sin angle) (Math/cos angle))]
   1.365 +    [Vector3f/ZERO
   1.366 +     (.mult
   1.367 +      direction
   1.368 +      (float (* 2 (Math/sin (* Math/PI 2 (/ (rem time 300 ) 300))))))
   1.369 +     Vector3f/ZERO
   1.370 +     Vector3f/ZERO
   1.371 +     Vector3f/ZERO]))
   1.372  
   1.373  (defn test-worm-control
   1.374    []
   1.375    (let [worm (point-worm)
   1.376          time (atom 0)
   1.377 -        worm-motor-map (motor-map worm)
   1.378 -        ;;body-map (proprioception worm)
   1.379 -        debug-segments
   1.380 -        (map
   1.381 -         #(doto
   1.382 -              (make-shape
   1.383 -               (assoc base-shape
   1.384 -                 :name "debug-line"
   1.385 -                 :physical? false
   1.386 -                 :shape
   1.387 -                 (com.jme3.scene.shape.Line.
   1.388 -                  (.add (.getWorldTranslation %)
   1.389 -                        (Vector3f. -0.2 0 0 ))
   1.390 -                  (.add (.getWorldTranslation %)
   1.391 -                        (Vector3f. 0.2 0 0)))))
   1.392 -                 (.setMaterial (green-x-ray)))
   1.393 -            (drop 1 (node-seq worm)))]
   1.394 +        worm-motor-map (vector-motor-control worm)]
   1.395      (world
   1.396       (nodify [worm
   1.397                (box 10 0.5 10 :position (Vector3f. 0 -5 0) :mass 0
   1.398                     :color ColorRGBA/Gray)])
   1.399       standard-debug-controls
   1.400       (fn [world]
   1.401 -       (.attachChild (.getRootNode world) (nodify debug-segments))
   1.402         (enable-debug world)
   1.403         (light-up-everything world)
   1.404 -       (com.aurellem.capture.Capture/captureVideo
   1.405 -        world
   1.406 -        (file-str "/home/r/proj/cortex/tmp/moving-worm")))
   1.407 +       (comment
   1.408 +         (com.aurellem.capture.Capture/captureVideo
   1.409 +          world
   1.410 +          (file-str "/home/r/proj/cortex/tmp/moving-worm")))
   1.411 +       )
   1.412       
   1.413       (fn [_ _]
   1.414 -       (dorun
   1.415 -        (map
   1.416 -         (fn [worm-segment
   1.417 -              debug-segment]
   1.418 -           (.rotate
   1.419 -            debug-segment
   1.420 -            (Quaternion. (float 0) (float 0.05) (float 0) (float 1))))
   1.421 -         (drop 1 (node-seq worm))
   1.422 -         debug-segments))
   1.423         (swap! time inc)
   1.424 -       ;;(println-repl (with-out-str (clojure.pprint/pprint (doall (body-map)))))
   1.425 -       (Thread/sleep 200)
   1.426 +       ;;(Thread/sleep 200)
   1.427         (dorun (worm-motor-map
   1.428                 (worm-pattern @time)))))))
   1.429  
   1.430  
   1.431  
   1.432  
   1.433 -
   1.434  (defn test-prop
   1.435    "see how torque works."
   1.436    []
   1.437 @@ -428,7 +332,7 @@
   1.438  #+end_src
   1.439  
   1.440  
   1.441 -* COMMENT failed-clojure-code
   1.442 +* COMMENT code-limbo
   1.443  #+begin_src clojure
   1.444  ;;(.loadModel 
   1.445  ;; (doto (asset-manager)
   1.446 @@ -759,6 +663,90 @@
   1.447        (reduce concat (map relative-positions (list (first joints)))))))
   1.448  
   1.449  
   1.450 +(defn skel [node]
   1.451 +  (doto
   1.452 +      (.getSkeleton
   1.453 +       (.getControl node SkeletonControl))
   1.454 +    ;; this is necessary to force the skeleton to have accurate world
   1.455 +    ;; transforms before it is rendered to the screen. 
   1.456 +    (.resetAndUpdate)))
   1.457 +
   1.458 +(defn green-x-ray []
   1.459 +  (doto (Material. (asset-manager)
   1.460 +                   "Common/MatDefs/Misc/Unshaded.j3md")
   1.461 +    (.setColor "Color" ColorRGBA/Green)
   1.462 +    (-> (.getAdditionalRenderState)
   1.463 +        (.setDepthTest false))))
   1.464 +
   1.465 +(defn test-worm []
   1.466 +  (.start
   1.467 +   (world
   1.468 +    (doto (Node.)
   1.469 +      ;;(.attachChild (point-worm))
   1.470 +      (.attachChild (load-blender-model
   1.471 +                     "Models/anim2/joint-worm.blend"))
   1.472 +                      
   1.473 +      (.attachChild (box 10 1 10
   1.474 +                         :position (Vector3f. 0 -2 0) :mass 0
   1.475 +                         :color (ColorRGBA/Gray))))
   1.476 +    {
   1.477 +     "key-space" (fire-cannon-ball)
   1.478 +     }
   1.479 +    (fn [world]
   1.480 +      (enable-debug world)
   1.481 +      (light-up-everything world)
   1.482 +      ;;(.setTimer world (NanoTimer.))
   1.483 +      )
   1.484 +    no-op)))
   1.485 +
   1.486 +
   1.487 +
   1.488 +;; defunct movement stuff
   1.489 +(defn torque-controls [control]
   1.490 +  (let [torques
   1.491 +        (concat
   1.492 +         (map #(Vector3f. 0 (Math/sin %) (Math/cos %))
   1.493 +              (range 0 (* Math/PI 2) (/ (* Math/PI 2) 20)))
   1.494 +         [Vector3f/UNIT_X])]
   1.495 +    (map (fn [torque-axis]
   1.496 +           (fn [torque]
   1.497 +             (.applyTorque
   1.498 +              control
   1.499 +              (.mult (.mult (.getPhysicsRotation control)
   1.500 +                            torque-axis)
   1.501 +                     (float
   1.502 +                      (* (.getMass control) torque))))))
   1.503 +         torques)))
   1.504 +
   1.505 +(defn motor-map
   1.506 +  "Take a creature and generate a function that will enable fine
   1.507 +   grained control over all the creature's limbs."  
   1.508 +  [#^Node creature]
   1.509 +  (let [controls (keep #(.getControl % RigidBodyControl)
   1.510 +                       (node-seq creature))
   1.511 +        limb-controls (reduce concat (map torque-controls controls))
   1.512 +        body-control  (partial map #(%1 %2) limb-controls)]
   1.513 +    body-control))
   1.514 +
   1.515 +(defn test-motor-map
   1.516 +  "see how torque works."
   1.517 +  []
   1.518 +  (let [finger (box 3 0.5 0.5 :position (Vector3f. 0 2 0)
   1.519 +                    :mass 1 :color ColorRGBA/Green)
   1.520 +        motor-map (motor-map finger)]
   1.521 +    (world
   1.522 +     (nodify [finger
   1.523 +              (box 10 0.5 10 :position (Vector3f. 0 -5 0) :mass 0
   1.524 +                   :color ColorRGBA/Gray)])
   1.525 +     standard-debug-controls
   1.526 +     (fn [world]
   1.527 +       (set-gravity world Vector3f/ZERO)
   1.528 +       (light-up-everything world)
   1.529 +       (.setTimer world (NanoTimer.)))
   1.530 +     (fn [_ _]
   1.531 +       (dorun (motor-map [0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0]))))))
   1.532 +
   1.533 +
   1.534  #+end_src
   1.535  
   1.536