Mercurial > cortex
comparison org/test-creature.org @ 108:92b857b6145d
slow implementation of UV-mapped touch is complete
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sun, 15 Jan 2012 04:08:31 -0700 |
parents | 53fb379ac678 |
children | c05d8d222166 |
comparison
equal
deleted
inserted
replaced
107:53fb379ac678 | 108:92b857b6145d |
---|---|
63 (import java.awt.Dimension) | 63 (import java.awt.Dimension) |
64 (import javax.swing.JFrame) | 64 (import javax.swing.JFrame) |
65 (import java.awt.Dimension) | 65 (import java.awt.Dimension) |
66 (import com.aurellem.capture.RatchetTimer) | 66 (import com.aurellem.capture.RatchetTimer) |
67 (declare joint-create) | 67 (declare joint-create) |
68 (use 'clojure.contrib.def) | |
68 | 69 |
69 (defn view-image | 70 (defn view-image |
70 "Initailizes a JPanel on which you may draw a BufferedImage. | 71 "Initailizes a JPanel on which you may draw a BufferedImage. |
71 Returns a function that accepts a BufferedImage and draws it to the | 72 Returns a function that accepts a BufferedImage and draws it to the |
72 JPanel." | 73 JPanel." |
140 | 141 |
141 (defn collapse | 142 (defn collapse |
142 "Take a set of pairs of integers and collapse them into a | 143 "Take a set of pairs of integers and collapse them into a |
143 contigous bitmap." | 144 contigous bitmap." |
144 [points] | 145 [points] |
145 (let | 146 (if (empty? points) [] |
146 [num-points (count points) | 147 (let |
147 center (vector | 148 [num-points (count points) |
148 (int (average (map first points))) | 149 center (vector |
149 (int (average (map first points)))) | 150 (int (average (map first points))) |
150 flattened | 151 (int (average (map first points)))) |
151 (reduce | 152 flattened |
152 concat | 153 (reduce |
153 (map | 154 concat |
154 (fn [column] | 155 (map |
155 (map vector | 156 (fn [column] |
156 (map first column) | 157 (map vector |
157 (collapse-1d (second center) | 158 (map first column) |
158 (map second column)))) | 159 (collapse-1d (second center) |
159 (partition-by first (sort-by first points)))) | 160 (map second column)))) |
160 squeezed | 161 (partition-by first (sort-by first points)))) |
161 (reduce | 162 squeezed |
162 concat | 163 (reduce |
163 (map | 164 concat |
164 (fn [row] | 165 (map |
165 (map vector | 166 (fn [row] |
166 (collapse-1d (first center) | 167 (map vector |
167 (map first row)) | 168 (collapse-1d (first center) |
168 (map second row))) | 169 (map first row)) |
169 (partition-by second (sort-by second flattened)))) | 170 (map second row))) |
170 relocate | 171 (partition-by second (sort-by second flattened)))) |
171 (let [min-x (apply min (map first squeezed)) | 172 relocate |
172 min-y (apply min (map second squeezed))] | 173 (let [min-x (apply min (map first squeezed)) |
173 (map (fn [[x y]] | 174 min-y (apply min (map second squeezed))] |
174 [(- x min-x) | 175 (map (fn [[x y]] |
175 (- y min-y)]) | 176 [(- x min-x) |
176 squeezed))] | 177 (- y min-y)]) |
177 relocate | 178 squeezed))] |
178 )) | 179 relocate |
180 ))) | |
179 | 181 |
180 (defn load-bullet [] | 182 (defn load-bullet [] |
181 (let [sim (world (Node.) {} no-op no-op)] | 183 (let [sim (world (Node.) {} no-op no-op)] |
182 (doto sim | 184 (doto sim |
183 (.enqueue | 185 (.enqueue |
415 | 417 |
416 (import jme3tools.converters.ImageToAwt) | 418 (import jme3tools.converters.ImageToAwt) |
417 | 419 |
418 (import ij.ImagePlus) | 420 (import ij.ImagePlus) |
419 | 421 |
420 (defn triangle-indices | 422 ;; Every Mesh has many triangles, each with its own index. |
421 "Get the triangle vertex indices of a given triangle from a given | 423 ;; Every vertex has its own index as well. |
422 mesh." | 424 |
423 [#^Mesh mesh triangle-index] | 425 (defn tactile-sensor-image |
424 (let [indices (int-array 3)] | |
425 (.getTriangle mesh triangle-index indices) | |
426 (vec indices))) | |
427 | |
428 (defn uv-coord | |
429 "Get the uv-coordinates of the vertex named by vertex-index" | |
430 [#^Mesh mesh vertex-index] | |
431 (let [UV-buffer | |
432 (.getData | |
433 (.getBuffer | |
434 mesh | |
435 VertexBuffer$Type/TexCoord))] | |
436 (Vector2f. | |
437 (.get UV-buffer (* vertex-index 2)) | |
438 (.get UV-buffer (+ 1 (* vertex-index 2)))))) | |
439 | |
440 (defn tri-uv-coord | |
441 "Get the uv-cooridnates of the triangle's verticies." | |
442 [#^Mesh mesh #^Triangle triangle] | |
443 (map (partial uv-coord mesh) | |
444 (triangle-indices mesh (.getIndex triangle)))) | |
445 | |
446 (defn touch-receptor-image | |
447 "Return the touch-sensor distribution image in ImagePlus format, or | 426 "Return the touch-sensor distribution image in ImagePlus format, or |
448 nil if it does not exist." | 427 nil if it does not exist." |
449 [#^Geometry obj] | 428 [#^Geometry obj] |
450 (let [mat (.getMaterial obj)] | 429 (let [mat (.getMaterial obj)] |
451 (if-let [texture-param | 430 (if-let [texture-param |
454 MaterialHelper/TEXTURE_TYPE_DIFFUSE)] | 433 MaterialHelper/TEXTURE_TYPE_DIFFUSE)] |
455 (let | 434 (let |
456 [texture | 435 [texture |
457 (.getTextureValue texture-param) | 436 (.getTextureValue texture-param) |
458 im (.getImage texture)] | 437 im (.getImage texture)] |
459 (ImagePlus. | 438 (ImageToAwt/convert im false false 0))))) |
460 "UV-map" | |
461 (ImageToAwt/convert im false false 0)))))) | |
462 | 439 |
463 (import ij.process.ImageProcessor) | 440 (import ij.process.ImageProcessor) |
464 (import java.awt.image.BufferedImage) | 441 (import java.awt.image.BufferedImage) |
465 | 442 |
466 (def white -1) | 443 (def white -1) |
467 | 444 |
468 (defn filter-pixels | 445 (defn filter-pixels |
469 "List the coordinates of all pixels matching pred." | 446 "List the coordinates of all pixels matching pred, within the bounds |
447 provided. Bounds -> [x0 y0 width height]" | |
470 {:author "Dylan Holmes"} | 448 {:author "Dylan Holmes"} |
471 [pred #^ImageProcessor ip] | 449 ([pred #^BufferedImage image] |
472 (let | 450 (filter-pixels pred image [0 0 (.getWidth image) (.getHeight image)])) |
473 [width (.getWidth ip) | 451 ([pred #^BufferedImage image [x0 y0 width height]] |
474 height (.getHeight ip)] | 452 ((fn accumulate [x y matches] |
475 ((fn accumulate [x y matches] | 453 (cond |
476 (cond | 454 (>= y (+ height y0)) matches |
477 (>= y height) matches | 455 (>= x (+ width x0)) (recur 0 (inc y) matches) |
478 (>= x width) (recur 0 (inc y) matches) | 456 (pred (.getRGB image x y)) |
479 (pred (.getPixel ip x y)) | 457 (recur (inc x) y (conj matches [x y])) |
480 (recur (inc x) y (conj matches (Vector2f. x y))) | 458 :else (recur (inc x) y matches))) |
481 :else (recur (inc x) y matches))) | 459 x0 y0 []))) |
482 0 0 []))) | |
483 | 460 |
484 (defn white-coordinates | 461 (defn white-coordinates |
485 "List the coordinates of all the white pixels in an image." | 462 "Coordinates of all the white pixels in a subset of the image." |
486 [#^ImageProcessor ip] | 463 [#^BufferedImage image bounds] |
487 (filter-pixels #(= % white) ip)) | 464 (filter-pixels #(= % white) image bounds)) |
465 | |
466 (defn triangle | |
467 "Get the triangle specified by triangle-index from the mesh" | |
468 [#^Mesh mesh triangle-index] | |
469 (let [scratch (Triangle.)] | |
470 (.getTriangle mesh triangle-index scratch) | |
471 scratch)) | |
472 | |
473 (defn triangle-vertex-indices | |
474 "Get the triangle vertex indices of a given triangle from a given | |
475 mesh." | |
476 [#^Mesh mesh triangle-index] | |
477 (let [indices (int-array 3)] | |
478 (.getTriangle mesh triangle-index indices) | |
479 (vec indices))) | |
480 | |
481 (defn vertex-UV-coord | |
482 "Get the uv-coordinates of the vertex named by vertex-index" | |
483 [#^Mesh mesh vertex-index] | |
484 (let [UV-buffer | |
485 (.getData | |
486 (.getBuffer | |
487 mesh | |
488 VertexBuffer$Type/TexCoord))] | |
489 [(.get UV-buffer (* vertex-index 2)) | |
490 (.get UV-buffer (+ 1 (* vertex-index 2)))])) | |
491 | |
492 (defn triangle-UV-coord | |
493 "Get the uv-cooridnates of the triangle's verticies." | |
494 [#^Mesh mesh width height triangle-index] | |
495 (map (fn [[u v]] (vector (* width u) (* height v))) | |
496 (map (partial vertex-UV-coord mesh) | |
497 (triangle-vertex-indices mesh triangle-index)))) | |
488 | 498 |
489 (defn same-side? | 499 (defn same-side? |
490 "Given the points p1 and p2 and the reference point ref, is point p | 500 "Given the points p1 and p2 and the reference point ref, is point p |
491 on the same side of the line that goes through p1 and p2 as ref is?" | 501 on the same side of the line that goes through p1 and p2 as ref is?" |
492 [p1 p2 ref p] | 502 [p1 p2 ref p] |
494 0 | 504 0 |
495 (.dot | 505 (.dot |
496 (.cross (.subtract p2 p1) (.subtract p p1)) | 506 (.cross (.subtract p2 p1) (.subtract p p1)) |
497 (.cross (.subtract p2 p1) (.subtract ref p1))))) | 507 (.cross (.subtract p2 p1) (.subtract ref p1))))) |
498 | 508 |
509 (defn triangle-seq [#^Triangle tri] | |
510 [(.get1 tri) (.get2 tri) (.get3 tri)]) | |
511 | |
512 (defn vector3f-seq [#^Vector3f v] | |
513 [(.getX v) (.getY v) (.getZ v)]) | |
514 | |
515 (defn inside-triangle? | |
516 "Is the point inside the triangle?" | |
517 {:author "Dylan Holmes"} | |
518 [#^Triangle tri #^Vector3f p] | |
519 (let [[vert-1 vert-2 vert-3] (triangle-seq tri)] | |
520 (and | |
521 (same-side? vert-1 vert-2 vert-3 p) | |
522 (same-side? vert-2 vert-3 vert-1 p) | |
523 (same-side? vert-3 vert-1 vert-2 p)))) | |
524 | |
499 (defn triangle->matrix4f | 525 (defn triangle->matrix4f |
500 "Converts the triangle into a 4x4 matrix of vertices: The first | 526 "Converts the triangle into a 4x4 matrix: The first three columns |
501 three columns contain the vertices of the triangle; the last | 527 contain the vertices of the triangle; the last contains the unit |
502 contains the unit normal of the triangle. The bottom row is filled | 528 normal of the triangle. The bottom row is filled with 1s." |
503 with 1s." | |
504 [#^Triangle t] | 529 [#^Triangle t] |
505 (let [mat (Matrix4f.) | 530 (let [mat (Matrix4f.) |
506 [vert-1 vert-2 vert-3] | 531 [vert-1 vert-2 vert-3] |
507 ((comp vec map) #(.get t %) (range 3)) | 532 ((comp vec map) #(.get t %) (range 3)) |
508 unit-normal (do (.calculateNormal t)(.getNormal t)) | 533 unit-normal (do (.calculateNormal t)(.getNormal t)) |
521 [#^Triangle tri-1 #^Triangle tri-2] | 546 [#^Triangle tri-1 #^Triangle tri-2] |
522 (.mult | 547 (.mult |
523 (triangle->matrix4f tri-2) | 548 (triangle->matrix4f tri-2) |
524 (.invert (triangle->matrix4f tri-1)))) | 549 (.invert (triangle->matrix4f tri-1)))) |
525 | 550 |
526 (def death (Triangle. | 551 (defn point->vector2f [[u v]] |
527 (Vector3f. 1 1 1) | 552 (Vector2f. u v)) |
528 (Vector3f. 1 2 3) | |
529 (Vector3f. 5 6 7))) | |
530 | |
531 (def death-2 (Triangle. | |
532 (Vector3f. 2 2 2) | |
533 (Vector3f. 1 1 1) | |
534 (Vector3f. 0 1 0))) | |
535 | 553 |
536 (defn vector2f->vector3f [v] | 554 (defn vector2f->vector3f [v] |
537 (Vector3f. (.getX v) (.getY v) 0)) | 555 (Vector3f. (.getX v) (.getY v) 0)) |
538 | |
539 (extend-type Triangle | |
540 Textual | |
541 (text [t] | |
542 (println "Triangle: " \newline (.get1 t) \newline | |
543 (.get2 t) \newline (.get3 t)))) | |
544 | 556 |
545 (defn map-triangle [f #^Triangle tri] | 557 (defn map-triangle [f #^Triangle tri] |
546 (Triangle. | 558 (Triangle. |
547 (f 0 (.get1 tri)) | 559 (f 0 (.get1 tri)) |
548 (f 1 (.get2 tri)) | 560 (f 1 (.get2 tri)) |
549 (f 2 (.get3 tri)))) | 561 (f 2 (.get3 tri)))) |
550 | 562 |
551 (defn triangle-seq [#^Triangle tri] | 563 (defn points->triangle |
552 [(.get1 tri) (.get2 tri) (.get3 tri)]) | 564 "Convert a list of points into a triangle." |
553 | 565 [points] |
554 (defn vector3f-seq [#^Vector3f v] | |
555 [(.getX v) (.getY v) (.getZ v)]) | |
556 | |
557 (defn inside-triangle? | |
558 "Is the point inside the triangle? Now what do we do? | |
559 You might want to hold on there" | |
560 {:author "Dylan Holmes"} | |
561 [tri p] | |
562 (let [[vert-1 vert-2 vert-3] (triangle-seq tri)] | |
563 (and | |
564 (same-side? vert-1 vert-2 vert-3 p) | |
565 (same-side? vert-2 vert-3 vert-1 p) | |
566 (same-side? vert-3 vert-1 vert-2 p)))) | |
567 | |
568 (defn uv-triangle | |
569 "Convert the mesh triangle into the cooresponding triangle in | |
570 UV-space. Z-component of these triangles is always zero." | |
571 [#^Mesh mesh #^Triangle tri] | |
572 (apply #(Triangle. %1 %2 %3) | 566 (apply #(Triangle. %1 %2 %3) |
573 (map vector2f->vector3f | 567 (map (fn [point] |
574 (tri-uv-coord mesh tri)))) | 568 (let [point (vec point)] |
575 | 569 (Vector3f. (get point 0 0) |
576 (defn pixel-triangle | 570 (get point 1 0) |
577 "Convert the mesh triangle into the corresponding triangle in | 571 (get point 2 0)))) |
578 UV-pixel-space. Z compenent will be zero." | 572 (take 3 points)))) |
579 [#^Mesh mesh #^Triangle tri width height] | 573 |
580 (map-triangle (fn [_ v] | 574 (defn convex-bounds |
581 (Vector3f. (* width (.getX v)) | 575 "Dimensions of the smallest integer bounding square of the list of |
582 (* height (.getY v)) | 576 2D verticies in the form: [x y width height]." |
583 0)) | 577 [uv-verts] |
584 (uv-triangle mesh tri))) | 578 (let [xs (map first uv-verts) |
585 | 579 ys (map second uv-verts) |
586 (def rasterize pixel-triangle) | 580 x0 (Math/floor (apply min xs)) |
587 | 581 y0 (Math/floor (apply min ys)) |
588 | 582 x1 (Math/ceil (apply max xs)) |
589 (defn triangle-bounds | 583 y1 (Math/ceil (apply max ys))] |
590 "Dimensions of the bounding square of the triangle in the form | 584 [x0 y0 (- x1 x0) (- y1 y0)])) |
591 [x y width height]. | |
592 Assumes that the triangle lies in the XY plane." | |
593 [#^Triangle tri] | |
594 (let [verts (map vector3f-seq (triangle-seq tri)) | |
595 x (apply min (map first verts)) | |
596 y (apply min (map second verts))] | |
597 [x y | |
598 (- (apply max (map first verts)) x) | |
599 (- (apply max (map second verts)) y) | |
600 ])) | |
601 | |
602 | 585 |
603 (defn sensors-in-triangle | 586 (defn sensors-in-triangle |
604 "Find the locations of the touch sensors within a triangle in both | 587 "Find the locations of the touch sensors within a triangle in both |
605 UV and gemoetry relative coordinates." | 588 UV and gemoetry relative coordinates." |
606 [image mesh tri-index] | 589 [image mesh tri-index] |
607 (let [width (.getWidth image) | 590 (let [width (.getWidth image) |
608 height (.getHeight image)] | 591 height (.getHeight image) |
609 | 592 UV-vertex-coords (triangle-UV-coord mesh width height tri-index) |
610 | 593 bounds (convex-bounds UV-vertex-coords) |
611 | 594 |
612 | 595 cutout-triangle (points->triangle UV-vertex-coords) |
613 ) | 596 UV-sensor-coords |
614 | 597 (filter (comp (partial inside-triangle? cutout-triangle) |
615 | 598 (fn [[u v]] (Vector3f. u v 0))) |
616 (defn locate-feelers | 599 (white-coordinates image bounds)) |
600 UV->geometry (triangle-transformation | |
601 cutout-triangle | |
602 (triangle mesh tri-index)) | |
603 geometry-sensor-coords | |
604 (map (fn [[u v]] (.mult UV->geometry (Vector3f. u v 0))) | |
605 UV-sensor-coords)] | |
606 {:UV UV-sensor-coords :geometry geometry-sensor-coords})) | |
607 | |
608 (defn-memo locate-feelers | |
617 "Search the geometry's tactile UV image for touch sensors, returning | 609 "Search the geometry's tactile UV image for touch sensors, returning |
618 their positions in geometry-relative coordinates." | 610 their positions in geometry-relative coordinates." |
619 [#^Geometry geo] | 611 [#^Geometry geo] |
620 (if-let [image (touch-receptor-image geo)] | 612 (let [mesh (.getMesh geo) |
621 (let [mesh (.getMesh geo) | 613 num-triangles (.getTriangleCount mesh)] |
622 tris (triangles geo) | 614 (if-let [image (tactile-sensor-image geo)] |
623 | 615 (map |
624 width (.getWidth image) | 616 (partial sensors-in-triangle image mesh) |
625 height (.getHeight image) | 617 (range num-triangles)) |
626 | 618 (repeat (.getTriangleCount mesh) {:UV nil :geometry nil})))) |
627 ;; for each triangle | |
628 sensor-coords | |
629 (fn [tri] | |
630 ;; translate triangle to uv-pixel-space | |
631 (let [uv-tri | |
632 (pixel-triangle mesh tri width height) | |
633 bounds (vec (triangle-bounds uv-tri))] | |
634 | |
635 ;; get that part of the picture | |
636 | |
637 (apply #(.setRoi image %1 %2 %3 %4) bounds) | |
638 (let [cutout (.crop (.getProcessor image)) | |
639 ;; extract white pixels inside triangle | |
640 cutout-tri | |
641 (map-triangle | |
642 (fn [_ v] | |
643 (.subtract | |
644 v | |
645 (Vector3f. (bounds 0) (bounds 1) (float 0)))) | |
646 uv-tri) | |
647 whites (filter (partial inside-triangle? cutout-tri) | |
648 (map vector2f->vector3f | |
649 (white-coordinates cutout))) | |
650 ;; translate pixel coordinates to world-space | |
651 transform (triangle-transformation cutout-tri tri)] | |
652 (map #(.mult transform %) whites))))] | |
653 (vec (map sensor-coords tris))) | |
654 (repeat (count (triangles geo)) []))) | |
655 | 619 |
656 (use 'clojure.contrib.def) | 620 (use 'clojure.contrib.def) |
657 | 621 |
658 (defn-memo touch-topology [#^Gemoetry geo] | 622 (defn-memo touch-topology [#^Gemoetry geo] |
659 (if-let [image (touch-receptor-image geo)] | 623 (vec (collapse (reduce concat (map :UV (locate-feelers geo)))))) |
660 (let [feeler-coords | 624 |
661 (map | 625 (defn-memo feeler-coordinates [#^Geometry geo] |
662 #(vector (int (.getX %)) (int (.getY %))) | 626 (vec (map :geometry (locate-feelers geo)))) |
663 (white-coordinates | |
664 (.getProcessor image)))] | |
665 (vec (collapse feeler-coords))) | |
666 [])) | |
667 | 627 |
668 (defn enable-touch [#^Geometry geo] | 628 (defn enable-touch [#^Geometry geo] |
669 (let [feeler-coords (locate-feelers geo) | 629 (let [feeler-coords (feeler-coordinates geo) |
670 tris (triangles geo) | 630 tris (triangles geo) |
671 limit 0.1] | 631 limit 0.1] |
672 (fn [node] | 632 (fn [node] |
673 (let [sensor-origins | 633 (let [sensor-origins |
674 (map | 634 (map |
742 (light-up-everything world) | 702 (light-up-everything world) |
743 (enable-debug world) | 703 (enable-debug world) |
744 ;;(com.aurellem.capture.Capture/captureVideo | 704 ;;(com.aurellem.capture.Capture/captureVideo |
745 ;; world (file-str "/home/r/proj/ai-videos/hand")) | 705 ;; world (file-str "/home/r/proj/ai-videos/hand")) |
746 (.setTimer world (RatchetTimer. 60)) | 706 (.setTimer world (RatchetTimer. 60)) |
707 ;;(speed-up world) | |
747 ;;(set-gravity world (Vector3f. 0 0 0)) | 708 ;;(set-gravity world (Vector3f. 0 0 0)) |
748 ) | 709 ) |
749 (fn [world tpf] | 710 (fn [world tpf] |
750 (dorun | 711 (dorun |
751 (map #(%1 (%2 (.getRootNode world))) touch-debug-windows touch-nerves)) | 712 (map #(%1 (%2 (.getRootNode world))) touch-debug-windows touch-nerves)) |