Mercurial > cortex
view org/test-creature.org @ 123:91773e8ec50f
got hearing diaplay working
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Mon, 23 Jan 2012 03:41:26 -0700 |
parents | b591da250afc |
children | 90154bd674e9 |
line wrap: on
line source
1 #+title: First attempt at a creature!2 #+author: Robert McIntyre3 #+email: rlm@mit.edu4 #+description:5 #+keywords: simulation, jMonkeyEngine3, clojure6 #+SETUPFILE: ../../aurellem/org/setup.org7 #+INCLUDE: ../../aurellem/org/level-0.org9 * objectives10 - [X] get an overall bitmap-like image for touch11 - [X] write code to visuliaze this bitmap12 - [ ] directly change the UV-pixels to show touch sensor activation13 - [ ] write an explination for why b&w bitmaps for senses is appropiate14 - [ ] clean up touch code and write visulazation test15 - [ ] do the same for eyes17 * Intro18 So far, I've made the following senses --19 - Vision20 - Hearing21 - Touch22 - Proprioception24 And one effector:25 - Movement27 However, the code so far has only enabled these senses, but has not28 actually implemented them. For example, there is still a lot of work29 to be done for vision. I need to be able to create an /eyeball/ in30 simulation that can be moved around and see the world from different31 angles. I also need to determine weather to use log-polar or cartesian32 for the visual input, and I need to determine how/wether to33 disceritise the visual input.35 I also want to be able to visualize both the sensors and the36 effectors in pretty pictures. This semi-retarted creature will be my37 first attempt at bringing everything together.39 * The creature's body41 Still going to do an eve-like body in blender, but due to problems42 importing the joints, etc into jMonkeyEngine3, I'm going to do all43 the connecting here in clojure code, using the names of the individual44 components and trial and error. Later, I'll maybe make some sort of45 creature-building modifications to blender that support whatever46 discreitized senses I'm going to make.48 #+name: body-149 #+begin_src clojure50 (ns cortex.silly51 "let's play!"52 {:author "Robert McIntyre"})54 ;; TODO remove this!55 (require 'cortex.import)56 (cortex.import/mega-import-jme3)57 (use '(cortex world util body hearing touch vision))59 (rlm.rlm-commands/help)60 (import java.awt.image.BufferedImage)61 (import javax.swing.JPanel)62 (import javax.swing.SwingUtilities)63 (import java.awt.Dimension)64 (import javax.swing.JFrame)65 (import java.awt.Dimension)66 (import com.aurellem.capture.RatchetTimer)67 (declare joint-create)68 (use 'clojure.contrib.def)70 (defn points->image71 "Take a sparse collection of points and visuliaze it as a72 BufferedImage."74 ;; TODO maybe parallelize this since it's easy76 [points]77 (if (empty? points)78 (BufferedImage. 1 1 BufferedImage/TYPE_BYTE_BINARY)79 (let [xs (vec (map first points))80 ys (vec (map second points))81 x0 (apply min xs)82 y0 (apply min ys)83 width (- (apply max xs) x0)84 height (- (apply max ys) y0)85 image (BufferedImage. (inc width) (inc height)86 BufferedImage/TYPE_INT_RGB)]87 (dorun88 (for [x (range (.getWidth image))89 y (range (.getHeight image))]90 (.setRGB image x y 0xFF0000)))91 (dorun92 (for [index (range (count points))]93 (.setRGB image (- (xs index) x0) (- (ys index) y0) -1)))95 image)))97 (defn average [coll]98 (/ (reduce + coll) (count coll)))100 (defn collapse-1d101 "One dimensional analogue of collapse"102 [center line]103 (let [length (count line)104 num-above (count (filter (partial < center) line))105 num-below (- length num-above)]106 (range (- center num-below)107 (+ center num-above))))109 (defn collapse110 "Take a set of pairs of integers and collapse them into a111 contigous bitmap."112 [points]113 (if (empty? points) []114 (let115 [num-points (count points)116 center (vector117 (int (average (map first points)))118 (int (average (map first points))))119 flattened120 (reduce121 concat122 (map123 (fn [column]124 (map vector125 (map first column)126 (collapse-1d (second center)127 (map second column))))128 (partition-by first (sort-by first points))))129 squeezed130 (reduce131 concat132 (map133 (fn [row]134 (map vector135 (collapse-1d (first center)136 (map first row))137 (map second row)))138 (partition-by second (sort-by second flattened))))139 relocate140 (let [min-x (apply min (map first squeezed))141 min-y (apply min (map second squeezed))]142 (map (fn [[x y]]143 [(- x min-x)144 (- y min-y)])145 squeezed))]146 relocate)))148 (defn load-bullet []149 (let [sim (world (Node.) {} no-op no-op)]150 (doto sim151 (.enqueue152 (fn []153 (.stop sim)))154 (.start))))156 (defn load-blender-model157 "Load a .blend file using an asset folder relative path."158 [^String model]159 (.loadModel160 (doto (asset-manager)161 (.registerLoader BlenderModelLoader (into-array String ["blend"])))162 model))164 (defn meta-data [blender-node key]165 (if-let [data (.getUserData blender-node "properties")]166 (.findValue data key)167 nil))169 (defn blender-to-jme170 "Convert from Blender coordinates to JME coordinates"171 [#^Vector3f in]172 (Vector3f. (.getX in)173 (.getZ in)174 (- (.getY in))))176 (defn jme-to-blender177 "Convert from JME coordinates to Blender coordinates"178 [#^Vector3f in]179 (Vector3f. (.getX in)180 (- (.getZ in))181 (.getY in)))183 (defn joint-targets184 "Return the two closest two objects to the joint object, ordered185 from bottom to top according to the joint's rotation."186 [#^Node parts #^Node joint]187 (loop [radius (float 0.01)]188 (let [results (CollisionResults.)]189 (.collideWith190 parts191 (BoundingBox. (.getWorldTranslation joint)192 radius radius radius)193 results)194 (let [targets195 (distinct196 (map #(.getGeometry %) results))]197 (if (>= (count targets) 2)198 (sort-by199 #(let [v200 (jme-to-blender201 (.mult202 (.inverse (.getWorldRotation joint))203 (.subtract (.getWorldTranslation %)204 (.getWorldTranslation joint))))]205 (println-repl (.getName %) ":" v)206 (.dot (Vector3f. 1 1 1)207 v))208 (take 2 targets))209 (recur (float (* radius 2))))))))211 (defn world-to-local212 "Convert the world coordinates into coordinates relative to the213 object (i.e. local coordinates), taking into account the rotation214 of object."215 [#^Spatial object world-coordinate]216 (let [out (Vector3f.)]217 (.worldToLocal object world-coordinate out) out))219 (defn local-to-world220 "Convert the local coordinates into coordinates into world relative221 coordinates"222 [#^Spatial object local-coordinate]223 (let [world-coordinate (Vector3f.)]224 (.localToWorld object local-coordinate world-coordinate)225 world-coordinate))227 (defmulti joint-dispatch228 "Translate blender pseudo-joints into real JME joints."229 (fn [constraints & _]230 (:type constraints)))232 (defmethod joint-dispatch :point233 [constraints control-a control-b pivot-a pivot-b rotation]234 (println-repl "creating POINT2POINT joint")235 (Point2PointJoint.236 control-a237 control-b238 pivot-a239 pivot-b))241 (defmethod joint-dispatch :hinge242 [constraints control-a control-b pivot-a pivot-b rotation]243 (println-repl "creating HINGE joint")244 (let [axis245 (if-let246 [axis (:axis constraints)]247 axis248 Vector3f/UNIT_X)249 [limit-1 limit-2] (:limit constraints)250 hinge-axis251 (.mult252 rotation253 (blender-to-jme axis))]254 (doto255 (HingeJoint.256 control-a257 control-b258 pivot-a259 pivot-b260 hinge-axis261 hinge-axis)262 (.setLimit limit-1 limit-2))))264 (defmethod joint-dispatch :cone265 [constraints control-a control-b pivot-a pivot-b rotation]266 (let [limit-xz (:limit-xz constraints)267 limit-xy (:limit-xy constraints)268 twist (:twist constraints)]270 (println-repl "creating CONE joint")271 (println-repl rotation)272 (println-repl273 "UNIT_X --> " (.mult rotation (Vector3f. 1 0 0)))274 (println-repl275 "UNIT_Y --> " (.mult rotation (Vector3f. 0 1 0)))276 (println-repl277 "UNIT_Z --> " (.mult rotation (Vector3f. 0 0 1)))278 (doto279 (ConeJoint.280 control-a281 control-b282 pivot-a283 pivot-b284 rotation285 rotation)286 (.setLimit (float limit-xz)287 (float limit-xy)288 (float twist)))))290 (defn connect291 "here are some examples:292 {:type :point}293 {:type :hinge :limit [0 (/ Math/PI 2)] :axis (Vector3f. 0 1 0)}294 (:axis defaults to (Vector3f. 1 0 0) if not provided for hinge joints)296 {:type :cone :limit-xz 0]297 :limit-xy 0]298 :twist 0]} (use XZY rotation mode in blender!)"299 [#^Node obj-a #^Node obj-b #^Node joint]300 (let [control-a (.getControl obj-a RigidBodyControl)301 control-b (.getControl obj-b RigidBodyControl)302 joint-center (.getWorldTranslation joint)303 joint-rotation (.toRotationMatrix (.getWorldRotation joint))304 pivot-a (world-to-local obj-a joint-center)305 pivot-b (world-to-local obj-b joint-center)]307 (if-let [constraints308 (map-vals309 eval310 (read-string311 (meta-data joint "joint")))]312 ;; A side-effect of creating a joint registers313 ;; it with both physics objects which in turn314 ;; will register the joint with the physics system315 ;; when the simulation is started.316 (do317 (println-repl "creating joint between"318 (.getName obj-a) "and" (.getName obj-b))319 (joint-dispatch constraints320 control-a control-b321 pivot-a pivot-b322 joint-rotation))323 (println-repl "could not find joint meta-data!"))))325 (defn assemble-creature [#^Node pieces joints]326 (dorun327 (map328 (fn [geom]329 (let [physics-control330 (RigidBodyControl.331 (HullCollisionShape.332 (.getMesh geom))333 (if-let [mass (meta-data geom "mass")]334 (do335 (println-repl336 "setting" (.getName geom) "mass to" (float mass))337 (float mass))338 (float 1)))]340 (.addControl geom physics-control)))341 (filter #(isa? (class %) Geometry )342 (node-seq pieces))))343 (dorun344 (map345 (fn [joint]346 (let [[obj-a obj-b]347 (joint-targets pieces joint)]348 (connect obj-a obj-b joint)))349 joints))350 pieces)352 (declare blender-creature)354 (def hand "Models/creature1/one.blend")356 (def worm "Models/creature1/try-again.blend")358 (def touch "Models/creature1/touch.blend")360 (defn worm-model [] (load-blender-model worm))362 (defn x-ray [#^ColorRGBA color]363 (doto (Material. (asset-manager)364 "Common/MatDefs/Misc/Unshaded.j3md")365 (.setColor "Color" color)366 (-> (.getAdditionalRenderState)367 (.setDepthTest false))))369 (defn colorful []370 (.getChild (worm-model) "worm-21"))372 (import jme3tools.converters.ImageToAwt)374 (import ij.ImagePlus)376 ;; Every Mesh has many triangles, each with its own index.377 ;; Every vertex has its own index as well.379 (defn tactile-sensor-image380 "Return the touch-sensor distribution image in BufferedImage format,381 or nil if it does not exist."382 [#^Geometry obj]383 (if-let [image-path (meta-data obj "touch")]384 (ImageToAwt/convert385 (.getImage386 (.loadTexture387 (asset-manager)388 image-path))389 false false 0)))391 (import ij.process.ImageProcessor)392 (import java.awt.image.BufferedImage)394 (def white -1)396 (defn filter-pixels397 "List the coordinates of all pixels matching pred, within the bounds398 provided. Bounds -> [x0 y0 width height]"399 {:author "Dylan Holmes"}400 ([pred #^BufferedImage image]401 (filter-pixels pred image [0 0 (.getWidth image) (.getHeight image)]))402 ([pred #^BufferedImage image [x0 y0 width height]]403 ((fn accumulate [x y matches]404 (cond405 (>= y (+ height y0)) matches406 (>= x (+ width x0)) (recur 0 (inc y) matches)407 (pred (.getRGB image x y))408 (recur (inc x) y (conj matches [x y]))409 :else (recur (inc x) y matches)))410 x0 y0 [])))412 (defn white-coordinates413 "Coordinates of all the white pixels in a subset of the image."414 ([#^BufferedImage image bounds]415 (filter-pixels #(= % white) image bounds))416 ([#^BufferedImage image]417 (filter-pixels #(= % white) image)))419 (defn triangle420 "Get the triangle specified by triangle-index from the mesh within421 bounds."422 [#^Mesh mesh triangle-index]423 (let [scratch (Triangle.)]424 (.getTriangle mesh triangle-index scratch)425 scratch))427 (defn triangle-vertex-indices428 "Get the triangle vertex indices of a given triangle from a given429 mesh."430 [#^Mesh mesh triangle-index]431 (let [indices (int-array 3)]432 (.getTriangle mesh triangle-index indices)433 (vec indices)))435 (defn vertex-UV-coord436 "Get the uv-coordinates of the vertex named by vertex-index"437 [#^Mesh mesh vertex-index]438 (let [UV-buffer439 (.getData440 (.getBuffer441 mesh442 VertexBuffer$Type/TexCoord))]443 [(.get UV-buffer (* vertex-index 2))444 (.get UV-buffer (+ 1 (* vertex-index 2)))]))446 (defn triangle-UV-coord447 "Get the uv-cooridnates of the triangle's verticies."448 [#^Mesh mesh width height triangle-index]449 (map (fn [[u v]] (vector (* width u) (* height v)))450 (map (partial vertex-UV-coord mesh)451 (triangle-vertex-indices mesh triangle-index))))453 (defn same-side?454 "Given the points p1 and p2 and the reference point ref, is point p455 on the same side of the line that goes through p1 and p2 as ref is?"456 [p1 p2 ref p]457 (<=458 0459 (.dot460 (.cross (.subtract p2 p1) (.subtract p p1))461 (.cross (.subtract p2 p1) (.subtract ref p1)))))463 (defn triangle-seq [#^Triangle tri]464 [(.get1 tri) (.get2 tri) (.get3 tri)])466 (defn vector3f-seq [#^Vector3f v]467 [(.getX v) (.getY v) (.getZ v)])469 (defn inside-triangle?470 "Is the point inside the triangle?"471 {:author "Dylan Holmes"}472 [#^Triangle tri #^Vector3f p]473 (let [[vert-1 vert-2 vert-3] (triangle-seq tri)]474 (and475 (same-side? vert-1 vert-2 vert-3 p)476 (same-side? vert-2 vert-3 vert-1 p)477 (same-side? vert-3 vert-1 vert-2 p))))479 (defn triangle->matrix4f480 "Converts the triangle into a 4x4 matrix: The first three columns481 contain the vertices of the triangle; the last contains the unit482 normal of the triangle. The bottom row is filled with 1s."483 [#^Triangle t]484 (let [mat (Matrix4f.)485 [vert-1 vert-2 vert-3]486 ((comp vec map) #(.get t %) (range 3))487 unit-normal (do (.calculateNormal t)(.getNormal t))488 vertices [vert-1 vert-2 vert-3 unit-normal]]489 (dorun490 (for [row (range 4) col (range 3)]491 (do492 (.set mat col row (.get (vertices row)col))493 (.set mat 3 row 1))))494 mat))496 (defn triangle-transformation497 "Returns the affine transformation that converts each vertex in the498 first triangle into the corresponding vertex in the second499 triangle."500 [#^Triangle tri-1 #^Triangle tri-2]501 (.mult502 (triangle->matrix4f tri-2)503 (.invert (triangle->matrix4f tri-1))))505 (defn point->vector2f [[u v]]506 (Vector2f. u v))508 (defn vector2f->vector3f [v]509 (Vector3f. (.getX v) (.getY v) 0))511 (defn map-triangle [f #^Triangle tri]512 (Triangle.513 (f 0 (.get1 tri))514 (f 1 (.get2 tri))515 (f 2 (.get3 tri))))517 (defn points->triangle518 "Convert a list of points into a triangle."519 [points]520 (apply #(Triangle. %1 %2 %3)521 (map (fn [point]522 (let [point (vec point)]523 (Vector3f. (get point 0 0)524 (get point 1 0)525 (get point 2 0))))526 (take 3 points))))528 (defn convex-bounds529 "Dimensions of the smallest integer bounding square of the list of530 2D verticies in the form: [x y width height]."531 [uv-verts]532 (let [xs (map first uv-verts)533 ys (map second uv-verts)534 x0 (Math/floor (apply min xs))535 y0 (Math/floor (apply min ys))536 x1 (Math/ceil (apply max xs))537 y1 (Math/ceil (apply max ys))]538 [x0 y0 (- x1 x0) (- y1 y0)]))540 (defn sensors-in-triangle541 "Find the locations of the touch sensors within a triangle in both542 UV and gemoetry relative coordinates."543 [image mesh tri-index]544 (let [width (.getWidth image)545 height (.getHeight image)546 UV-vertex-coords (triangle-UV-coord mesh width height tri-index)547 bounds (convex-bounds UV-vertex-coords)549 cutout-triangle (points->triangle UV-vertex-coords)550 UV-sensor-coords551 (filter (comp (partial inside-triangle? cutout-triangle)552 (fn [[u v]] (Vector3f. u v 0)))553 (white-coordinates image bounds))554 UV->geometry (triangle-transformation555 cutout-triangle556 (triangle mesh tri-index))557 geometry-sensor-coords558 (map (fn [[u v]] (.mult UV->geometry (Vector3f. u v 0)))559 UV-sensor-coords)]560 {:UV UV-sensor-coords :geometry geometry-sensor-coords}))562 (defn-memo locate-feelers563 "Search the geometry's tactile UV image for touch sensors, returning564 their positions in geometry-relative coordinates."565 [#^Geometry geo]566 (let [mesh (.getMesh geo)567 num-triangles (.getTriangleCount mesh)]568 (if-let [image (tactile-sensor-image geo)]569 (map570 (partial sensors-in-triangle image mesh)571 (range num-triangles))572 (repeat (.getTriangleCount mesh) {:UV nil :geometry nil}))))574 (use 'clojure.contrib.def)576 (defn-memo touch-topology [#^Gemoetry geo]577 (vec (collapse (reduce concat (map :UV (locate-feelers geo))))))579 (defn-memo feeler-coordinates [#^Geometry geo]580 (vec (map :geometry (locate-feelers geo))))582 (defn enable-touch [#^Geometry geo]583 (let [feeler-coords (feeler-coordinates geo)584 tris (triangles geo)585 limit 0.1586 ;;results (CollisionResults.)587 ]588 (if (empty? (touch-topology geo))589 nil590 (fn [node]591 (let [sensor-origins592 (map593 #(map (partial local-to-world geo) %)594 feeler-coords)595 triangle-normals596 (map (partial get-ray-direction geo)597 tris)598 rays599 (flatten600 (map (fn [origins norm]601 (map #(doto (Ray. % norm)602 (.setLimit limit)) origins))603 sensor-origins triangle-normals))]604 (vector605 (touch-topology geo)606 (vec607 (for [ray rays]608 (do609 (let [results (CollisionResults.)]610 (.collideWith node ray results)611 (let [touch-objects612 (set613 (filter #(not (= geo %))614 (map #(.getGeometry %) results)))]615 (if (> (count touch-objects) 0)616 1 0))))))))))))618 (defn touch [#^Node pieces]619 (filter (comp not nil?)620 (map enable-touch621 (filter #(isa? (class %) Geometry)622 (node-seq pieces)))))625 ;; human eye transmits 62kb/s to brain Bandwidth is 8.75 Mb/s626 ;; http://en.wikipedia.org/wiki/Retina628 (defn test-eye []629 (.getChild630 (.getChild (worm-model) "eyes")631 "eye"))634 (defn retina-sensor-image635 "Return a map of pixel selection functions to BufferedImages636 describing the distribution of light-sensitive components on this637 geometry's surface. Each function creates an integer from the rgb638 values found in the pixel. :red, :green, :blue, :gray are already639 defined as extracting the red green blue and average components640 respectively."641 [#^Spatial eye]642 (if-let [eye-map (meta-data eye "eye")]643 (map-vals644 #(ImageToAwt/convert645 (.getImage (.loadTexture (asset-manager) %))646 false false 0)647 (eval (read-string eye-map)))))649 (defn eye-dimensions650 "returns the width and height specified in the metadata of the eye"651 [#^Spatial eye]652 (let [dimensions653 (map #(vector (.getWidth %) (.getHeight %))654 (vals (retina-sensor-image eye)))]655 [(apply max (map first dimensions))656 (apply max (map second dimensions))]))658 (defn creature-eyes659 "The eye nodes which are children of the \"eyes\" node in the660 creature."661 [#^Node creature]662 (if-let [eye-node (.getChild creature "eyes")]663 (seq (.getChildren eye-node))664 (do (println-repl "could not find eyes node") [])))666 ;; Here's how vision will work.668 ;; Make the continuation in scene-processor take FrameBuffer,669 ;; byte-buffer, BufferedImage already sized to the correct670 ;; dimensions. the continuation will decide wether to "mix" them671 ;; into the BufferedImage, lazily ignore them, or mix them halfway672 ;; and call c/graphics card routines.674 ;; (vision creature) will take an optional :skip argument which will675 ;; inform the continuations in scene processor to skip the given676 ;; number of cycles; 0 means that no cycles will be skipped.678 ;; (vision creature) will return [init-functions sensor-functions].679 ;; The init-functions are each single-arg functions that take the680 ;; world and register the cameras and must each be called before the681 ;; corresponding sensor-functions. Each init-function returns the682 ;; viewport for that eye which can be manipulated, saved, etc. Each683 ;; sensor-function is a thunk and will return data in the same684 ;; format as the tactile-sensor functions; the structure is685 ;; [topology, sensor-data]. Internally, these sensor-functions686 ;; maintain a reference to sensor-data which is periodically updated687 ;; by the continuation function established by its init-function.688 ;; They can be queried every cycle, but their information may not689 ;; necessairly be different every cycle.691 ;; Each eye in the creature in blender will work the same way as692 ;; joints -- a zero dimensional object with no geometry whose local693 ;; coordinate system determines the orientation of the resulting694 ;; eye. All eyes will have a parent named "eyes" just as all joints695 ;; have a parent named "joints". The resulting camera will be a696 ;; ChaseCamera or a CameraNode bound to the geo that is closest to697 ;; the eye marker. The eye marker will contain the metadata for the698 ;; eye, and will be moved by it's bound geometry. The dimensions of699 ;; the eye's camera are equal to the dimensions of the eye's "UV"700 ;; map.703 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;705 ;; Ears work the same way as vision.707 ;; (hearing creature) will return [init-functions708 ;; sensor-functions]. The init functions each take the world and709 ;; register a SoundProcessor that does foureier transforms on the710 ;; incommong sound data, making it available to each sensor function.712 (defn creature-ears713 "The ear nodes which are children of the \"ears\" node in the714 creature."715 [#^Node creature]716 (if-let [ear-node (.getChild creature "ears")]717 (seq (.getChildren ear-node))718 (do (println-repl "could not find ears node") [])))720 (defn closest-node721 "The closest object in creature to the given node."722 [#^Node creature #^Node eye]723 (loop [radius (float 0.01)]724 (let [results (CollisionResults.)]725 (.collideWith726 creature727 (BoundingBox. (.getWorldTranslation eye)728 radius radius radius)729 results)730 (if-let [target (first results)]731 (.getGeometry target)732 (recur (float (* 2 radius)))))))734 (defn bind-sense735 "Bind the sense to the Spatial such that it will maintain its736 current position relative to the Spatial no matter how the spatial737 moves. 'sense can be either a Camera or Listener object."738 [#^Spatial obj sense]739 (let [sense-offset (.subtract (.getLocation sense)740 (.getWorldTranslation obj))741 initial-sense-rotation (Quaternion. (.getRotation sense))742 base-anti-rotation (.inverse (.getWorldRotation obj))]743 (.addControl744 obj745 (proxy [AbstractControl] []746 (controlUpdate [tpf]747 (let [total-rotation748 (.mult base-anti-rotation (.getWorldRotation obj))]749 (.setLocation sense750 (.add751 (.mult total-rotation sense-offset)752 (.getWorldTranslation obj)))753 (.setRotation sense754 (.mult total-rotation initial-sense-rotation))))755 (controlRender [_ _])))))758 (defn update-listener-velocity759 "Update the listener's velocity every update loop."760 [#^Spatial obj #^Listener lis]761 (let [old-position (atom (.getLocation lis))]762 (.addControl763 obj764 (proxy [AbstractControl] []765 (controlUpdate [tpf]766 (let [new-position (.getLocation lis)]767 (.setVelocity768 lis769 (.mult (.subtract new-position @old-position)770 (float (/ tpf))))771 (reset! old-position new-position)))772 (controlRender [_ _])))))774 (import com.aurellem.capture.audio.AudioSendRenderer)776 (defn attach-ear777 [#^Application world #^Node creature #^Spatial ear continuation]778 (let [target (closest-node creature ear)779 lis (Listener.)780 audio-renderer (.getAudioRenderer world)781 sp (sound-processor continuation)]782 (println-repl "audio-renderer is " audio-renderer)783 (.setLocation lis (.getWorldTranslation ear))784 (.setRotation lis (.getWorldRotation ear))785 (bind-sense target lis)786 (update-listener-velocity target lis)787 (.addListener audio-renderer lis)788 (.registerSoundProcessor audio-renderer lis sp)))790 (defn enable-hearing791 [#^Node creature #^Spatial ear]792 (let [hearing-data (atom [])]793 [(fn [world]794 (attach-ear world creature ear795 (fn [data]796 (reset! hearing-data (vec data)))))797 [(fn []798 (let [data @hearing-data799 topology800 (vec (map #(vector % 0) (range 0 (count data))))801 scaled-data802 (vec803 (map804 #(rem (int (* 255 (/ (+ 1 %) 2))) 256)805 data))]806 (println-repl (take 10 scaled-data))807 [topology scaled-data]))808 ]]))810 (defn hearing811 [#^Node creature]812 (reduce813 (fn [[init-a senses-a]814 [init-b senses-b]]815 [(conj init-a init-b)816 (into senses-a senses-b)])817 [[][]]818 (for [ear (creature-ears creature)]819 (enable-hearing creature ear))))821 (defn attach-eye822 "Attach a Camera to the appropiate area and return the Camera."823 [#^Node creature #^Spatial eye]824 (let [target (closest-node creature eye)825 [cam-width cam-height] (eye-dimensions eye)826 cam (Camera. cam-width cam-height)]827 (.setLocation cam (.getWorldTranslation eye))828 (.setRotation cam (.getWorldRotation eye))829 (.setFrustumPerspective830 cam 45 (/ (.getWidth cam) (.getHeight cam))831 1 1000)832 (bind-sense target cam)833 cam))835 (def presets836 {:all 0xFFFFFF837 :red 0xFF0000838 :blue 0x0000FF839 :green 0x00FF00})841 (defn enable-vision842 "return [init-function sensor-functions] for a particular eye"843 [#^Node creature #^Spatial eye & {skip :skip :or {skip 0}}]844 (let [retinal-map (retina-sensor-image eye)845 camera (attach-eye creature eye)846 vision-image847 (atom848 (BufferedImage. (.getWidth camera)849 (.getHeight camera)850 BufferedImage/TYPE_BYTE_BINARY))]851 [(fn [world]852 (add-eye853 world camera854 (let [counter (atom 0)]855 (fn [r fb bb bi]856 (if (zero? (rem (swap! counter inc) (inc skip)))857 (reset! vision-image (BufferedImage! r fb bb bi)))))))858 (vec859 (map860 (fn [[key image]]861 (let [whites (white-coordinates image)862 topology (vec (collapse whites))863 mask (presets key)]864 (fn []865 (vector866 topology867 (vec868 (for [[x y] whites]869 (bit-and870 mask (.getRGB @vision-image x y))))))))871 retinal-map))]))873 (defn vision874 [#^Node creature & {skip :skip :or {skip 0}}]875 (reduce876 (fn [[init-a senses-a]877 [init-b senses-b]]878 [(conj init-a init-b)879 (into senses-a senses-b)])880 [[][]]881 (for [eye (creature-eyes creature)]882 (enable-vision creature eye))))885 (defn blender-creature886 "Return a creature with all joints in place."887 [blender-path]888 (let [model (load-blender-model blender-path)889 joints890 (if-let [joint-node (.getChild model "joints")]891 (seq (.getChildren joint-node))892 (do (println-repl "could not find joints node") []))]893 (assemble-creature model joints)))895 (defn debug-window896 "creates function that offers a debug view of sensor data"897 []898 (let [vi (view-image)]899 (fn900 [[coords sensor-data]]901 (let [image (points->image coords)]902 (dorun903 (for [i (range (count coords))]904 (.setRGB image ((coords i) 0) ((coords i) 1)905 ({0 0x000000906 1 0xFFFFFF} (sensor-data i)))))907 (vi image)))))909 (defn debug-vision-window910 "creates function that offers a debug view of sensor data"911 []912 (let [vi (view-image)]913 (fn914 [[coords sensor-data]]915 (let [image (points->image coords)]916 (dorun917 (for [i (range (count coords))]918 (.setRGB image ((coords i) 0) ((coords i) 1)919 (sensor-data i))))920 (vi image)))))922 (defn debug-hearing-window923 "view audio data"924 [height]925 (let [vi (view-image)]926 (fn [[coords sensor-data]]927 (let [image (BufferedImage. (count coords) height928 BufferedImage/TYPE_INT_RGB)]929 (dorun930 (for [x (range (count coords))]931 (dorun932 (for [y (range height)]933 (let [raw-sensor (sensor-data x)]934 (.setRGB image x y935 (+ raw-sensor936 (bit-shift-left raw-sensor 8)937 (bit-shift-left raw-sensor 16))))))))938 (vi image)))))942 ;;(defn test-touch [world creature]949 (defn test-creature [thing]950 (let [x-axis951 (box 1 0.01 0.01 :physical? false :color ColorRGBA/Red)952 y-axis953 (box 0.01 1 0.01 :physical? false :color ColorRGBA/Green)954 z-axis955 (box 0.01 0.01 1 :physical? false :color ColorRGBA/Blue)956 creature (blender-creature thing)957 touch-nerves (touch creature)958 touch-debug-windows (map (fn [_] (debug-window)) touch-nerves)959 [init-vision-fns vision-data] (vision creature)960 vision-debug (map (fn [_] (debug-vision-window)) vision-data)961 me (sphere 0.5 :color ColorRGBA/Blue :physical? false)962 [init-hearing-fns hearing-senses] (hearing creature)963 hearing-windows (map (fn [_] (debug-hearing-window 50))964 hearing-senses)965 bang (AudioNode. (asset-manager)966 "Sounds/dream.wav" false)967 ;; dream969 ]970 (world971 (nodify [creature972 (box 10 2 10 :position (Vector3f. 0 -9 0)973 :color ColorRGBA/Gray :mass 0)974 x-axis y-axis z-axis975 me976 ])977 (merge standard-debug-controls978 {"key-return"979 (fn [_ value]980 (if value981 (do982 (println-repl "play-sound")983 (.play bang))))})984 (fn [world]985 (light-up-everything world)986 (enable-debug world)987 (dorun (map #(% world) init-vision-fns))988 (dorun (map #(% world) init-hearing-fns))990 (add-eye world991 (attach-eye creature (test-eye))992 (comp (view-image) BufferedImage!))994 (add-eye world (.getCamera world) no-op)996 ;;(com.aurellem.capture.Capture/captureVideo997 ;; world (file-str "/home/r/proj/ai-videos/hand"))998 ;;(.setTimer world (RatchetTimer. 60))999 (speed-up world)1000 ;;(set-gravity world (Vector3f. 0 0 0))1001 )1002 (fn [world tpf]1003 ;;(dorun1004 ;; (map #(%1 %2) touch-nerves (repeat (.getRootNode world))))1008 (dorun1009 (map #(%1 (%2 (.getRootNode world)))1010 touch-debug-windows touch-nerves))1012 (dorun1013 (map #(%1 (%2))1014 vision-debug vision-data))1015 (dorun1016 (map #(%1 (%2)) hearing-windows hearing-senses))1019 ;;(println-repl (vision-data))1020 (.setLocalTranslation me (.getLocation (.getCamera world)))1023 )1024 ;;(let [timer (atom 0)]1025 ;; (fn [_ _]1026 ;; (swap! timer inc)1027 ;; (if (= (rem @timer 60) 0)1028 ;; (println-repl (float (/ @timer 60))))))1029 )))1039 ;;; experiments in collisions1043 (defn collision-test []1044 (let [b-radius 11045 b-position (Vector3f. 0 0 0)1046 obj-b (box 1 1 1 :color ColorRGBA/Blue1047 :position b-position1048 :mass 0)1049 node (nodify [obj-b])1050 bounds-b1051 (doto (Picture.)1052 (.setHeight 50)1053 (.setWidth 50)1054 (.setImage (asset-manager)1055 "Models/creature1/hand.png"1056 false1057 ))1059 ;;(Ray. (Vector3f. 0 -5 0) (.normalize (Vector3f. 0 1 0)))1061 collisions1062 (let [cr (CollisionResults.)]1063 (.collideWith node bounds-b cr)1064 (println (map #(.getContactPoint %) cr))1065 cr)1067 ;;collision-points1068 ;;(map #(sphere 0.1 :position (.getContactPoint %))1069 ;; collisions)1071 ;;node (nodify (conj collision-points obj-b))1073 sim1074 (world node1075 {"key-space"1076 (fn [_ value]1077 (if value1078 (let [cr (CollisionResults.)]1079 (.collideWith node bounds-b cr)1080 (println-repl (map #(.getContactPoint %) cr))1081 cr)))}1082 no-op1083 no-op)1085 ]1086 sim1088 ))1091 ;; the camera will stay in its initial position/rotation with relation1092 ;; to the spatial.1095 (defn follow-test1096 "show a camera that stays in the same relative position to a blue cube."1097 []1098 (let [camera-pos (Vector3f. 0 30 0)1099 rock (box 1 1 1 :color ColorRGBA/Blue1100 :position (Vector3f. 0 10 0)1101 :mass 301102 )1103 rot (.getWorldRotation rock)1105 table (box 3 1 10 :color ColorRGBA/Gray :mass 01106 :position (Vector3f. 0 -3 0))]1108 (world1109 (nodify [rock table])1110 standard-debug-controls1111 (fn [world]1112 (let1113 [cam (doto (.clone (.getCamera world))1114 (.setLocation camera-pos)1115 (.lookAt Vector3f/ZERO1116 Vector3f/UNIT_X))]1117 (bind-sense rock cam)1119 (.setTimer world (RatchetTimer. 60))1120 (add-eye world cam (comp (view-image) BufferedImage!))1121 (add-eye world (.getCamera world) no-op))1122 )1123 (fn [_ _] (println-repl rot)))))1127 #+end_src1129 #+results: body-11130 : #'cortex.silly/test-creature1133 * COMMENT purgatory1134 #+begin_src clojure1135 (defn bullet-trans []1136 (let [obj-a (sphere 0.5 :color ColorRGBA/Red1137 :position (Vector3f. -10 5 0))1138 obj-b (sphere 0.5 :color ColorRGBA/Blue1139 :position (Vector3f. -10 -5 0)1140 :mass 0)1141 control-a (.getControl obj-a RigidBodyControl)1142 control-b (.getControl obj-b RigidBodyControl)1143 swivel1144 (.toRotationMatrix1145 (doto (Quaternion.)1146 (.fromAngleAxis (/ Math/PI 2)1147 Vector3f/UNIT_X)))]1148 (doto1149 (ConeJoint.1150 control-a control-b1151 (Vector3f. 0 5 0)1152 (Vector3f. 0 -5 0)1153 swivel swivel)1154 (.setLimit (* 0.6 (/ Math/PI 4))1155 (/ Math/PI 4)1156 (* Math/PI 0.8)))1157 (world (nodify1158 [obj-a obj-b])1159 standard-debug-controls1160 enable-debug1161 no-op)))1164 (defn bullet-trans* []1165 (let [obj-a (box 1.5 0.5 0.5 :color ColorRGBA/Red1166 :position (Vector3f. 5 0 0)1167 :mass 90)1168 obj-b (sphere 0.5 :color ColorRGBA/Blue1169 :position (Vector3f. -5 0 0)1170 :mass 0)1171 control-a (.getControl obj-a RigidBodyControl)1172 control-b (.getControl obj-b RigidBodyControl)1173 move-up? (atom nil)1174 move-down? (atom nil)1175 move-left? (atom nil)1176 move-right? (atom nil)1177 roll-left? (atom nil)1178 roll-right? (atom nil)1179 force 1001180 swivel1181 (.toRotationMatrix1182 (doto (Quaternion.)1183 (.fromAngleAxis (/ Math/PI 2)1184 Vector3f/UNIT_X)))1185 x-move1186 (doto (Matrix3f.)1187 (.fromStartEndVectors Vector3f/UNIT_X1188 (.normalize (Vector3f. 1 1 0))))1190 timer (atom 0)]1191 (doto1192 (ConeJoint.1193 control-a control-b1194 (Vector3f. -8 0 0)1195 (Vector3f. 2 0 0)1196 ;;swivel swivel1197 ;;Matrix3f/IDENTITY Matrix3f/IDENTITY1198 x-move Matrix3f/IDENTITY1199 )1200 (.setCollisionBetweenLinkedBodys false)1201 (.setLimit (* 1 (/ Math/PI 4)) ;; twist1202 (* 1 (/ Math/PI 4)) ;; swing span in X-Y plane1203 (* 0 (/ Math/PI 4)))) ;; swing span in Y-Z plane1204 (world (nodify1205 [obj-a obj-b])1206 (merge standard-debug-controls1207 {"key-r" (fn [_ pressed?] (reset! move-up? pressed?))1208 "key-t" (fn [_ pressed?] (reset! move-down? pressed?))1209 "key-f" (fn [_ pressed?] (reset! move-left? pressed?))1210 "key-g" (fn [_ pressed?] (reset! move-right? pressed?))1211 "key-v" (fn [_ pressed?] (reset! roll-left? pressed?))1212 "key-b" (fn [_ pressed?] (reset! roll-right? pressed?))})1214 (fn [world]1215 (enable-debug world)1216 (set-gravity world Vector3f/ZERO)1217 )1219 (fn [world _]1221 (if @move-up?1222 (.applyForce control-a1223 (Vector3f. force 0 0)1224 (Vector3f. 0 0 0)))1225 (if @move-down?1226 (.applyForce control-a1227 (Vector3f. (- force) 0 0)1228 (Vector3f. 0 0 0)))1229 (if @move-left?1230 (.applyForce control-a1231 (Vector3f. 0 force 0)1232 (Vector3f. 0 0 0)))1233 (if @move-right?1234 (.applyForce control-a1235 (Vector3f. 0 (- force) 0)1236 (Vector3f. 0 0 0)))1238 (if @roll-left?1239 (.applyForce control-a1240 (Vector3f. 0 0 force)1241 (Vector3f. 0 0 0)))1242 (if @roll-right?1243 (.applyForce control-a1244 (Vector3f. 0 0 (- force))1245 (Vector3f. 0 0 0)))1247 (if (zero? (rem (swap! timer inc) 100))1248 (.attachChild1249 (.getRootNode world)1250 (sphere 0.05 :color ColorRGBA/Yellow1251 :physical? false :position1252 (.getWorldTranslation obj-a)))))1253 )1254 ))1256 (defn transform-trianglesdsd1257 "Transform that converts each vertex in the first triangle1258 into the corresponding vertex in the second triangle."1259 [#^Triangle tri-1 #^Triangle tri-2]1260 (let [in [(.get1 tri-1)1261 (.get2 tri-1)1262 (.get3 tri-1)]1263 out [(.get1 tri-2)1264 (.get2 tri-2)1265 (.get3 tri-2)]]1266 (let [translate (doto (Matrix4f.) (.setTranslation (.negate (in 0))))1267 in* [(.mult translate (in 0))1268 (.mult translate (in 1))1269 (.mult translate (in 2))]1270 final-translation1271 (doto (Matrix4f.)1272 (.setTranslation (out 1)))1274 rotate-11275 (doto (Matrix3f.)1276 (.fromStartEndVectors1277 (.normalize1278 (.subtract1279 (in* 1) (in* 0)))1280 (.normalize1281 (.subtract1282 (out 1) (out 0)))))1283 in** [(.mult rotate-1 (in* 0))1284 (.mult rotate-1 (in* 1))1285 (.mult rotate-1 (in* 2))]1286 scale-factor-11287 (.mult1288 (.normalize1289 (.subtract1290 (out 1)1291 (out 0)))1292 (/ (.length1293 (.subtract (out 1)1294 (out 0)))1295 (.length1296 (.subtract (in** 1)1297 (in** 0)))))1298 scale-1 (doto (Matrix4f.) (.setScale scale-factor-1))1299 in*** [(.mult scale-1 (in** 0))1300 (.mult scale-1 (in** 1))1301 (.mult scale-1 (in** 2))]1307 ]1309 (dorun (map println in))1310 (println)1311 (dorun (map println in*))1312 (println)1313 (dorun (map println in**))1314 (println)1315 (dorun (map println in***))1316 (println)1318 ))))1321 (defn world-setup [joint]1322 (let [joint-position (Vector3f. 0 0 0)1323 joint-rotation1324 (.toRotationMatrix1325 (.mult1326 (doto (Quaternion.)1327 (.fromAngleAxis1328 (* 1 (/ Math/PI 4))1329 (Vector3f. -1 0 0)))1330 (doto (Quaternion.)1331 (.fromAngleAxis1332 (* 1 (/ Math/PI 2))1333 (Vector3f. 0 0 1)))))1334 top-position (.mult joint-rotation (Vector3f. 8 0 0))1336 origin (doto1337 (sphere 0.1 :physical? false :color ColorRGBA/Cyan1338 :position top-position))1339 top (doto1340 (sphere 0.1 :physical? false :color ColorRGBA/Yellow1341 :position top-position)1343 (.addControl1344 (RigidBodyControl.1345 (CapsuleCollisionShape. 0.5 1.5 1) (float 20))))1346 bottom (doto1347 (sphere 0.1 :physical? false :color ColorRGBA/DarkGray1348 :position (Vector3f. 0 0 0))1349 (.addControl1350 (RigidBodyControl.1351 (CapsuleCollisionShape. 0.5 1.5 1) (float 0))))1352 table (box 10 2 10 :position (Vector3f. 0 -20 0)1353 :color ColorRGBA/Gray :mass 0)1354 a (.getControl top RigidBodyControl)1355 b (.getControl bottom RigidBodyControl)]1357 (cond1358 (= joint :cone)1360 (doto (ConeJoint.1361 a b1362 (world-to-local top joint-position)1363 (world-to-local bottom joint-position)1364 joint-rotation1365 joint-rotation1366 )1369 (.setLimit (* (/ 10) Math/PI)1370 (* (/ 4) Math/PI)1371 0)))1372 [origin top bottom table]))1374 (defn test-joint [joint]1375 (let [[origin top bottom floor] (world-setup joint)1376 control (.getControl top RigidBodyControl)1377 move-up? (atom false)1378 move-down? (atom false)1379 move-left? (atom false)1380 move-right? (atom false)1381 roll-left? (atom false)1382 roll-right? (atom false)1383 timer (atom 0)]1385 (world1386 (nodify [top bottom floor origin])1387 (merge standard-debug-controls1388 {"key-r" (fn [_ pressed?] (reset! move-up? pressed?))1389 "key-t" (fn [_ pressed?] (reset! move-down? pressed?))1390 "key-f" (fn [_ pressed?] (reset! move-left? pressed?))1391 "key-g" (fn [_ pressed?] (reset! move-right? pressed?))1392 "key-v" (fn [_ pressed?] (reset! roll-left? pressed?))1393 "key-b" (fn [_ pressed?] (reset! roll-right? pressed?))})1395 (fn [world]1396 (light-up-everything world)1397 (enable-debug world)1398 (set-gravity world (Vector3f. 0 0 0))1399 )1401 (fn [world _]1402 (if (zero? (rem (swap! timer inc) 100))1403 (do1404 ;; (println-repl @timer)1405 (.attachChild (.getRootNode world)1406 (sphere 0.05 :color ColorRGBA/Yellow1407 :position (.getWorldTranslation top)1408 :physical? false))1409 (.attachChild (.getRootNode world)1410 (sphere 0.05 :color ColorRGBA/LightGray1411 :position (.getWorldTranslation bottom)1412 :physical? false))))1414 (if @move-up?1415 (.applyTorque control1416 (.mult (.getPhysicsRotation control)1417 (Vector3f. 0 0 10))))1418 (if @move-down?1419 (.applyTorque control1420 (.mult (.getPhysicsRotation control)1421 (Vector3f. 0 0 -10))))1422 (if @move-left?1423 (.applyTorque control1424 (.mult (.getPhysicsRotation control)1425 (Vector3f. 0 10 0))))1426 (if @move-right?1427 (.applyTorque control1428 (.mult (.getPhysicsRotation control)1429 (Vector3f. 0 -10 0))))1430 (if @roll-left?1431 (.applyTorque control1432 (.mult (.getPhysicsRotation control)1433 (Vector3f. -1 0 0))))1434 (if @roll-right?1435 (.applyTorque control1436 (.mult (.getPhysicsRotation control)1437 (Vector3f. 1 0 0))))))))1441 (defprotocol Frame1442 (frame [this]))1444 (extend-type BufferedImage1445 Frame1446 (frame [image]1447 (merge1448 (apply1449 hash-map1450 (interleave1451 (doall (for [x (range (.getWidth image)) y (range (.getHeight image))]1452 (vector x y)))1453 (doall (for [x (range (.getWidth image)) y (range (.getHeight image))]1454 (let [data (.getRGB image x y)]1455 (hash-map :r (bit-shift-right (bit-and 0xff0000 data) 16)1456 :g (bit-shift-right (bit-and 0x00ff00 data) 8)1457 :b (bit-and 0x0000ff data)))))))1458 {:width (.getWidth image) :height (.getHeight image)})))1461 (extend-type ImagePlus1462 Frame1463 (frame [image+]1464 (frame (.getBufferedImage image+))))1467 #+end_src1470 * COMMENT generate source1471 #+begin_src clojure :tangle ../src/cortex/silly.clj1472 <<body-1>>1473 #+end_src