Mercurial > cortex
comparison org/touch.org @ 243:f33fec68f775
touch has been restored, with some very slight speed improvements, and now with much less code
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sun, 12 Feb 2012 14:14:57 -0700 |
parents | a7f26a074071 |
children | f23217324f72 |
comparison
equal
deleted
inserted
replaced
242:a7f26a074071 | 243:f33fec68f775 |
---|---|
75 ** TODO add image showing example touch-uv map | 75 ** TODO add image showing example touch-uv map |
76 ** TODO add metadata display for worm | 76 ** TODO add metadata display for worm |
77 | 77 |
78 | 78 |
79 * Skin Creation | 79 * Skin Creation |
80 * TODO get the actual lengths for each hair | 80 * TODO get the actual lengths for each feeler |
81 | |
82 #+begin_src clojure | |
83 pixel-triangles | |
84 xyz-triangles | |
85 conversions (map triangles->affine-transform pixel-triangles | |
86 xyz-triangles) | |
87 | |
88 #+end_src | |
89 | 81 |
90 | 82 |
91 =(touch-kernel)= generates the functions which implement the sense of | 83 =(touch-kernel)= generates the functions which implement the sense of |
92 touch for a creature. These functions must do 6 things to obtain touch | 84 touch for a creature. These functions must do 6 things to obtain touch |
93 data. | 85 data. |
117 For both of these, =(feeler-tips)= | 109 For both of these, =(feeler-tips)= |
118 | 110 |
119 - Generate some sort of topology for the sensors. | 111 - Generate some sort of topology for the sensors. |
120 =(touch-topology)= | 112 =(touch-topology)= |
121 | 113 |
122 #+begin_src clojure | |
123 | |
124 | |
125 | |
126 | |
127 #+end_src | |
128 | |
129 | |
130 | 114 |
131 #+name: kernel | 115 #+name: kernel |
132 #+begin_src clojure | 116 #+begin_src clojure |
133 (in-ns 'cortex.touch) | 117 (in-ns 'cortex.touch) |
134 | 118 |
135 (declare touch-topology feelers set-ray) | 119 (declare touch-topology feelers set-ray) |
136 | 120 |
137 (defn set-ray [#^Ray ray #^Matrix4f transform | 121 (defn set-ray [#^Ray ray #^Matrix4f transform #^Vector3f origin |
138 #^Vector3f origin #^Vector3f tip | 122 #^Vector3f tip length] |
139 length] | 123 ;; Doing everything locally recduces garbage collection by enough to |
140 (.setOrigin ray (.mult transform origin)) | 124 ;; be worth it. |
141 (.setDirection ray (.subtract | 125 (.mult transform origin (.getOrigin ray)) |
142 (.mult transform tip) | 126 |
143 (.getOrigin ray))) | 127 (.mult transform tip (.getDirection ray)) |
144 (.setLimit ray length) | 128 (.subtractLocal (.getDirection ray) (.getOrigin ray)) |
145 ray) | 129 (.setLimit ray length)) |
146 | |
147 | 130 |
148 (defn touch-kernel | 131 (defn touch-kernel |
149 "Constructs a function which will return tactile sensory data from | 132 "Constructs a function which will return tactile sensory data from |
150 'geo when called from inside a running simulation" | 133 'geo when called from inside a running simulation" |
151 [#^Geometry geo] | 134 [#^Geometry geo] |
152 (let [profile (tactile-sensor-profile geo) | 135 (if-let |
153 ray-reference-origins (feeler-origins geo profile) | 136 [profile (tactile-sensor-profile geo)] |
154 ray-reference-tips (feeler-tips geo profile) | 137 (let [ray-reference-origins (feeler-origins geo profile) |
155 ray-lengths (repeat 9000 0.1) | 138 ray-reference-tips (feeler-tips geo profile) |
156 current-rays (map (fn [] (Ray.)) ray-reference-origins) | 139 ray-lengths (repeat 9000 0.1) |
157 topology (touch-topology geo profile)] | 140 current-rays (map (fn [_] (Ray.)) ray-reference-origins) |
158 (if (empty? ray-reference-origins) nil | 141 topology (touch-topology geo profile)] |
159 (fn [node] | |
160 (let [transform (.getWorldMatrix geo)] | |
161 (dorun | |
162 (map (fn [ray ref-origin ref-tip length] | |
163 (set-ray ray transform ref-origin ref-tip length)) | |
164 current-rays ray-reference-origins | |
165 ray-reference-tips ray-lengths)) | |
166 (vector | |
167 topology | |
168 (vec | |
169 (for [ray current-rays] | |
170 (do | |
171 (let [results (CollisionResults.)] | |
172 (.collideWith node ray results) | |
173 (let [touch-objects | |
174 (filter #(not (= geo (.getGeometry %))) | |
175 results)] | |
176 [(if (empty? touch-objects) | |
177 (.getLimit ray) | |
178 (.getDistance (first touch-objects))) | |
179 (.getLimit ray)]))))))))))) | |
180 | |
181 (defn touch-kernel* | |
182 "Returns a function which returns tactile sensory data when called | |
183 inside a running simulation." | |
184 [#^Geometry geo] | |
185 (let [feeler-coords (feeler-coordinates geo) | |
186 tris (triangles geo) | |
187 limit (tactile-scale geo)] | |
188 (if (empty? (touch-topology geo)) | |
189 nil | |
190 (fn [node] | 142 (fn [node] |
191 (let [sensor-origins | 143 (let [transform (.getWorldMatrix geo)] |
192 (map | 144 (dorun |
193 #(map (partial local-to-world geo) %) | 145 (map (fn [ray ref-origin ref-tip length] |
194 feeler-coords) | 146 (set-ray ray transform ref-origin ref-tip length)) |
195 triangle-normals | 147 current-rays ray-reference-origins |
196 (map (partial get-ray-direction geo) | 148 ray-reference-tips ray-lengths)) |
197 tris) | |
198 rays | |
199 (flatten | |
200 (map (fn [origins norm] | |
201 (map #(doto (Ray. % norm) | |
202 (.setLimit limit)) origins)) | |
203 sensor-origins triangle-normals))] | |
204 (vector | 149 (vector |
205 (touch-topology geo) | 150 topology |
206 (vec | 151 (vec |
207 (for [ray rays] | 152 (for [ray current-rays] |
208 (do | 153 (do |
209 (let [results (CollisionResults.)] | 154 (let [results (CollisionResults.)] |
210 (.collideWith node ray results) | 155 (.collideWith node ray results) |
211 (let [touch-objects | 156 (let [touch-objects |
212 (filter #(not (= geo (.getGeometry %))) | 157 (filter #(not (= geo (.getGeometry %))) |
213 results)] | 158 results)] |
214 [(if (empty? touch-objects) | 159 [(if (empty? touch-objects) |
215 limit (.getDistance (first touch-objects))) | 160 (.getLimit ray) |
216 limit]))))))))))) | 161 (.getDistance (first touch-objects))) |
162 (.getLimit ray)]))))))))))) | |
217 | 163 |
218 (defn touch! | 164 (defn touch! |
219 "Endow the creature with the sense of touch. Returns a sequence of | 165 "Endow the creature with the sense of touch. Returns a sequence of |
220 functions, one for each body part with a tactile-sensor-proile, | 166 functions, one for each body part with a tactile-sensor-proile, |
221 each of which when called returns sensory data for that body part." | 167 each of which when called returns sensory data for that body part." |
224 (comp not nil?) | 170 (comp not nil?) |
225 (map touch-kernel | 171 (map touch-kernel |
226 (filter #(isa? (class %) Geometry) | 172 (filter #(isa? (class %) Geometry) |
227 (node-seq creature))))) | 173 (node-seq creature))))) |
228 #+end_src | 174 #+end_src |
175 | |
176 #+results: kernel | |
177 : #'cortex.touch/touch! | |
229 | 178 |
230 * Sensor Related Functions | 179 * Sensor Related Functions |
231 | 180 |
232 These functions analyze the touch-sensor-profile image convert the | 181 These functions analyze the touch-sensor-profile image convert the |
233 location of each touch sensor from pixel coordinates to UV-coordinates | 182 location of each touch sensor from pixel coordinates to UV-coordinates |
277 (map #(.add % normal) origins)) | 226 (map #(.add % normal) origins)) |
278 world-coords normals))) | 227 world-coords normals))) |
279 | 228 |
280 | 229 |
281 (defn touch-topology [#^Geometry geo image] | 230 (defn touch-topology [#^Geometry geo image] |
282 (collapse (feeler-pixel-coords geo image))) | 231 (collapse (reduce concat (feeler-pixel-coords geo image)))) |
283 | 232 #+end_src |
284 | |
285 (defn sensors-in-triangle | |
286 "Locate the touch sensors in the triangle, returning a map of their | |
287 UV and geometry-relative coordinates." | |
288 [image mesh tri-index] | |
289 (let [width (.getWidth image) | |
290 height (.getHeight image) | |
291 UV-vertex-coords (triangle-UV-coord mesh width height tri-index) | |
292 bounds (convex-bounds UV-vertex-coords) | |
293 | |
294 cutout-triangle (points->triangle UV-vertex-coords) | |
295 UV-sensor-coords | |
296 (filter (comp (partial inside-triangle? cutout-triangle) | |
297 (fn [[u v]] (Vector3f. u v 0))) | |
298 (white-coordinates image bounds)) | |
299 UV->geometry (triangle-transformation | |
300 cutout-triangle | |
301 (mesh-triangle mesh tri-index)) | |
302 geometry-sensor-coords | |
303 (map (fn [[u v]] (.mult UV->geometry (Vector3f. u v 0))) | |
304 UV-sensor-coords)] | |
305 {:UV UV-sensor-coords :geometry geometry-sensor-coords})) | |
306 | |
307 (defn-memo locate-feelers | |
308 "Search the geometry's tactile UV profile for touch sensors, | |
309 returning their positions in geometry-relative coordinates." | |
310 [#^Geometry geo] | |
311 (let [mesh (.getMesh geo) | |
312 num-triangles (.getTriangleCount mesh)] | |
313 (if-let [image (tactile-sensor-profile geo)] | |
314 (map | |
315 (partial sensors-in-triangle image mesh) | |
316 (range num-triangles)) | |
317 (repeat (.getTriangleCount mesh) {:UV nil :geometry nil})))) | |
318 | |
319 (defn-memo touch-topology | |
320 "Return a sequence of vectors of the form [x y] describing the | |
321 \"topology\" of the tactile sensors. Points that are close together | |
322 in the touch-topology are generally close together in the simulation." | |
323 [#^Gemoetry geo] | |
324 (vec (collapse (reduce concat (map :UV (locate-feelers geo)))))) | |
325 | |
326 (defn-memo feeler-coordinates | |
327 "The location of the touch sensors in world-space coordinates." | |
328 [#^Geometry geo] | |
329 (vec (map :geometry (locate-feelers geo)))) | |
330 #+end_src | |
331 | |
332 | |
333 | |
334 | 233 |
335 * Visualizing Touch | 234 * Visualizing Touch |
336 #+name: visualization | 235 #+name: visualization |
337 #+begin_src clojure | 236 #+begin_src clojure |
338 (in-ns 'cortex.touch) | 237 (in-ns 'cortex.touch) |
455 for translating any coordinate within the UV triangle to the | 354 for translating any coordinate within the UV triangle to the |
456 cooresponding coordinate in the XYZ triangle. | 355 cooresponding coordinate in the XYZ triangle. |
457 | 356 |
458 #+name: triangles-3 | 357 #+name: triangles-3 |
459 #+begin_src clojure | 358 #+begin_src clojure |
359 (in-ns 'cortex.touch) | |
360 | |
460 (defn triangle->matrix4f | 361 (defn triangle->matrix4f |
461 "Converts the triangle into a 4x4 matrix: The first three columns | 362 "Converts the triangle into a 4x4 matrix: The first three columns |
462 contain the vertices of the triangle; the last contains the unit | 363 contain the vertices of the triangle; the last contains the unit |
463 normal of the triangle. The bottom row is filled with 1s." | 364 normal of the triangle. The bottom row is filled with 1s." |
464 [#^Triangle t] | 365 [#^Triangle t] |
490 It is convienent to treat a =Triangle= as a sequence of verticies, and | 391 It is convienent to treat a =Triangle= as a sequence of verticies, and |
491 a =Vector2f= and =Vector3f= as a sequence of floats. These conversion | 392 a =Vector2f= and =Vector3f= as a sequence of floats. These conversion |
492 functions make this easy. If these classes implemented =Iterable= then | 393 functions make this easy. If these classes implemented =Iterable= then |
493 this code would not be necessary. Hopefully they will in the future. | 394 this code would not be necessary. Hopefully they will in the future. |
494 | 395 |
495 #+name: triangles-2 | |
496 #+begin_src clojure | |
497 (defn point->vector2f [[u v]] | |
498 (Vector2f. u v)) | |
499 | |
500 (defn vector2f->vector3f [v] | |
501 (Vector3f. (.getX v) (.getY v) 0)) | |
502 | |
503 (defn map-triangle [f #^Triangle tri] | |
504 (Triangle. | |
505 (f 0 (.get1 tri)) | |
506 (f 1 (.get2 tri)) | |
507 (f 2 (.get3 tri)))) | |
508 | |
509 (defn points->triangle | |
510 "Convert a list of points into a triangle." | |
511 [points] | |
512 (apply #(Triangle. %1 %2 %3) | |
513 (map (fn [point] | |
514 (let [point (vec point)] | |
515 (Vector3f. (get point 0 0) | |
516 (get point 1 0) | |
517 (get point 2 0)))) | |
518 (take 3 points)))) | |
519 #+end_src | |
520 | |
521 | 396 |
522 * Triangle Boundaries | 397 * Triangle Boundaries |
523 | 398 |
524 For efficiency's sake I will divide the UV-image into small squares | 399 For efficiency's sake I will divide the UV-image into small squares |
525 which inscribe each UV-triangle, then extract the points which lie | 400 which inscribe each UV-triangle, then extract the points which lie |
561 (same-side? vert-1 vert-2 vert-3 p) | 436 (same-side? vert-1 vert-2 vert-3 p) |
562 (same-side? vert-2 vert-3 vert-1 p) | 437 (same-side? vert-2 vert-3 vert-1 p) |
563 (same-side? vert-3 vert-1 vert-2 p)))) | 438 (same-side? vert-3 vert-1 vert-2 p)))) |
564 #+end_src | 439 #+end_src |
565 | 440 |
566 #+results: triangles-4 | |
567 : #'cortex.touch/inside-triangle? | |
568 | |
569 | |
570 * Physics Collision Objects | 441 * Physics Collision Objects |
571 | 442 |
572 The "hairs" are actually =Rays= which extend from a point on a | 443 The "hairs" are actually =Rays= which extend from a point on a |
573 =Triangle= in the =Mesh= normal to the =Triangle's= surface. | 444 =Triangle= in the =Mesh= normal to the =Triangle's= surface. |
574 | 445 |
575 #+name: rays | |
576 #+begin_src clojure | |
577 (defn get-ray-origin | |
578 "Return the origin which a Ray would have to have to be in the exact | |
579 center of a particular Triangle in the Geometry in World | |
580 Coordinates." | |
581 [geom tri] | |
582 (let [new (Vector3f.)] | |
583 (.calculateCenter tri) | |
584 (.localToWorld geom (.getCenter tri) new) new)) | |
585 | |
586 (defn get-ray-direction | |
587 "Return the direction which a Ray would have to have to be to point | |
588 normal to the Triangle, in coordinates relative to the center of the | |
589 Triangle." | |
590 [geom tri] | |
591 (let [n+c (Vector3f.)] | |
592 (.calculateNormal tri) | |
593 (.calculateCenter tri) | |
594 (.localToWorld | |
595 geom | |
596 (.add (.getCenter tri) (.getNormal tri)) n+c) | |
597 (.subtract n+c (get-ray-origin geom tri)))) | |
598 #+end_src | |
599 * Headers | 446 * Headers |
600 | 447 |
601 #+name: touch-header | 448 #+name: touch-header |
602 #+begin_src clojure | 449 #+begin_src clojure |
603 (ns cortex.touch | 450 (ns cortex.touch |
634 | 481 |
635 (fn [world] | 482 (fn [world] |
636 (light-up-everything world)) | 483 (light-up-everything world)) |
637 | 484 |
638 (fn [world tpf] | 485 (fn [world tpf] |
639 (touch-display (map #(% (.getRootNode world)) touch)))))) | 486 |
487 | |
488 (dorun (map #(% (.getRootNode world)) touch)) | |
489 | |
490 | |
491 )))) | |
640 #+end_src | 492 #+end_src |
641 * Source Listing | 493 * Source Listing |
642 * Next | 494 * Next |
643 | 495 |
644 | 496 |
645 * COMMENT Code Generation | 497 * COMMENT Code Generation |
646 #+begin_src clojure :tangle ../src/cortex/touch.clj | 498 #+begin_src clojure :tangle ../src/cortex/touch.clj |
647 <<touch-header>> | 499 <<touch-header>> |
648 <<meta-data>> | 500 <<meta-data>> |
649 <<triangles-1>> | 501 <<triangles-1>> |
650 <<triangles-2>> | |
651 <<triangles-3>> | 502 <<triangles-3>> |
652 <<triangles-4>> | 503 <<triangles-4>> |
653 <<sensors>> | 504 <<sensors>> |
654 <<rays>> | |
655 <<kernel>> | 505 <<kernel>> |
656 <<visualization>> | 506 <<visualization>> |
657 #+end_src | 507 #+end_src |
658 | 508 |
659 | 509 |