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