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