Mercurial > cortex
comparison org/skin.org @ 156:e8df6e76c3e5
refactored touch
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Fri, 03 Feb 2012 06:15:34 -0700 |
parents | 39e4e1542e4a |
children |
comparison
equal
deleted
inserted
replaced
155:95bf55614211 | 156:e8df6e76c3e5 |
---|---|
23 "Simulate the sense of touch in jMonkeyEngine3. Enables any Geometry | 23 "Simulate the sense of touch in jMonkeyEngine3. Enables any Geometry |
24 to be outfitted with touch sensors with density proportional to the | 24 to be outfitted with touch sensors with density proportional to the |
25 density of triangles along the surface of the Geometry. Enables a | 25 density of triangles along the surface of the Geometry. Enables a |
26 Geometry to know what parts of itself are touching nearby objects." | 26 Geometry to know what parts of itself are touching nearby objects." |
27 {:author "Robert McIntyre"} | 27 {:author "Robert McIntyre"} |
28 (:use (cortex world util)) | 28 (:use (cortex world util sense)) |
29 (:import com.jme3.scene.Geometry) | 29 (:import com.jme3.scene.Geometry) |
30 (:import com.jme3.collision.CollisionResults) | 30 (:import com.jme3.collision.CollisionResults) |
31 (:import jme3tools.converters.ImageToAwt) | |
31 (:import (com.jme3.math Triangle Vector3f Ray))) | 32 (:import (com.jme3.math Triangle Vector3f Ray))) |
32 | 33 |
34 (use 'clojure.contrib.def) | |
35 (cortex.import/mega-import-jme3) | |
36 | |
33 (defn triangles | 37 (defn triangles |
34 "Return a sequence of all the Triangles which compose a given | 38 "Return a sequence of all the Triangles which compose a given |
35 Geometry." | 39 Geometry." |
36 [#^Geometry geom] | 40 [#^Geometry geom] |
37 (let | 41 (let |
54 (let [new (Vector3f.)] | 58 (let [new (Vector3f.)] |
55 (.calculateCenter tri) | 59 (.calculateCenter tri) |
56 (.localToWorld geom (.getCenter tri) new) new)) | 60 (.localToWorld geom (.getCenter tri) new) new)) |
57 | 61 |
58 (defn get-ray-direction | 62 (defn get-ray-direction |
59 "Return the direction which a Ray would have to have to be in the | 63 "Return the direction which a Ray would have to have to be to point |
60 exact center of a particular Triangle in the Geometry, pointing | |
61 normal to the Triangle, in coordinates relative to the center of the | 64 normal to the Triangle, in coordinates relative to the center of the |
62 Triangle." | 65 Triangle." |
63 [geom tri] | 66 [geom tri] |
64 (let [n+c (Vector3f.)] | 67 (let [n+c (Vector3f.)] |
65 (.calculateNormal tri) | 68 (.calculateNormal tri) |
67 (.localToWorld | 70 (.localToWorld |
68 geom | 71 geom |
69 (.add (.getCenter tri) (.getNormal tri)) n+c) | 72 (.add (.getCenter tri) (.getNormal tri)) n+c) |
70 (.subtract n+c (get-ray-origin geom tri)))) | 73 (.subtract n+c (get-ray-origin geom tri)))) |
71 | 74 |
72 (defn normal-rays | 75 ;; Every Mesh has many triangles, each with its own index. |
73 "For each Triangle which comprises the Geometry, returns a Ray which | 76 ;; Every vertex has its own index as well. |
74 is centered on that Triangle, points outward in a normal direction, | 77 |
75 and extends for =limit= distance." | 78 (defn tactile-sensor-image |
76 [limit #^Geometry geom] | 79 "Return the touch-sensor distribution image in BufferedImage format, |
77 (vec | 80 or nil if it does not exist." |
78 (map | 81 [#^Geometry obj] |
79 (fn [tri] | 82 (if-let [image-path (meta-data obj "touch")] |
80 (doto | 83 (ImageToAwt/convert |
81 (Ray. (get-ray-origin geom tri) | 84 (.getImage |
82 (get-ray-direction geom tri)) | 85 (.loadTexture |
83 (.setLimit limit))) | 86 (asset-manager) |
84 (triangles geom)))) | 87 image-path)) |
85 | 88 false false 0))) |
86 (defn touch-percieve | 89 |
87 "Augment a Geometry with the sense of touch. Returns a sequence of | 90 |
88 non-negative integers, one for each triangle, with the value of the | 91 |
89 integer describing how many objects a ray of length =limit=, normal | 92 (defn triangle |
90 to the triangle and originating from its center, encountered. The | 93 "Get the triangle specified by triangle-index from the mesh within |
91 Geometry itself is not counted among the results." | 94 bounds." |
92 [limit geom node] | 95 [#^Mesh mesh triangle-index] |
93 (let [normals (normal-rays limit geom)] | 96 (let [scratch (Triangle.)] |
94 (doall | 97 (.getTriangle mesh triangle-index scratch) |
95 (for [ray normals] | 98 scratch)) |
99 | |
100 (defn triangle-vertex-indices | |
101 "Get the triangle vertex indices of a given triangle from a given | |
102 mesh." | |
103 [#^Mesh mesh triangle-index] | |
104 (let [indices (int-array 3)] | |
105 (.getTriangle mesh triangle-index indices) | |
106 (vec indices))) | |
107 | |
108 (defn vertex-UV-coord | |
109 "Get the uv-coordinates of the vertex named by vertex-index" | |
110 [#^Mesh mesh vertex-index] | |
111 (let [UV-buffer | |
112 (.getData | |
113 (.getBuffer | |
114 mesh | |
115 VertexBuffer$Type/TexCoord))] | |
116 [(.get UV-buffer (* vertex-index 2)) | |
117 (.get UV-buffer (+ 1 (* vertex-index 2)))])) | |
118 | |
119 (defn triangle-UV-coord | |
120 "Get the uv-cooridnates of the triangle's verticies." | |
121 [#^Mesh mesh width height triangle-index] | |
122 (map (fn [[u v]] (vector (* width u) (* height v))) | |
123 (map (partial vertex-UV-coord mesh) | |
124 (triangle-vertex-indices mesh triangle-index)))) | |
125 | |
126 (defn same-side? | |
127 "Given the points p1 and p2 and the reference point ref, is point p | |
128 on the same side of the line that goes through p1 and p2 as ref is?" | |
129 [p1 p2 ref p] | |
130 (<= | |
131 0 | |
132 (.dot | |
133 (.cross (.subtract p2 p1) (.subtract p p1)) | |
134 (.cross (.subtract p2 p1) (.subtract ref p1))))) | |
135 | |
136 (defn triangle-seq [#^Triangle tri] | |
137 [(.get1 tri) (.get2 tri) (.get3 tri)]) | |
138 | |
139 (defn vector3f-seq [#^Vector3f v] | |
140 [(.getX v) (.getY v) (.getZ v)]) | |
141 | |
142 (defn inside-triangle? | |
143 "Is the point inside the triangle?" | |
144 {:author "Dylan Holmes"} | |
145 [#^Triangle tri #^Vector3f p] | |
146 (let [[vert-1 vert-2 vert-3] (triangle-seq tri)] | |
147 (and | |
148 (same-side? vert-1 vert-2 vert-3 p) | |
149 (same-side? vert-2 vert-3 vert-1 p) | |
150 (same-side? vert-3 vert-1 vert-2 p)))) | |
151 | |
152 (defn triangle->matrix4f | |
153 "Converts the triangle into a 4x4 matrix: The first three columns | |
154 contain the vertices of the triangle; the last contains the unit | |
155 normal of the triangle. The bottom row is filled with 1s." | |
156 [#^Triangle t] | |
157 (let [mat (Matrix4f.) | |
158 [vert-1 vert-2 vert-3] | |
159 ((comp vec map) #(.get t %) (range 3)) | |
160 unit-normal (do (.calculateNormal t)(.getNormal t)) | |
161 vertices [vert-1 vert-2 vert-3 unit-normal]] | |
162 (dorun | |
163 (for [row (range 4) col (range 3)] | |
96 (do | 164 (do |
97 (let [results (CollisionResults.)] | 165 (.set mat col row (.get (vertices row)col)) |
98 (.collideWith node ray results) | 166 (.set mat 3 row 1)))) |
99 (let [touch-objects | 167 mat)) |
100 (set (filter #(not (= geom %)) | 168 |
101 (map #(.getGeometry %) results)))] | 169 (defn triangle-transformation |
102 (count touch-objects)))))))) | 170 "Returns the affine transformation that converts each vertex in the |
171 first triangle into the corresponding vertex in the second | |
172 triangle." | |
173 [#^Triangle tri-1 #^Triangle tri-2] | |
174 (.mult | |
175 (triangle->matrix4f tri-2) | |
176 (.invert (triangle->matrix4f tri-1)))) | |
177 | |
178 (defn point->vector2f [[u v]] | |
179 (Vector2f. u v)) | |
180 | |
181 (defn vector2f->vector3f [v] | |
182 (Vector3f. (.getX v) (.getY v) 0)) | |
183 | |
184 (defn map-triangle [f #^Triangle tri] | |
185 (Triangle. | |
186 (f 0 (.get1 tri)) | |
187 (f 1 (.get2 tri)) | |
188 (f 2 (.get3 tri)))) | |
189 | |
190 (defn points->triangle | |
191 "Convert a list of points into a triangle." | |
192 [points] | |
193 (apply #(Triangle. %1 %2 %3) | |
194 (map (fn [point] | |
195 (let [point (vec point)] | |
196 (Vector3f. (get point 0 0) | |
197 (get point 1 0) | |
198 (get point 2 0)))) | |
199 (take 3 points)))) | |
200 | |
201 (defn convex-bounds | |
202 ;;dylan | |
203 "Returns the smallest square containing the given | |
204 vertices, as a vector of integers [left top width height]." | |
205 ;; "Dimensions of the smallest integer bounding square of the list of | |
206 ;; 2D verticies in the form: [x y width height]." | |
207 [uv-verts] | |
208 (let [xs (map first uv-verts) | |
209 ys (map second uv-verts) | |
210 x0 (Math/floor (apply min xs)) | |
211 y0 (Math/floor (apply min ys)) | |
212 x1 (Math/ceil (apply max xs)) | |
213 y1 (Math/ceil (apply max ys))] | |
214 [x0 y0 (- x1 x0) (- y1 y0)])) | |
215 | |
216 (defn sensors-in-triangle | |
217 ;;dylan | |
218 "Locate the touch sensors in the triangle, returning a map of their UV and geometry-relative coordinates." | |
219 ;;"Find the locations of the touch sensors within a triangle in both | |
220 ;; UV and gemoetry relative coordinates." | |
221 [image mesh tri-index] | |
222 (let [width (.getWidth image) | |
223 height (.getHeight image) | |
224 UV-vertex-coords (triangle-UV-coord mesh width height tri-index) | |
225 bounds (convex-bounds UV-vertex-coords) | |
226 | |
227 cutout-triangle (points->triangle UV-vertex-coords) | |
228 UV-sensor-coords | |
229 (filter (comp (partial inside-triangle? cutout-triangle) | |
230 (fn [[u v]] (Vector3f. u v 0))) | |
231 (white-coordinates image bounds)) | |
232 UV->geometry (triangle-transformation | |
233 cutout-triangle | |
234 (triangle mesh tri-index)) | |
235 geometry-sensor-coords | |
236 (map (fn [[u v]] (.mult UV->geometry (Vector3f. u v 0))) | |
237 UV-sensor-coords)] | |
238 {:UV UV-sensor-coords :geometry geometry-sensor-coords})) | |
239 | |
240 (defn-memo locate-feelers | |
241 "Search the geometry's tactile UV image for touch sensors, returning | |
242 their positions in geometry-relative coordinates." | |
243 [#^Geometry geo] | |
244 (let [mesh (.getMesh geo) | |
245 num-triangles (.getTriangleCount mesh)] | |
246 (if-let [image (tactile-sensor-image geo)] | |
247 (map | |
248 (partial sensors-in-triangle image mesh) | |
249 (range num-triangles)) | |
250 (repeat (.getTriangleCount mesh) {:UV nil :geometry nil})))) | |
251 | |
252 | |
253 | |
254 (defn-memo touch-topology [#^Gemoetry geo] | |
255 (vec (collapse (reduce concat (map :UV (locate-feelers geo)))))) | |
256 | |
257 (defn-memo feeler-coordinates [#^Geometry geo] | |
258 (vec (map :geometry (locate-feelers geo)))) | |
259 | |
260 (defn enable-touch [#^Geometry geo] | |
261 (let [feeler-coords (feeler-coordinates geo) | |
262 tris (triangles geo) | |
263 limit 0.1 | |
264 ;;results (CollisionResults.) | |
265 ] | |
266 (if (empty? (touch-topology geo)) | |
267 nil | |
268 (fn [node] | |
269 (let [sensor-origins | |
270 (map | |
271 #(map (partial local-to-world geo) %) | |
272 feeler-coords) | |
273 triangle-normals | |
274 (map (partial get-ray-direction geo) | |
275 tris) | |
276 rays | |
277 (flatten | |
278 (map (fn [origins norm] | |
279 (map #(doto (Ray. % norm) | |
280 (.setLimit limit)) origins)) | |
281 sensor-origins triangle-normals))] | |
282 (vector | |
283 (touch-topology geo) | |
284 (vec | |
285 (for [ray rays] | |
286 (do | |
287 (let [results (CollisionResults.)] | |
288 (.collideWith node ray results) | |
289 (let [touch-objects | |
290 (filter #(not (= geo (.getGeometry %))) | |
291 results)] | |
292 (- 255 | |
293 (if (empty? touch-objects) 255 | |
294 (rem | |
295 (int | |
296 (* 255 (/ (.getDistance | |
297 (first touch-objects)) limit))) | |
298 256)))))))))))))) | |
299 | |
300 | |
301 (defn touch [#^Node pieces] | |
302 (filter (comp not nil?) | |
303 (map enable-touch | |
304 (filter #(isa? (class %) Geometry) | |
305 (node-seq pieces))))) | |
306 | |
307 | |
103 #+end_src | 308 #+end_src |
104 | 309 |
105 | 310 |
106 * Example | 311 * Example |
107 | 312 |