view org/test-creature.org @ 135:421cc43441ae

cleaned up test, moved some functions
author Robert McIntyre <rlm@mit.edu>
date Wed, 01 Feb 2012 05:43:51 -0700
parents ac350a0ac6b0
children ffbab4199c0d
line wrap: on
line source
1 #+title: First attempt at a creature!
2 #+author: Robert McIntyre
3 #+email: rlm@mit.edu
4 #+description:
5 #+keywords: simulation, jMonkeyEngine3, clojure
6 #+SETUPFILE: ../../aurellem/org/setup.org
7 #+INCLUDE: ../../aurellem/org/level-0.org
11 * Brainstorming different sensors and effectors.
13 Every sense that we have should have an effector that changes what
14 that sense (or others who have that sense) experiences.
16 ** Classic Senses
17 | Sense | Effector |
18 |------------------------------+---------------------------------|
19 | Vision | Variable Coloration |
20 | Hearing | Speech |
21 | Proprioception | Movement |
22 | Smell/Taste (Chemoreception) | Pheremones |
23 | Touch | Movement / Controllable Texture |
24 | Acceleration | Movement |
25 | Balance (sense gravity) | Movement |
26 | | |
28 - New Senses/Effectors
29 - Levitation
30 - Telekenesis
32 - Symbol Sense
33 Where objects in the world can be queried for description /
34 symbols.
36 - Symbol Marking
37 The ability to mark objects in the world with your own descriptions
38 and symbols.
40 - Vision
41 Distinguish the polarization of light
42 Color
43 Movement
45 * project ideas
46 - HACKER for writing muscle-control programs : Presented with
47 low-level muscle control/ sense API, generate higher level programs
48 for accomplishing various stated goals. Example goals might be
49 "extend all your fingers" or "move your hand into the area with
50 blue light" or "decrease the angle of this joint". It would be
51 like Sussman's HACKER, except it would operate with much more data
52 in a more realistic world. Start off with "calestanthics" to
53 develop subrouitines over the motor control API. This would be the
54 "spinal chord" of a more intelligent creature. The low level
55 programming code might be a turning machine that could develop
56 programs to iterate over a "tape" where each entry in the tape
57 could control recruitment of the fibers in a muscle.
58 - Make a virtual computer in the virtual world which with which the
59 creature interacts using its fingers to press keys on a virtual
60 keyboard. The creature can access the internet, watch videos, take
61 over the world, anything it wants.
62 - Make virtual insturments like pianos, drumbs, etc that it learns to
63 play.
64 - make a joint that figures out what type of joint it is (range of
65 motion)
71 * goals
73 ** have to get done before winston
74 - [ ] write an explination for why greyscale bitmaps for senses is
75 appropiate -- 1/2 day
76 - [ ] muscle control -- day
77 - [ ] proprioception sensor map in the style of the other senses -- day
78 - [ ] refactor integration code to distribute to each of the senses
79 -- day
80 - [ ] create video showing all the senses for Winston -- 2 days
81 - [ ] write summary of project for Winston \
82 - [ ] project proposals for Winston \
83 - [ ] additional senses to be implemented for Winston | -- 2 days
84 - [ ] send Winston package /
86 ** would be cool to get done before winston
87 - [X] enable greyscale bitmaps for touch -- 2 hours
88 - [X] use sawfish to auto-tile sense windows -- 6 hours
89 - [X] sawfish keybinding to automatically delete all sense windows
90 - [ ] directly change the UV-pixels to show sensor activation -- 2
91 days
92 - [ ] proof of concept C sense manipulation -- 2 days
93 - [ ] proof of concept GPU sense manipulation -- week
94 - [ ] fourier view of sound -- 2 or 3 days
95 - [ ] dancing music generator -- 1 day, depends on fourier
97 ** don't have to get done before winston
98 - [ ] write tests for integration -- 3 days
99 - [ ] usertime/gametime clock HUD display -- day
100 - [ ] find papers for each of the senses justifying my own
101 representation -- week
102 - [ ] show sensor maps in HUD display? -- 4 days
103 - [ ] show sensor maps in AWT display? -- 2 days
106 * Intro
107 So far, I've made the following senses --
108 - Vision
109 - Hearing
110 - Touch
111 - Proprioception
113 And one effector:
114 - Movement
116 However, the code so far has only enabled these senses, but has not
117 actually implemented them. For example, there is still a lot of work
118 to be done for vision. I need to be able to create an /eyeball/ in
119 simulation that can be moved around and see the world from different
120 angles. I also need to determine weather to use log-polar or cartesian
121 for the visual input, and I need to determine how/wether to
122 disceritise the visual input.
124 I also want to be able to visualize both the sensors and the
125 effectors in pretty pictures. This semi-retarted creature will be my
126 first attempt at bringing everything together.
128 * The creature's body
130 Still going to do an eve-like body in blender, but due to problems
131 importing the joints, etc into jMonkeyEngine3, I'm going to do all
132 the connecting here in clojure code, using the names of the individual
133 components and trial and error. Later, I'll maybe make some sort of
134 creature-building modifications to blender that support whatever
135 discreitized senses I'm going to make.
137 #+name: body-1
138 #+begin_src clojure
139 (ns cortex.silly
140 "let's play!"
141 {:author "Robert McIntyre"})
143 ;; TODO remove this!
144 (require 'cortex.import)
145 (cortex.import/mega-import-jme3)
146 (use '(cortex world util body hearing touch vision))
148 (rlm.rlm-commands/help)
149 (import java.awt.image.BufferedImage)
150 (import javax.swing.JPanel)
151 (import javax.swing.SwingUtilities)
152 (import java.awt.Dimension)
153 (import javax.swing.JFrame)
154 (import java.awt.Dimension)
155 (import com.aurellem.capture.RatchetTimer)
156 (declare joint-create)
157 (use 'clojure.contrib.def)
159 (defn points->image
160 "Take a sparse collection of points and visuliaze it as a
161 BufferedImage."
163 ;; TODO maybe parallelize this since it's easy
165 [points]
166 (if (empty? points)
167 (BufferedImage. 1 1 BufferedImage/TYPE_BYTE_BINARY)
168 (let [xs (vec (map first points))
169 ys (vec (map second points))
170 x0 (apply min xs)
171 y0 (apply min ys)
172 width (- (apply max xs) x0)
173 height (- (apply max ys) y0)
174 image (BufferedImage. (inc width) (inc height)
175 BufferedImage/TYPE_INT_RGB)]
176 (dorun
177 (for [x (range (.getWidth image))
178 y (range (.getHeight image))]
179 (.setRGB image x y 0xFF0000)))
180 (dorun
181 (for [index (range (count points))]
182 (.setRGB image (- (xs index) x0) (- (ys index) y0) -1)))
184 image)))
186 (defn average [coll]
187 (/ (reduce + coll) (count coll)))
189 (defn collapse-1d
190 "One dimensional analogue of collapse"
191 [center line]
192 (let [length (count line)
193 num-above (count (filter (partial < center) line))
194 num-below (- length num-above)]
195 (range (- center num-below)
196 (+ center num-above))))
198 (defn collapse
199 "Take a set of pairs of integers and collapse them into a
200 contigous bitmap."
201 [points]
202 (if (empty? points) []
203 (let
204 [num-points (count points)
205 center (vector
206 (int (average (map first points)))
207 (int (average (map first points))))
208 flattened
209 (reduce
210 concat
211 (map
212 (fn [column]
213 (map vector
214 (map first column)
215 (collapse-1d (second center)
216 (map second column))))
217 (partition-by first (sort-by first points))))
218 squeezed
219 (reduce
220 concat
221 (map
222 (fn [row]
223 (map vector
224 (collapse-1d (first center)
225 (map first row))
226 (map second row)))
227 (partition-by second (sort-by second flattened))))
228 relocate
229 (let [min-x (apply min (map first squeezed))
230 min-y (apply min (map second squeezed))]
231 (map (fn [[x y]]
232 [(- x min-x)
233 (- y min-y)])
234 squeezed))]
235 relocate)))
237 (defn load-bullet []
238 (let [sim (world (Node.) {} no-op no-op)]
239 (doto sim
240 (.enqueue
241 (fn []
242 (.stop sim)))
243 (.start))))
245 (defn load-blender-model
246 "Load a .blend file using an asset folder relative path."
247 [^String model]
248 (.loadModel
249 (doto (asset-manager)
250 (.registerLoader BlenderModelLoader (into-array String ["blend"])))
251 model))
253 (defn meta-data [blender-node key]
254 (if-let [data (.getUserData blender-node "properties")]
255 (.findValue data key)
256 nil))
258 (defn blender-to-jme
259 "Convert from Blender coordinates to JME coordinates"
260 [#^Vector3f in]
261 (Vector3f. (.getX in)
262 (.getZ in)
263 (- (.getY in))))
269 (defn world-to-local
270 "Convert the world coordinates into coordinates relative to the
271 object (i.e. local coordinates), taking into account the rotation
272 of object."
273 [#^Spatial object world-coordinate]
274 (let [out (Vector3f.)]
275 (.worldToLocal object world-coordinate out) out))
277 (defn local-to-world
278 "Convert the local coordinates into coordinates into world relative
279 coordinates"
280 [#^Spatial object local-coordinate]
281 (let [world-coordinate (Vector3f.)]
282 (.localToWorld object local-coordinate world-coordinate)
283 world-coordinate))
285 (defmulti joint-dispatch
286 "Translate blender pseudo-joints into real JME joints."
287 (fn [constraints & _]
288 (:type constraints)))
290 (defmethod joint-dispatch :point
291 [constraints control-a control-b pivot-a pivot-b rotation]
292 (println-repl "creating POINT2POINT joint")
293 ;; bullet's point2point joints are BROKEN, so we must use the
294 ;; generic 6DOF joint instead of an actual Point2Point joint!
296 ;; should be able to do this:
297 (comment
298 (Point2PointJoint.
299 control-a
300 control-b
301 pivot-a
302 pivot-b))
304 ;; but instead we must do this:
305 (println-repl "substuting 6DOF joint for POINT2POINT joint!")
306 (doto
307 (SixDofJoint.
308 control-a
309 control-b
310 pivot-a
311 pivot-b
312 false)
313 (.setLinearLowerLimit Vector3f/ZERO)
314 (.setLinearUpperLimit Vector3f/ZERO)
315 ;;(.setAngularLowerLimit (Vector3f. 1 1 1))
316 ;;(.setAngularUpperLimit (Vector3f. 0 0 0))
318 ))
321 (defmethod joint-dispatch :hinge
322 [constraints control-a control-b pivot-a pivot-b rotation]
323 (println-repl "creating HINGE joint")
324 (let [axis
325 (if-let
326 [axis (:axis constraints)]
327 axis
328 Vector3f/UNIT_X)
329 [limit-1 limit-2] (:limit constraints)
330 hinge-axis
331 (.mult
332 rotation
333 (blender-to-jme axis))]
334 (doto
335 (HingeJoint.
336 control-a
337 control-b
338 pivot-a
339 pivot-b
340 hinge-axis
341 hinge-axis)
342 (.setLimit limit-1 limit-2))))
344 (defmethod joint-dispatch :cone
345 [constraints control-a control-b pivot-a pivot-b rotation]
346 (let [limit-xz (:limit-xz constraints)
347 limit-xy (:limit-xy constraints)
348 twist (:twist constraints)]
350 (println-repl "creating CONE joint")
351 (println-repl rotation)
352 (println-repl
353 "UNIT_X --> " (.mult rotation (Vector3f. 1 0 0)))
354 (println-repl
355 "UNIT_Y --> " (.mult rotation (Vector3f. 0 1 0)))
356 (println-repl
357 "UNIT_Z --> " (.mult rotation (Vector3f. 0 0 1)))
358 (doto
359 (ConeJoint.
360 control-a
361 control-b
362 pivot-a
363 pivot-b
364 rotation
365 rotation)
366 (.setLimit (float limit-xz)
367 (float limit-xy)
368 (float twist)))))
370 (defn connect
371 "here are some examples:
372 {:type :point}
373 {:type :hinge :limit [0 (/ Math/PI 2)] :axis (Vector3f. 0 1 0)}
374 (:axis defaults to (Vector3f. 1 0 0) if not provided for hinge joints)
376 {:type :cone :limit-xz 0]
377 :limit-xy 0]
378 :twist 0]} (use XZY rotation mode in blender!)"
379 [#^Node obj-a #^Node obj-b #^Node joint]
380 (let [control-a (.getControl obj-a RigidBodyControl)
381 control-b (.getControl obj-b RigidBodyControl)
382 joint-center (.getWorldTranslation joint)
383 joint-rotation (.toRotationMatrix (.getWorldRotation joint))
384 pivot-a (world-to-local obj-a joint-center)
385 pivot-b (world-to-local obj-b joint-center)]
387 (if-let [constraints
388 (map-vals
389 eval
390 (read-string
391 (meta-data joint "joint")))]
392 ;; A side-effect of creating a joint registers
393 ;; it with both physics objects which in turn
394 ;; will register the joint with the physics system
395 ;; when the simulation is started.
396 (do
397 (println-repl "creating joint between"
398 (.getName obj-a) "and" (.getName obj-b))
399 (joint-dispatch constraints
400 control-a control-b
401 pivot-a pivot-b
402 joint-rotation))
403 (println-repl "could not find joint meta-data!"))))
408 (defn assemble-creature [#^Node pieces joints]
409 (dorun
410 (map
411 (fn [geom]
412 (let [physics-control
413 (RigidBodyControl.
414 (HullCollisionShape.
415 (.getMesh geom))
416 (if-let [mass (meta-data geom "mass")]
417 (do
418 (println-repl
419 "setting" (.getName geom) "mass to" (float mass))
420 (float mass))
421 (float 1)))]
423 (.addControl geom physics-control)))
424 (filter #(isa? (class %) Geometry )
425 (node-seq pieces))))
426 (dorun
427 (map
428 (fn [joint]
429 (let [[obj-a obj-b] (joint-targets pieces joint)]
430 (connect obj-a obj-b joint)))
431 joints))
432 pieces)
434 (declare blender-creature)
436 (def hand "Models/creature1/one.blend")
438 (def worm "Models/creature1/try-again.blend")
440 (def touch "Models/creature1/touch.blend")
442 (defn worm-model [] (load-blender-model worm))
444 (defn x-ray [#^ColorRGBA color]
445 (doto (Material. (asset-manager)
446 "Common/MatDefs/Misc/Unshaded.j3md")
447 (.setColor "Color" color)
448 (-> (.getAdditionalRenderState)
449 (.setDepthTest false))))
451 (defn colorful []
452 (.getChild (worm-model) "worm-21"))
454 (import jme3tools.converters.ImageToAwt)
456 (import ij.ImagePlus)
458 ;; Every Mesh has many triangles, each with its own index.
459 ;; Every vertex has its own index as well.
461 (defn tactile-sensor-image
462 "Return the touch-sensor distribution image in BufferedImage format,
463 or nil if it does not exist."
464 [#^Geometry obj]
465 (if-let [image-path (meta-data obj "touch")]
466 (ImageToAwt/convert
467 (.getImage
468 (.loadTexture
469 (asset-manager)
470 image-path))
471 false false 0)))
473 (import ij.process.ImageProcessor)
474 (import java.awt.image.BufferedImage)
476 (def white -1)
478 (defn filter-pixels
479 "List the coordinates of all pixels matching pred, within the bounds
480 provided. Bounds -> [x0 y0 width height]"
481 {:author "Dylan Holmes"}
482 ([pred #^BufferedImage image]
483 (filter-pixels pred image [0 0 (.getWidth image) (.getHeight image)]))
484 ([pred #^BufferedImage image [x0 y0 width height]]
485 ((fn accumulate [x y matches]
486 (cond
487 (>= y (+ height y0)) matches
488 (>= x (+ width x0)) (recur 0 (inc y) matches)
489 (pred (.getRGB image x y))
490 (recur (inc x) y (conj matches [x y]))
491 :else (recur (inc x) y matches)))
492 x0 y0 [])))
494 (defn white-coordinates
495 "Coordinates of all the white pixels in a subset of the image."
496 ([#^BufferedImage image bounds]
497 (filter-pixels #(= % white) image bounds))
498 ([#^BufferedImage image]
499 (filter-pixels #(= % white) image)))
501 (defn triangle
502 "Get the triangle specified by triangle-index from the mesh within
503 bounds."
504 [#^Mesh mesh triangle-index]
505 (let [scratch (Triangle.)]
506 (.getTriangle mesh triangle-index scratch)
507 scratch))
509 (defn triangle-vertex-indices
510 "Get the triangle vertex indices of a given triangle from a given
511 mesh."
512 [#^Mesh mesh triangle-index]
513 (let [indices (int-array 3)]
514 (.getTriangle mesh triangle-index indices)
515 (vec indices)))
517 (defn vertex-UV-coord
518 "Get the uv-coordinates of the vertex named by vertex-index"
519 [#^Mesh mesh vertex-index]
520 (let [UV-buffer
521 (.getData
522 (.getBuffer
523 mesh
524 VertexBuffer$Type/TexCoord))]
525 [(.get UV-buffer (* vertex-index 2))
526 (.get UV-buffer (+ 1 (* vertex-index 2)))]))
528 (defn triangle-UV-coord
529 "Get the uv-cooridnates of the triangle's verticies."
530 [#^Mesh mesh width height triangle-index]
531 (map (fn [[u v]] (vector (* width u) (* height v)))
532 (map (partial vertex-UV-coord mesh)
533 (triangle-vertex-indices mesh triangle-index))))
535 (defn same-side?
536 "Given the points p1 and p2 and the reference point ref, is point p
537 on the same side of the line that goes through p1 and p2 as ref is?"
538 [p1 p2 ref p]
539 (<=
540 0
541 (.dot
542 (.cross (.subtract p2 p1) (.subtract p p1))
543 (.cross (.subtract p2 p1) (.subtract ref p1)))))
545 (defn triangle-seq [#^Triangle tri]
546 [(.get1 tri) (.get2 tri) (.get3 tri)])
548 (defn vector3f-seq [#^Vector3f v]
549 [(.getX v) (.getY v) (.getZ v)])
551 (defn inside-triangle?
552 "Is the point inside the triangle?"
553 {:author "Dylan Holmes"}
554 [#^Triangle tri #^Vector3f p]
555 (let [[vert-1 vert-2 vert-3] (triangle-seq tri)]
556 (and
557 (same-side? vert-1 vert-2 vert-3 p)
558 (same-side? vert-2 vert-3 vert-1 p)
559 (same-side? vert-3 vert-1 vert-2 p))))
561 (defn triangle->matrix4f
562 "Converts the triangle into a 4x4 matrix: The first three columns
563 contain the vertices of the triangle; the last contains the unit
564 normal of the triangle. The bottom row is filled with 1s."
565 [#^Triangle t]
566 (let [mat (Matrix4f.)
567 [vert-1 vert-2 vert-3]
568 ((comp vec map) #(.get t %) (range 3))
569 unit-normal (do (.calculateNormal t)(.getNormal t))
570 vertices [vert-1 vert-2 vert-3 unit-normal]]
571 (dorun
572 (for [row (range 4) col (range 3)]
573 (do
574 (.set mat col row (.get (vertices row)col))
575 (.set mat 3 row 1))))
576 mat))
578 (defn triangle-transformation
579 "Returns the affine transformation that converts each vertex in the
580 first triangle into the corresponding vertex in the second
581 triangle."
582 [#^Triangle tri-1 #^Triangle tri-2]
583 (.mult
584 (triangle->matrix4f tri-2)
585 (.invert (triangle->matrix4f tri-1))))
587 (defn point->vector2f [[u v]]
588 (Vector2f. u v))
590 (defn vector2f->vector3f [v]
591 (Vector3f. (.getX v) (.getY v) 0))
593 (defn map-triangle [f #^Triangle tri]
594 (Triangle.
595 (f 0 (.get1 tri))
596 (f 1 (.get2 tri))
597 (f 2 (.get3 tri))))
599 (defn points->triangle
600 "Convert a list of points into a triangle."
601 [points]
602 (apply #(Triangle. %1 %2 %3)
603 (map (fn [point]
604 (let [point (vec point)]
605 (Vector3f. (get point 0 0)
606 (get point 1 0)
607 (get point 2 0))))
608 (take 3 points))))
610 (defn convex-bounds
611 ;;dylan
612 "Returns the smallest square containing the given
613 vertices, as a vector of integers [left top width height]."
614 ;; "Dimensions of the smallest integer bounding square of the list of
615 ;; 2D verticies in the form: [x y width height]."
616 [uv-verts]
617 (let [xs (map first uv-verts)
618 ys (map second uv-verts)
619 x0 (Math/floor (apply min xs))
620 y0 (Math/floor (apply min ys))
621 x1 (Math/ceil (apply max xs))
622 y1 (Math/ceil (apply max ys))]
623 [x0 y0 (- x1 x0) (- y1 y0)]))
625 (defn sensors-in-triangle
626 ;;dylan
627 "Locate the touch sensors in the triangle, returning a map of their UV and geometry-relative coordinates."
628 ;;"Find the locations of the touch sensors within a triangle in both
629 ;; UV and gemoetry relative coordinates."
630 [image mesh tri-index]
631 (let [width (.getWidth image)
632 height (.getHeight image)
633 UV-vertex-coords (triangle-UV-coord mesh width height tri-index)
634 bounds (convex-bounds UV-vertex-coords)
636 cutout-triangle (points->triangle UV-vertex-coords)
637 UV-sensor-coords
638 (filter (comp (partial inside-triangle? cutout-triangle)
639 (fn [[u v]] (Vector3f. u v 0)))
640 (white-coordinates image bounds))
641 UV->geometry (triangle-transformation
642 cutout-triangle
643 (triangle mesh tri-index))
644 geometry-sensor-coords
645 (map (fn [[u v]] (.mult UV->geometry (Vector3f. u v 0)))
646 UV-sensor-coords)]
647 {:UV UV-sensor-coords :geometry geometry-sensor-coords}))
649 (defn-memo locate-feelers
650 "Search the geometry's tactile UV image for touch sensors, returning
651 their positions in geometry-relative coordinates."
652 [#^Geometry geo]
653 (let [mesh (.getMesh geo)
654 num-triangles (.getTriangleCount mesh)]
655 (if-let [image (tactile-sensor-image geo)]
656 (map
657 (partial sensors-in-triangle image mesh)
658 (range num-triangles))
659 (repeat (.getTriangleCount mesh) {:UV nil :geometry nil}))))
661 (use 'clojure.contrib.def)
663 (defn-memo touch-topology [#^Gemoetry geo]
664 (vec (collapse (reduce concat (map :UV (locate-feelers geo))))))
666 (defn-memo feeler-coordinates [#^Geometry geo]
667 (vec (map :geometry (locate-feelers geo))))
669 (defn enable-touch [#^Geometry geo]
670 (let [feeler-coords (feeler-coordinates geo)
671 tris (triangles geo)
672 limit 0.1
673 ;;results (CollisionResults.)
674 ]
675 (if (empty? (touch-topology geo))
676 nil
677 (fn [node]
678 (let [sensor-origins
679 (map
680 #(map (partial local-to-world geo) %)
681 feeler-coords)
682 triangle-normals
683 (map (partial get-ray-direction geo)
684 tris)
685 rays
686 (flatten
687 (map (fn [origins norm]
688 (map #(doto (Ray. % norm)
689 (.setLimit limit)) origins))
690 sensor-origins triangle-normals))]
691 (vector
692 (touch-topology geo)
693 (vec
694 (for [ray rays]
695 (do
696 (let [results (CollisionResults.)]
697 (.collideWith node ray results)
698 (let [touch-objects
699 (filter #(not (= geo (.getGeometry %)))
700 results)]
701 (- 255
702 (if (empty? touch-objects) 255
703 (rem
704 (int
705 (* 255 (/ (.getDistance
706 (first touch-objects)) limit)))
707 256))))))))))))))
710 (defn touch [#^Node pieces]
711 (filter (comp not nil?)
712 (map enable-touch
713 (filter #(isa? (class %) Geometry)
714 (node-seq pieces)))))
717 ;; human eye transmits 62kb/s to brain Bandwidth is 8.75 Mb/s
718 ;; http://en.wikipedia.org/wiki/Retina
720 (defn test-eye []
721 (.getChild
722 (.getChild (worm-model) "eyes")
723 "eye"))
726 (defn retina-sensor-image
727 "Return a map of pixel selection functions to BufferedImages
728 describing the distribution of light-sensitive components on this
729 geometry's surface. Each function creates an integer from the rgb
730 values found in the pixel. :red, :green, :blue, :gray are already
731 defined as extracting the red green blue and average components
732 respectively."
733 [#^Spatial eye]
734 (if-let [eye-map (meta-data eye "eye")]
735 (map-vals
736 #(ImageToAwt/convert
737 (.getImage (.loadTexture (asset-manager) %))
738 false false 0)
739 (eval (read-string eye-map)))))
741 (defn eye-dimensions
742 "returns the width and height specified in the metadata of the eye"
743 [#^Spatial eye]
744 (let [dimensions
745 (map #(vector (.getWidth %) (.getHeight %))
746 (vals (retina-sensor-image eye)))]
747 [(apply max (map first dimensions))
748 (apply max (map second dimensions))]))
750 (defn creature-eyes
751 ;;dylan
752 "Return the children of the creature's \"eyes\" node."
753 ;;"The eye nodes which are children of the \"eyes\" node in the
754 ;;creature."
755 [#^Node creature]
756 (if-let [eye-node (.getChild creature "eyes")]
757 (seq (.getChildren eye-node))
758 (do (println-repl "could not find eyes node") [])))
760 ;; Here's how vision will work.
762 ;; Make the continuation in scene-processor take FrameBuffer,
763 ;; byte-buffer, BufferedImage already sized to the correct
764 ;; dimensions. the continuation will decide wether to "mix" them
765 ;; into the BufferedImage, lazily ignore them, or mix them halfway
766 ;; and call c/graphics card routines.
768 ;; (vision creature) will take an optional :skip argument which will
769 ;; inform the continuations in scene processor to skip the given
770 ;; number of cycles; 0 means that no cycles will be skipped.
772 ;; (vision creature) will return [init-functions sensor-functions].
773 ;; The init-functions are each single-arg functions that take the
774 ;; world and register the cameras and must each be called before the
775 ;; corresponding sensor-functions. Each init-function returns the
776 ;; viewport for that eye which can be manipulated, saved, etc. Each
777 ;; sensor-function is a thunk and will return data in the same
778 ;; format as the tactile-sensor functions; the structure is
779 ;; [topology, sensor-data]. Internally, these sensor-functions
780 ;; maintain a reference to sensor-data which is periodically updated
781 ;; by the continuation function established by its init-function.
782 ;; They can be queried every cycle, but their information may not
783 ;; necessairly be different every cycle.
785 ;; Each eye in the creature in blender will work the same way as
786 ;; joints -- a zero dimensional object with no geometry whose local
787 ;; coordinate system determines the orientation of the resulting
788 ;; eye. All eyes will have a parent named "eyes" just as all joints
789 ;; have a parent named "joints". The resulting camera will be a
790 ;; ChaseCamera or a CameraNode bound to the geo that is closest to
791 ;; the eye marker. The eye marker will contain the metadata for the
792 ;; eye, and will be moved by it's bound geometry. The dimensions of
793 ;; the eye's camera are equal to the dimensions of the eye's "UV"
794 ;; map.
797 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
799 ;; Ears work the same way as vision.
801 ;; (hearing creature) will return [init-functions
802 ;; sensor-functions]. The init functions each take the world and
803 ;; register a SoundProcessor that does foureier transforms on the
804 ;; incommong sound data, making it available to each sensor function.
806 (defn creature-ears
807 "Return the children of the creature's \"ears\" node."
808 ;;dylan
809 ;;"The ear nodes which are children of the \"ears\" node in the
810 ;;creature."
811 [#^Node creature]
812 (if-let [ear-node (.getChild creature "ears")]
813 (seq (.getChildren ear-node))
814 (do (println-repl "could not find ears node") [])))
816 (defn closest-node
817 "Return the object in creature which is closest to the given node."
818 ;;dylan"The closest object in creature to the given node."
819 [#^Node creature #^Node eye]
820 (loop [radius (float 0.01)]
821 (let [results (CollisionResults.)]
822 (.collideWith
823 creature
824 (BoundingBox. (.getWorldTranslation eye)
825 radius radius radius)
826 results)
827 (if-let [target (first results)]
828 (.getGeometry target)
829 (recur (float (* 2 radius)))))))
831 ;;dylan (defn follow-sense, adjoin-sense, attach-stimuli,
832 ;;anchor-qualia, augment-organ, with-organ
833 (defn bind-sense
834 "Bind the sense to the Spatial such that it will maintain its
835 current position relative to the Spatial no matter how the spatial
836 moves. 'sense can be either a Camera or Listener object."
837 [#^Spatial obj sense]
838 (let [sense-offset (.subtract (.getLocation sense)
839 (.getWorldTranslation obj))
840 initial-sense-rotation (Quaternion. (.getRotation sense))
841 base-anti-rotation (.inverse (.getWorldRotation obj))]
842 (.addControl
843 obj
844 (proxy [AbstractControl] []
845 (controlUpdate [tpf]
846 (let [total-rotation
847 (.mult base-anti-rotation (.getWorldRotation obj))]
848 (.setLocation sense
849 (.add
850 (.mult total-rotation sense-offset)
851 (.getWorldTranslation obj)))
852 (.setRotation sense
853 (.mult total-rotation initial-sense-rotation))))
854 (controlRender [_ _])))))
857 (defn update-listener-velocity
858 "Update the listener's velocity every update loop."
859 [#^Spatial obj #^Listener lis]
860 (let [old-position (atom (.getLocation lis))]
861 (.addControl
862 obj
863 (proxy [AbstractControl] []
864 (controlUpdate [tpf]
865 (let [new-position (.getLocation lis)]
866 (.setVelocity
867 lis
868 (.mult (.subtract new-position @old-position)
869 (float (/ tpf))))
870 (reset! old-position new-position)))
871 (controlRender [_ _])))))
873 (import com.aurellem.capture.audio.AudioSendRenderer)
875 (defn attach-ear
876 [#^Application world #^Node creature #^Spatial ear continuation]
877 (let [target (closest-node creature ear)
878 lis (Listener.)
879 audio-renderer (.getAudioRenderer world)
880 sp (sound-processor continuation)]
881 (.setLocation lis (.getWorldTranslation ear))
882 (.setRotation lis (.getWorldRotation ear))
883 (bind-sense target lis)
884 (update-listener-velocity target lis)
885 (.addListener audio-renderer lis)
886 (.registerSoundProcessor audio-renderer lis sp)))
888 (defn enable-hearing
889 [#^Node creature #^Spatial ear]
890 (let [hearing-data (atom [])]
891 [(fn [world]
892 (attach-ear world creature ear
893 (fn [data]
894 (reset! hearing-data (vec data)))))
895 [(fn []
896 (let [data @hearing-data
897 topology
898 (vec (map #(vector % 0) (range 0 (count data))))
899 scaled-data
900 (vec
901 (map
902 #(rem (int (* 255 (/ (+ 1 %) 2))) 256)
903 data))]
904 [topology scaled-data]))
905 ]]))
907 (defn hearing
908 [#^Node creature]
909 (reduce
910 (fn [[init-a senses-a]
911 [init-b senses-b]]
912 [(conj init-a init-b)
913 (into senses-a senses-b)])
914 [[][]]
915 (for [ear (creature-ears creature)]
916 (enable-hearing creature ear))))
918 (defn attach-eye
919 "Attach a Camera to the appropiate area and return the Camera."
920 [#^Node creature #^Spatial eye]
921 (let [target (closest-node creature eye)
922 [cam-width cam-height] (eye-dimensions eye)
923 cam (Camera. cam-width cam-height)]
924 (.setLocation cam (.getWorldTranslation eye))
925 (.setRotation cam (.getWorldRotation eye))
926 (.setFrustumPerspective
927 cam 45 (/ (.getWidth cam) (.getHeight cam))
928 1 1000)
929 (bind-sense target cam)
930 cam))
932 (def presets
933 {:all 0xFFFFFF
934 :red 0xFF0000
935 :blue 0x0000FF
936 :green 0x00FF00})
938 (defn enable-vision
939 "return [init-function sensor-functions] for a particular eye"
940 [#^Node creature #^Spatial eye & {skip :skip :or {skip 0}}]
941 (let [retinal-map (retina-sensor-image eye)
942 camera (attach-eye creature eye)
943 vision-image
944 (atom
945 (BufferedImage. (.getWidth camera)
946 (.getHeight camera)
947 BufferedImage/TYPE_BYTE_BINARY))]
948 [(fn [world]
949 (add-eye
950 world camera
951 (let [counter (atom 0)]
952 (fn [r fb bb bi]
953 (if (zero? (rem (swap! counter inc) (inc skip)))
954 (reset! vision-image (BufferedImage! r fb bb bi)))))))
955 (vec
956 (map
957 (fn [[key image]]
958 (let [whites (white-coordinates image)
959 topology (vec (collapse whites))
960 mask (presets key)]
961 (fn []
962 (vector
963 topology
964 (vec
965 (for [[x y] whites]
966 (bit-and
967 mask (.getRGB @vision-image x y))))))))
968 retinal-map))]))
970 (defn vision
971 [#^Node creature & {skip :skip :or {skip 0}}]
972 (reduce
973 (fn [[init-a senses-a]
974 [init-b senses-b]]
975 [(conj init-a init-b)
976 (into senses-a senses-b)])
977 [[][]]
978 (for [eye (creature-eyes creature)]
979 (enable-vision creature eye))))
985 ;; lower level --- nodes
986 ;; closest-node "parse/compile-x" -> makes organ, which is spatial, fn pair
988 ;; higher level -- organs
989 ;;
991 ;; higher level --- sense/effector
992 ;; these are the functions that provide world i/o, chinese-room style
997 (defn blender-creature
998 "Return a creature with all joints in place."
999 [blender-path]
1000 (let [model (load-blender-model blender-path)
1001 joints (creature-joints model)]
1002 (assemble-creature model joints)))
1004 (defn gray-scale [num]
1005 (+ num
1006 (bit-shift-left num 8)
1007 (bit-shift-left num 16)))
1009 (defn debug-touch-window
1010 "creates function that offers a debug view of sensor data"
1011 []
1012 (let [vi (view-image)]
1013 (fn
1014 [[coords sensor-data]]
1015 (let [image (points->image coords)]
1016 (dorun
1017 (for [i (range (count coords))]
1018 (.setRGB image ((coords i) 0) ((coords i) 1)
1019 (gray-scale (sensor-data i)))))
1022 (vi image)))))
1024 (defn debug-vision-window
1025 "creates function that offers a debug view of sensor data"
1026 []
1027 (let [vi (view-image)]
1028 (fn
1029 [[coords sensor-data]]
1030 (let [image (points->image coords)]
1031 (dorun
1032 (for [i (range (count coords))]
1033 (.setRGB image ((coords i) 0) ((coords i) 1)
1034 (sensor-data i))))
1035 (vi image)))))
1037 (defn debug-hearing-window
1038 "view audio data"
1039 [height]
1040 (let [vi (view-image)]
1041 (fn [[coords sensor-data]]
1042 (let [image (BufferedImage. (count coords) height
1043 BufferedImage/TYPE_INT_RGB)]
1044 (dorun
1045 (for [x (range (count coords))]
1046 (dorun
1047 (for [y (range height)]
1048 (let [raw-sensor (sensor-data x)]
1049 (.setRGB image x y (gray-scale raw-sensor)))))))
1051 (vi image)))))
1055 ;;(defn test-touch [world creature]
1060 ;; here's how motor-control/ proprioception will work: Each muscle is
1061 ;; defined by a 1-D array of numbers (the "motor pool") each of which
1062 ;; represent muscle fibers. A muscle also has a scalar :strength
1063 ;; factor which determines how strong the muscle as a whole is.
1064 ;; The effector function for a muscle takes a number < (count
1065 ;; motor-pool) and that number is said to "activate" all the muscle
1066 ;; fibers whose index is lower than the number. Each fiber will apply
1067 ;; force in proportion to its value in the array. Lower values cause
1068 ;; less force. The lower values can be put at the "beginning" of the
1069 ;; 1-D array to simulate the layout of actual human muscles, which are
1070 ;; capable of more percise movements when exerting less force.
1072 ;; I don't know how to encode proprioception, so for now, just return
1073 ;; a function for each joint that returns a triplet of floats which
1074 ;; represent relative roll, pitch, and yaw. Write display code for
1075 ;; this though.
1077 (defn muscle-fibre-values
1078 "Take the first row of the image and return the low-order bytes."
1079 [#^BufferedImage image]
1080 (let [width (.getWidth image)]
1081 (for [x (range width)]
1082 (bit-and
1083 0xFF
1084 (.getRGB image x 0)))))
1087 (defn draw-sprite [image sprite x y color ]
1088 (dorun
1089 (for [[u v] sprite]
1090 (.setRGB image (+ u x) (+ v y) color))))
1092 (defn view-angle
1093 "create a debug view of an angle"
1094 [color]
1095 (let [image (BufferedImage. 50 50 BufferedImage/TYPE_INT_RGB)
1096 previous (atom [25 25])
1097 sprite [[0 0] [0 1]
1098 [0 -1] [-1 0] [1 0]]]
1099 (fn [angle]
1100 (let [angle (float angle)]
1101 (let [position
1102 [(+ 25 (int (* 20 (Math/cos angle))))
1103 (+ 25 (int (* 20(Math/sin angle))))]]
1104 (draw-sprite image sprite (@previous 0) (@previous 1) 0x000000)
1105 (draw-sprite image sprite (position 0) (position 1) color)
1106 (reset! previous position))
1107 image))))
1109 (defn proprioception-debug-window
1110 []
1111 (let [yaw (view-angle 0xFF0000)
1112 roll (view-angle 0x00FF00)
1113 pitch (view-angle 0xFFFFFF)
1114 v-yaw (view-image)
1115 v-roll (view-image)
1116 v-pitch (view-image)
1118 (fn [prop-data]
1119 (dorun
1120 (map
1121 (fn [[y r p]]
1122 (v-yaw (yaw y))
1123 (v-roll (roll r))
1124 (v-pitch (pitch p)))
1125 prop-data)))))
1133 (defn test-creature [thing]
1134 (let [x-axis
1135 (box 1 0.01 0.01 :physical? false :color ColorRGBA/Red)
1136 y-axis
1137 (box 0.01 1 0.01 :physical? false :color ColorRGBA/Green)
1138 z-axis
1139 (box 0.01 0.01 1 :physical? false :color ColorRGBA/Blue)
1140 creature (blender-creature thing)
1141 touch-nerves (touch creature)
1142 touch-debug-windows (map (fn [_] (debug-touch-window)) touch-nerves)
1143 [init-vision-fns vision-data] (vision creature)
1144 vision-debug (map (fn [_] (debug-vision-window)) vision-data)
1145 me (sphere 0.5 :color ColorRGBA/Blue :physical? false)
1146 [init-hearing-fns hearing-senses] (hearing creature)
1147 hearing-windows (map (fn [_] (debug-hearing-window 50))
1148 hearing-senses)
1149 bell (AudioNode. (asset-manager)
1150 "Sounds/pure.wav" false)
1151 prop (proprioception creature)
1152 prop-debug (proprioception-debug-window)
1153 ;; dream
1156 (world
1157 (nodify [creature
1158 (box 10 2 10 :position (Vector3f. 0 -9 0)
1159 :color ColorRGBA/Gray :mass 0)
1160 x-axis y-axis z-axis
1161 me
1162 ])
1163 (merge standard-debug-controls
1164 {"key-return"
1165 (fn [_ value]
1166 (if value
1167 (do
1168 (println-repl "play-sound")
1169 (.play bell))))})
1170 (fn [world]
1171 (light-up-everything world)
1172 (enable-debug world)
1173 (dorun (map #(% world) init-vision-fns))
1174 (dorun (map #(% world) init-hearing-fns))
1176 (add-eye world
1177 (attach-eye creature (test-eye))
1178 (comp (view-image) BufferedImage!))
1180 (add-eye world (.getCamera world) no-op)
1181 ;;(set-gravity world (Vector3f. 0 0 0))
1182 ;;(com.aurellem.capture.Capture/captureVideo
1183 ;; world (file-str "/home/r/proj/ai-videos/hand"))
1184 ;;(.setTimer world (RatchetTimer. 60))
1185 (speed-up world)
1186 ;;(set-gravity world (Vector3f. 0 0 0))
1188 (fn [world tpf]
1189 ;;(dorun
1190 ;; (map #(%1 %2) touch-nerves (repeat (.getRootNode world))))
1192 (prop-debug (prop))
1194 (dorun
1195 (map #(%1 (%2 (.getRootNode world)))
1196 touch-debug-windows touch-nerves))
1198 (dorun
1199 (map #(%1 (%2))
1200 vision-debug vision-data))
1201 (dorun
1202 (map #(%1 (%2)) hearing-windows hearing-senses))
1205 ;;(println-repl (vision-data))
1206 (.setLocalTranslation me (.getLocation (.getCamera world)))
1210 ;;(let [timer (atom 0)]
1211 ;; (fn [_ _]
1212 ;; (swap! timer inc)
1213 ;; (if (= (rem @timer 60) 0)
1214 ;; (println-repl (float (/ @timer 60))))))
1215 )))
1225 ;;; experiments in collisions
1229 (defn collision-test []
1230 (let [b-radius 1
1231 b-position (Vector3f. 0 0 0)
1232 obj-b (box 1 1 1 :color ColorRGBA/Blue
1233 :position b-position
1234 :mass 0)
1235 node (nodify [obj-b])
1236 bounds-b
1237 (doto (Picture.)
1238 (.setHeight 50)
1239 (.setWidth 50)
1240 (.setImage (asset-manager)
1241 "Models/creature1/hand.png"
1242 false
1243 ))
1245 ;;(Ray. (Vector3f. 0 -5 0) (.normalize (Vector3f. 0 1 0)))
1247 collisions
1248 (let [cr (CollisionResults.)]
1249 (.collideWith node bounds-b cr)
1250 (println (map #(.getContactPoint %) cr))
1251 cr)
1253 ;;collision-points
1254 ;;(map #(sphere 0.1 :position (.getContactPoint %))
1255 ;; collisions)
1257 ;;node (nodify (conj collision-points obj-b))
1259 sim
1260 (world node
1261 {"key-space"
1262 (fn [_ value]
1263 (if value
1264 (let [cr (CollisionResults.)]
1265 (.collideWith node bounds-b cr)
1266 (println-repl (map #(.getContactPoint %) cr))
1267 cr)))}
1268 no-op
1269 no-op)
1272 sim
1274 ))
1277 ;; the camera will stay in its initial position/rotation with relation
1278 ;; to the spatial.
1281 (defn follow-test
1282 "show a camera that stays in the same relative position to a blue cube."
1283 []
1284 (let [camera-pos (Vector3f. 0 30 0)
1285 rock (box 1 1 1 :color ColorRGBA/Blue
1286 :position (Vector3f. 0 10 0)
1287 :mass 30
1289 rot (.getWorldRotation rock)
1291 table (box 3 1 10 :color ColorRGBA/Gray :mass 0
1292 :position (Vector3f. 0 -3 0))]
1294 (world
1295 (nodify [rock table])
1296 standard-debug-controls
1297 (fn [world]
1298 (let
1299 [cam (doto (.clone (.getCamera world))
1300 (.setLocation camera-pos)
1301 (.lookAt Vector3f/ZERO
1302 Vector3f/UNIT_X))]
1303 (bind-sense rock cam)
1305 (.setTimer world (RatchetTimer. 60))
1306 (add-eye world cam (comp (view-image) BufferedImage!))
1307 (add-eye world (.getCamera world) no-op))
1309 (fn [_ _] (println-repl rot)))))
1313 #+end_src
1315 #+results: body-1
1316 : #'cortex.silly/follow-test
1319 * COMMENT purgatory
1320 #+begin_src clojure
1321 (defn bullet-trans []
1322 (let [obj-a (sphere 0.5 :color ColorRGBA/Red
1323 :position (Vector3f. -10 5 0))
1324 obj-b (sphere 0.5 :color ColorRGBA/Blue
1325 :position (Vector3f. -10 -5 0)
1326 :mass 0)
1327 control-a (.getControl obj-a RigidBodyControl)
1328 control-b (.getControl obj-b RigidBodyControl)
1329 swivel
1330 (.toRotationMatrix
1331 (doto (Quaternion.)
1332 (.fromAngleAxis (/ Math/PI 2)
1333 Vector3f/UNIT_X)))]
1334 (doto
1335 (ConeJoint.
1336 control-a control-b
1337 (Vector3f. 0 5 0)
1338 (Vector3f. 0 -5 0)
1339 swivel swivel)
1340 (.setLimit (* 0.6 (/ Math/PI 4))
1341 (/ Math/PI 4)
1342 (* Math/PI 0.8)))
1343 (world (nodify
1344 [obj-a obj-b])
1345 standard-debug-controls
1346 enable-debug
1347 no-op)))
1350 (defn bullet-trans* []
1351 (let [obj-a (box 1.5 0.5 0.5 :color ColorRGBA/Red
1352 :position (Vector3f. 5 0 0)
1353 :mass 90)
1354 obj-b (sphere 0.5 :color ColorRGBA/Blue
1355 :position (Vector3f. -5 0 0)
1356 :mass 0)
1357 control-a (.getControl obj-a RigidBodyControl)
1358 control-b (.getControl obj-b RigidBodyControl)
1359 move-up? (atom nil)
1360 move-down? (atom nil)
1361 move-left? (atom nil)
1362 move-right? (atom nil)
1363 roll-left? (atom nil)
1364 roll-right? (atom nil)
1365 force 100
1366 swivel
1367 (.toRotationMatrix
1368 (doto (Quaternion.)
1369 (.fromAngleAxis (/ Math/PI 2)
1370 Vector3f/UNIT_X)))
1371 x-move
1372 (doto (Matrix3f.)
1373 (.fromStartEndVectors Vector3f/UNIT_X
1374 (.normalize (Vector3f. 1 1 0))))
1376 timer (atom 0)]
1377 (doto
1378 (ConeJoint.
1379 control-a control-b
1380 (Vector3f. -8 0 0)
1381 (Vector3f. 2 0 0)
1382 ;;swivel swivel
1383 ;;Matrix3f/IDENTITY Matrix3f/IDENTITY
1384 x-move Matrix3f/IDENTITY
1386 (.setCollisionBetweenLinkedBodys false)
1387 (.setLimit (* 1 (/ Math/PI 4)) ;; twist
1388 (* 1 (/ Math/PI 4)) ;; swing span in X-Y plane
1389 (* 0 (/ Math/PI 4)))) ;; swing span in Y-Z plane
1390 (world (nodify
1391 [obj-a obj-b])
1392 (merge standard-debug-controls
1393 {"key-r" (fn [_ pressed?] (reset! move-up? pressed?))
1394 "key-t" (fn [_ pressed?] (reset! move-down? pressed?))
1395 "key-f" (fn [_ pressed?] (reset! move-left? pressed?))
1396 "key-g" (fn [_ pressed?] (reset! move-right? pressed?))
1397 "key-v" (fn [_ pressed?] (reset! roll-left? pressed?))
1398 "key-b" (fn [_ pressed?] (reset! roll-right? pressed?))})
1400 (fn [world]
1401 (enable-debug world)
1402 (set-gravity world Vector3f/ZERO)
1405 (fn [world _]
1407 (if @move-up?
1408 (.applyForce control-a
1409 (Vector3f. force 0 0)
1410 (Vector3f. 0 0 0)))
1411 (if @move-down?
1412 (.applyForce control-a
1413 (Vector3f. (- force) 0 0)
1414 (Vector3f. 0 0 0)))
1415 (if @move-left?
1416 (.applyForce control-a
1417 (Vector3f. 0 force 0)
1418 (Vector3f. 0 0 0)))
1419 (if @move-right?
1420 (.applyForce control-a
1421 (Vector3f. 0 (- force) 0)
1422 (Vector3f. 0 0 0)))
1424 (if @roll-left?
1425 (.applyForce control-a
1426 (Vector3f. 0 0 force)
1427 (Vector3f. 0 0 0)))
1428 (if @roll-right?
1429 (.applyForce control-a
1430 (Vector3f. 0 0 (- force))
1431 (Vector3f. 0 0 0)))
1433 (if (zero? (rem (swap! timer inc) 100))
1434 (.attachChild
1435 (.getRootNode world)
1436 (sphere 0.05 :color ColorRGBA/Yellow
1437 :physical? false :position
1438 (.getWorldTranslation obj-a)))))
1440 ))
1442 (defn transform-trianglesdsd
1443 "Transform that converts each vertex in the first triangle
1444 into the corresponding vertex in the second triangle."
1445 [#^Triangle tri-1 #^Triangle tri-2]
1446 (let [in [(.get1 tri-1)
1447 (.get2 tri-1)
1448 (.get3 tri-1)]
1449 out [(.get1 tri-2)
1450 (.get2 tri-2)
1451 (.get3 tri-2)]]
1452 (let [translate (doto (Matrix4f.) (.setTranslation (.negate (in 0))))
1453 in* [(.mult translate (in 0))
1454 (.mult translate (in 1))
1455 (.mult translate (in 2))]
1456 final-translation
1457 (doto (Matrix4f.)
1458 (.setTranslation (out 1)))
1460 rotate-1
1461 (doto (Matrix3f.)
1462 (.fromStartEndVectors
1463 (.normalize
1464 (.subtract
1465 (in* 1) (in* 0)))
1466 (.normalize
1467 (.subtract
1468 (out 1) (out 0)))))
1469 in** [(.mult rotate-1 (in* 0))
1470 (.mult rotate-1 (in* 1))
1471 (.mult rotate-1 (in* 2))]
1472 scale-factor-1
1473 (.mult
1474 (.normalize
1475 (.subtract
1476 (out 1)
1477 (out 0)))
1478 (/ (.length
1479 (.subtract (out 1)
1480 (out 0)))
1481 (.length
1482 (.subtract (in** 1)
1483 (in** 0)))))
1484 scale-1 (doto (Matrix4f.) (.setScale scale-factor-1))
1485 in*** [(.mult scale-1 (in** 0))
1486 (.mult scale-1 (in** 1))
1487 (.mult scale-1 (in** 2))]
1495 (dorun (map println in))
1496 (println)
1497 (dorun (map println in*))
1498 (println)
1499 (dorun (map println in**))
1500 (println)
1501 (dorun (map println in***))
1502 (println)
1504 ))))
1507 (defn world-setup [joint]
1508 (let [joint-position (Vector3f. 0 0 0)
1509 joint-rotation
1510 (.toRotationMatrix
1511 (.mult
1512 (doto (Quaternion.)
1513 (.fromAngleAxis
1514 (* 1 (/ Math/PI 4))
1515 (Vector3f. -1 0 0)))
1516 (doto (Quaternion.)
1517 (.fromAngleAxis
1518 (* 1 (/ Math/PI 2))
1519 (Vector3f. 0 0 1)))))
1520 top-position (.mult joint-rotation (Vector3f. 8 0 0))
1522 origin (doto
1523 (sphere 0.1 :physical? false :color ColorRGBA/Cyan
1524 :position top-position))
1525 top (doto
1526 (sphere 0.1 :physical? false :color ColorRGBA/Yellow
1527 :position top-position)
1529 (.addControl
1530 (RigidBodyControl.
1531 (CapsuleCollisionShape. 0.5 1.5 1) (float 20))))
1532 bottom (doto
1533 (sphere 0.1 :physical? false :color ColorRGBA/DarkGray
1534 :position (Vector3f. 0 0 0))
1535 (.addControl
1536 (RigidBodyControl.
1537 (CapsuleCollisionShape. 0.5 1.5 1) (float 0))))
1538 table (box 10 2 10 :position (Vector3f. 0 -20 0)
1539 :color ColorRGBA/Gray :mass 0)
1540 a (.getControl top RigidBodyControl)
1541 b (.getControl bottom RigidBodyControl)]
1543 (cond
1544 (= joint :cone)
1546 (doto (ConeJoint.
1547 a b
1548 (world-to-local top joint-position)
1549 (world-to-local bottom joint-position)
1550 joint-rotation
1551 joint-rotation
1555 (.setLimit (* (/ 10) Math/PI)
1556 (* (/ 4) Math/PI)
1557 0)))
1558 [origin top bottom table]))
1560 (defn test-joint [joint]
1561 (let [[origin top bottom floor] (world-setup joint)
1562 control (.getControl top RigidBodyControl)
1563 move-up? (atom false)
1564 move-down? (atom false)
1565 move-left? (atom false)
1566 move-right? (atom false)
1567 roll-left? (atom false)
1568 roll-right? (atom false)
1569 timer (atom 0)]
1571 (world
1572 (nodify [top bottom floor origin])
1573 (merge standard-debug-controls
1574 {"key-r" (fn [_ pressed?] (reset! move-up? pressed?))
1575 "key-t" (fn [_ pressed?] (reset! move-down? pressed?))
1576 "key-f" (fn [_ pressed?] (reset! move-left? pressed?))
1577 "key-g" (fn [_ pressed?] (reset! move-right? pressed?))
1578 "key-v" (fn [_ pressed?] (reset! roll-left? pressed?))
1579 "key-b" (fn [_ pressed?] (reset! roll-right? pressed?))})
1581 (fn [world]
1582 (light-up-everything world)
1583 (enable-debug world)
1584 (set-gravity world (Vector3f. 0 0 0))
1587 (fn [world _]
1588 (if (zero? (rem (swap! timer inc) 100))
1589 (do
1590 ;; (println-repl @timer)
1591 (.attachChild (.getRootNode world)
1592 (sphere 0.05 :color ColorRGBA/Yellow
1593 :position (.getWorldTranslation top)
1594 :physical? false))
1595 (.attachChild (.getRootNode world)
1596 (sphere 0.05 :color ColorRGBA/LightGray
1597 :position (.getWorldTranslation bottom)
1598 :physical? false))))
1600 (if @move-up?
1601 (.applyTorque control
1602 (.mult (.getPhysicsRotation control)
1603 (Vector3f. 0 0 10))))
1604 (if @move-down?
1605 (.applyTorque control
1606 (.mult (.getPhysicsRotation control)
1607 (Vector3f. 0 0 -10))))
1608 (if @move-left?
1609 (.applyTorque control
1610 (.mult (.getPhysicsRotation control)
1611 (Vector3f. 0 10 0))))
1612 (if @move-right?
1613 (.applyTorque control
1614 (.mult (.getPhysicsRotation control)
1615 (Vector3f. 0 -10 0))))
1616 (if @roll-left?
1617 (.applyTorque control
1618 (.mult (.getPhysicsRotation control)
1619 (Vector3f. -1 0 0))))
1620 (if @roll-right?
1621 (.applyTorque control
1622 (.mult (.getPhysicsRotation control)
1623 (Vector3f. 1 0 0))))))))
1627 (defprotocol Frame
1628 (frame [this]))
1630 (extend-type BufferedImage
1631 Frame
1632 (frame [image]
1633 (merge
1634 (apply
1635 hash-map
1636 (interleave
1637 (doall (for [x (range (.getWidth image)) y (range (.getHeight image))]
1638 (vector x y)))
1639 (doall (for [x (range (.getWidth image)) y (range (.getHeight image))]
1640 (let [data (.getRGB image x y)]
1641 (hash-map :r (bit-shift-right (bit-and 0xff0000 data) 16)
1642 :g (bit-shift-right (bit-and 0x00ff00 data) 8)
1643 :b (bit-and 0x0000ff data)))))))
1644 {:width (.getWidth image) :height (.getHeight image)})))
1647 (extend-type ImagePlus
1648 Frame
1649 (frame [image+]
1650 (frame (.getBufferedImage image+))))
1653 #+end_src
1656 * COMMENT generate source
1657 #+begin_src clojure :tangle ../src/cortex/silly.clj
1658 <<body-1>>
1659 #+end_src