view org/test-creature.org @ 147:72801a20b8e5

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