# HG changeset patch # User Robert McIntyre # Date 1322560006 25200 # Node ID 7f2653ad3199319c72462b5e9e997e810643f831 # Parent 2b9d81017cb780435a5a8077242af1952e37862b cleaning diff -r 2b9d81017cb7 -r 7f2653ad3199 org/body.org --- a/org/body.org Mon Nov 28 21:28:46 2011 -0700 +++ b/org/body.org Tue Nov 29 02:46:46 2011 -0700 @@ -5,7 +5,7 @@ #+SETUPFILE: ../../aurellem/org/setup.org #+INCLUDE: ../../aurellem/org/level-0.org -* Body +* COMMENT Body #+srcname: body-main #+begin_src clojure @@ -16,35 +16,21 @@ (cortex.import/mega-import-jme3) (rlm.rlm-commands/help) -(defn load-blender-model +(defn load-blender-model + "Load a .blend file using an asset folder relative path." [^String model] (.loadModel (doto (asset-manager) (.registerLoader BlenderModelLoader (into-array String ["blend"]))) model)) -(defn skel [node] - (doto - (.getSkeleton - (.getControl node SkeletonControl)) - ;; this is necessary to force the skeleton to have accurate world - ;; transforms before it is rendered to the screen. - (.resetAndUpdate))) - - -(defn green-x-ray [] - (doto (Material. (asset-manager) - "Common/MatDefs/Misc/Unshaded.j3md") - (.setColor "Color" ColorRGBA/Green) - (-> (.getAdditionalRenderState) - (.setDepthTest false)))) - - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;; eve-style bodies ;;;;;;;; -(defn worm [segment-length num-segments interstitial-space radius] +(defn worm-segments + "Create multiple evenly spaced box segments. They're fabulous!" + [segment-length num-segments interstitial-space radius] (letfn [(nth-segment [n] (box segment-length radius radius :mass 0.1 @@ -55,14 +41,20 @@ :color (ColorRGBA/randomColor)))] (map nth-segment (range num-segments)))) - (defn connect-at-midpoint + "Connect two physics objects with a Point2Point joint constraint at + the point equidistant from both objects' centers." [segmentA segmentB] (let [centerA (.getWorldTranslation segmentA) centerB (.getWorldTranslation segmentB) midpoint (.mult (.add centerA centerB) (float 0.5)) pivotA (.subtract midpoint centerA) pivotB (.subtract midpoint centerB) + + ;; A side-effect of creating a joint registers + ;; it with both physics objects which in turn + ;; will register the joint with the physics system + ;; when the simulation is started. joint (Point2PointJoint. (.getControl segmentA RigidBodyControl) (.getControl segmentB RigidBodyControl) @@ -71,146 +63,34 @@ segmentB)) (defn point-worm [] - (let [segments (worm 0.2 5 0.1 0.1)] + (let [segments (worm-segments 0.2 5 0.1 0.1)] (dorun (map (partial apply connect-at-midpoint) (partition 2 1 segments))) - (nodify "worm" segments))) + (nodify "worm" segments))) -(defn test-worm [] - (.start - (world - (doto (Node.) - ;;(.attachChild (point-worm)) - (.attachChild (load-blender-model - "Models/anim2/joint-worm.blend")) - - (.attachChild (box 10 1 10 - :position (Vector3f. 0 -2 0) :mass 0 - :color (ColorRGBA/Gray)))) - { - "key-space" (fire-cannon-ball) - } - (fn [world] - (enable-debug world) - (light-up-everything world) - ;;(.setTimer world (NanoTimer.)) - ) - no-op))) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;; Proprioception ;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(declare + ;; generate an arbitray (but stable) orthogonal vector + ;; to a given vector. + some-orthogonal + ;; determine the amount of rotation a quaternion will + ;; cause about a given axis + project-quaternion -;;;;;;;;; Mortor Control ;;;;;;;;;;;;; + ;; proprioception for a single joint + joint-proprioception + + ;; create a function that provides proprioceptive information + ;; about an entire body. + proprioception) - -;; surprisingly ehough, terristerial creatures only move by using -;; torque applied to their joints. There's not a single straight line -;; of force in the human body at all! (a straight line of force would -;; correspond to some sort of jet or rocket propulseion) - -(defn torque-controls [control] - (let [torques - (concat - (map #(Vector3f. 0 (Math/sin %) (Math/cos %)) - (range 0 (* Math/PI 2) (/ (* Math/PI 2) 20))) - [Vector3f/UNIT_X])] - (map (fn [torque-axis] - (fn [torque] - (.applyTorque - control - (.mult (.mult (.getPhysicsRotation control) - torque-axis) - (float - (* (.getMass control) torque)))))) - torques))) - -(defn motor-map - "Take a creature and generate a function that will enable fine - grained control over all the creature's limbs." - [#^Node creature] - (let [controls (keep #(.getControl % RigidBodyControl) - (node-seq creature)) - limb-controls (reduce concat (map torque-controls controls)) - body-control (partial map #(%1 %2) limb-controls)] - body-control)) - -(defn test-motor-map - "see how torque works." - [] - (let [finger (box 3 0.5 0.5 :position (Vector3f. 0 2 0) - :mass 1 :color ColorRGBA/Green) - motor-map (motor-map finger)] - (world - (nodify [finger - (box 10 0.5 10 :position (Vector3f. 0 -5 0) :mass 0 - :color ColorRGBA/Gray)]) - standard-debug-controls - (fn [world] - (set-gravity world Vector3f/ZERO) - (light-up-everything world) - (.setTimer world (NanoTimer.))) - (fn [_ _] - (dorun (motor-map [0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0])))))) - -(defn test-torque - "see how torque works." - [] - (let [finger (box 3 0.5 0.5 :position (Vector3f. 0 2 0) - :mass 1 :color ColorRGBA/Green) - move-left? (atom false) - move-right? (atom false) - control (.getControl finger RigidBodyControl)] - (world - (nodify [finger - (box 10 0.5 10 :position (Vector3f. 0 -5 0) :mass 0 - :color ColorRGBA/Gray)]) - (merge standard-debug-controls - {"key-k" (fn [_ pressed?] (reset! move-left? pressed?)) - "key-l" (fn [_ pressed?] (reset! move-right? pressed?))}) - (fn [world] - (set-gravity world Vector3f/ZERO) - (light-up-everything world) - (.setTimer world (NanoTimer.))) - (fn [_ _] - (if @move-left? - (.applyTorque control - (.mult (.getPhysicsRotation control) - (Vector3f. -3 20 0)))) - (if @move-right? - (.applyTorque control (Vector3f. 0 0 1))))))) - -(defn worm-pattern [time] - [ 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 - - (* 20 (Math/sin (* Math/PI 2 (/ (rem time 300 ) 300)))) - - 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 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 0 0 - - ]) - -;;;;;;;;;;;;;;;;;; Proprioception ;;;;;;;;;;;;;;;;;;;;;;;; - -;; this is not used as just getting the rotation would be simpler. -(defn proprioception-senses - "given a control , create a sequence of thunks that will report the - rotation of the control's object along the same axes as the motor-control map." - [control] - (let [torques - (concat - (map #(Vector3f. 0 (Math/sin %) (Math/cos %)) - (range 0 (* Math/PI 2) (/ (* Math/PI 2) 20))) - [Vector3f/UNIT_X])] - (map (fn [torque-axis] - (fn [] - (.getPhysicsRotation control))) - torques))) - -(defn orthogonal-vect - "Return a vector orthogonal to the current one" +(defn some-orthogonal + "Generate an arbitray (but stable) orthogonal vector to a given + vector." [vector] (let [x (.getX vector) y (.getY vector) @@ -221,10 +101,13 @@ (not= z (float 0)) (Vector3f. 0 (- z) y) true Vector3f/ZERO))) -;; from -;; http://stackoverflow.com/questions/3684269/ \\ -;; component-of-a-quaternion-rotation-around-an-axis -(defn rot-about-axis [#^Quaternion q #^Vector3f axis] +(defn project-quaternion + "From http://stackoverflow.com/questions/3684269/ + component-of-a-quaternion-rotation-around-an-axis. + + Determine the amount of rotation a quaternion will + cause about a given axis." + [#^Quaternion q #^Vector3f axis] (let [basis-1 (orthogonal-vect axis) basis-2 (.cross axis basis-1) rotated (.mult q basis-1) @@ -232,15 +115,11 @@ beta (.dot basis-2 (.project rotated basis-2))] (Math/atan2 beta alpha))) - -(defn check-rot [a] - (rot-about-axis - (doto (Quaternion.) - (.fromAngleAxis - (float a) - (Vector3f. 1 0 0))) (Vector3f. 1 0 0))) - -(defn relative-positions [joint] +(defn joint-proprioception + "Relative position information for a two-part system connected by a + joint. Gives the pitch, yaw, and roll of the 'B' object relative to + the 'A' object, as determined by the joint." + [joint] (let [object-a (.getUserObject (.getBodyA joint)) object-b (.getUserObject (.getBodyB joint)) arm-a @@ -273,80 +152,105 @@ (.getLocalRotation object-b) (doto (Quaternion.) (.fromRotationMatrix rotate-a))) - arm-b) - ] - - - - ;;(println-repl - ;; "arm-b is " arm-b) - ;;(println-repl - ;; "pivot-b is " (.getPivotB joint)) - ;;(println-repl - ;; (format "pitch: %1.2f\nyaw: %1.2f\nroll: %1.2f\n" - ;; pitch yaw roll)) + arm-b)] [pitch yaw roll])) - - - +(defn proprioception + "Create a function that provides proprioceptive information about an + entire body." + [body] + ;; extract the body's joints + (let [joints + (distinct + (reduce + concat + (map #(.getJoints %) + (keep + #(.getControl % RigidBodyControl) + (node-seq body)))))] + (fn [] + (map joint-proprioception joints)))) - + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;; Mortor Control ;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + +;; surprisingly enough, terristerial creatures only move by using +;; torque applied about their joints. There's not a single straight +;; line of force in the human body at all! (A straight line of force +;; would correspond to some sort of jet or rocket propulseion.) + +(defn vector-motor-control + "Create a function that accepts a sequence of Vector3f objects that + describe the torque to be applied to each part of the body." + [body] + (let [nodes (node-seq body) + controls (keep #(.getControl % RigidBodyControl) nodes)] + (fn [torques] + (map #(.applyTorque %1 %2) + controls torques)))) + +;; note -- might want to add a lower dimensional, discrete version of +;; this if it proves usefull from a x-modal clustering perspective. + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + + +(defn worm-pattern [time] + [ 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 + + (* 20 (Math/sin (* Math/PI 2 (/ (rem time 300 ) 300)))) + + 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 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 0 0 + + ]) + +(defn worm-pattern [time] + (let [angle (* Math/PI (/ 4 20)) + direction (Vector3f. 0 (Math/sin angle) (Math/cos angle))] + [Vector3f/ZERO + (.mult + direction + (float (* 2 (Math/sin (* Math/PI 2 (/ (rem time 300 ) 300)))))) + Vector3f/ZERO + Vector3f/ZERO + Vector3f/ZERO])) (defn test-worm-control [] (let [worm (point-worm) time (atom 0) - worm-motor-map (motor-map worm) - ;;body-map (proprioception worm) - debug-segments - (map - #(doto - (make-shape - (assoc base-shape - :name "debug-line" - :physical? false - :shape - (com.jme3.scene.shape.Line. - (.add (.getWorldTranslation %) - (Vector3f. -0.2 0 0 )) - (.add (.getWorldTranslation %) - (Vector3f. 0.2 0 0))))) - (.setMaterial (green-x-ray))) - (drop 1 (node-seq worm)))] + worm-motor-map (vector-motor-control worm)] (world (nodify [worm (box 10 0.5 10 :position (Vector3f. 0 -5 0) :mass 0 :color ColorRGBA/Gray)]) standard-debug-controls (fn [world] - (.attachChild (.getRootNode world) (nodify debug-segments)) (enable-debug world) (light-up-everything world) - (com.aurellem.capture.Capture/captureVideo - world - (file-str "/home/r/proj/cortex/tmp/moving-worm"))) + (comment + (com.aurellem.capture.Capture/captureVideo + world + (file-str "/home/r/proj/cortex/tmp/moving-worm"))) + ) (fn [_ _] - (dorun - (map - (fn [worm-segment - debug-segment] - (.rotate - debug-segment - (Quaternion. (float 0) (float 0.05) (float 0) (float 1)))) - (drop 1 (node-seq worm)) - debug-segments)) (swap! time inc) - ;;(println-repl (with-out-str (clojure.pprint/pprint (doall (body-map))))) - (Thread/sleep 200) + ;;(Thread/sleep 200) (dorun (worm-motor-map (worm-pattern @time))))))) - (defn test-prop "see how torque works." [] @@ -428,7 +332,7 @@ #+end_src -* COMMENT failed-clojure-code +* COMMENT code-limbo #+begin_src clojure ;;(.loadModel ;; (doto (asset-manager) @@ -759,6 +663,90 @@ (reduce concat (map relative-positions (list (first joints))))))) +(defn skel [node] + (doto + (.getSkeleton + (.getControl node SkeletonControl)) + ;; this is necessary to force the skeleton to have accurate world + ;; transforms before it is rendered to the screen. + (.resetAndUpdate))) + +(defn green-x-ray [] + (doto (Material. (asset-manager) + "Common/MatDefs/Misc/Unshaded.j3md") + (.setColor "Color" ColorRGBA/Green) + (-> (.getAdditionalRenderState) + (.setDepthTest false)))) + +(defn test-worm [] + (.start + (world + (doto (Node.) + ;;(.attachChild (point-worm)) + (.attachChild (load-blender-model + "Models/anim2/joint-worm.blend")) + + (.attachChild (box 10 1 10 + :position (Vector3f. 0 -2 0) :mass 0 + :color (ColorRGBA/Gray)))) + { + "key-space" (fire-cannon-ball) + } + (fn [world] + (enable-debug world) + (light-up-everything world) + ;;(.setTimer world (NanoTimer.)) + ) + no-op))) + + + +;; defunct movement stuff +(defn torque-controls [control] + (let [torques + (concat + (map #(Vector3f. 0 (Math/sin %) (Math/cos %)) + (range 0 (* Math/PI 2) (/ (* Math/PI 2) 20))) + [Vector3f/UNIT_X])] + (map (fn [torque-axis] + (fn [torque] + (.applyTorque + control + (.mult (.mult (.getPhysicsRotation control) + torque-axis) + (float + (* (.getMass control) torque)))))) + torques))) + +(defn motor-map + "Take a creature and generate a function that will enable fine + grained control over all the creature's limbs." + [#^Node creature] + (let [controls (keep #(.getControl % RigidBodyControl) + (node-seq creature)) + limb-controls (reduce concat (map torque-controls controls)) + body-control (partial map #(%1 %2) limb-controls)] + body-control)) + +(defn test-motor-map + "see how torque works." + [] + (let [finger (box 3 0.5 0.5 :position (Vector3f. 0 2 0) + :mass 1 :color ColorRGBA/Green) + motor-map (motor-map finger)] + (world + (nodify [finger + (box 10 0.5 10 :position (Vector3f. 0 -5 0) :mass 0 + :color ColorRGBA/Gray)]) + standard-debug-controls + (fn [world] + (set-gravity world Vector3f/ZERO) + (light-up-everything world) + (.setTimer world (NanoTimer.))) + (fn [_ _] + (dorun (motor-map [0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0])))))) + + #+end_src