Mercurial > cortex
changeset 229:6f1be9525e40
fleshing out text in touch.org
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 11 Feb 2012 19:13:39 -0700 |
parents | 0589c35f04f2 |
children | f9b7d674aed8 |
files | org/touch.org |
diffstat | 1 files changed, 145 insertions(+), 90 deletions(-) [+] |
line wrap: on
line diff
1.1 --- a/org/touch.org Sat Feb 11 18:42:27 2012 -0700 1.2 +++ b/org/touch.org Sat Feb 11 19:13:39 2012 -0700 1.3 @@ -6,6 +6,8 @@ 1.4 #+SETUPFILE: ../../aurellem/org/setup.org 1.5 #+INCLUDE: ../../aurellem/org/level-0.org 1.6 1.7 + 1.8 + 1.9 * Touch 1.10 1.11 Touch is critical to navigation and spatial reasoning and as such I 1.12 @@ -35,59 +37,47 @@ 1.13 than vision and hearing. Those two senses piggybacked off 1.14 jMonkeyEngine's 3D audio and video rendering subsystems. To simulate 1.15 Touch, I use jMonkeyEngine's physics system to execute many small 1.16 -collision detections, one for each "hair". 1.17 +collision detections, one for each "hair". The placement of the 1.18 +"hairs" is determined by a UV-mapped image which shows where each hair 1.19 +should be on the 3D surface of the body. 1.20 1.21 -* Sensor Related Functions 1.22 + 1.23 +* Defining Touch Meta-Data in Blender 1.24 + 1.25 +Each geometry can have a single UV map which describes the position 1.26 +and length of the "hairs" which will constitute its sense of 1.27 +touch. This image path is stored under the "touch" key. The image 1.28 +itself is grayscale, with black meaning a hair length of 0 (no hair is 1.29 +present) and white meaning a hair length of =scale=, which is a float 1.30 +stored under the key "scale". If the pixel is gray then the resultant 1.31 +hair length is linearly interpolated between 0 and =scale=. 1.32 + 1.33 #+begin_src clojure 1.34 -(defn sensors-in-triangle 1.35 - "Locate the touch sensors in the triangle, returning a map of their 1.36 - UV and geometry-relative coordinates." 1.37 - [image mesh tri-index] 1.38 - (let [width (.getWidth image) 1.39 - height (.getHeight image) 1.40 - UV-vertex-coords (triangle-UV-coord mesh width height tri-index) 1.41 - bounds (convex-bounds UV-vertex-coords) 1.42 - 1.43 - cutout-triangle (points->triangle UV-vertex-coords) 1.44 - UV-sensor-coords 1.45 - (filter (comp (partial inside-triangle? cutout-triangle) 1.46 - (fn [[u v]] (Vector3f. u v 0))) 1.47 - (white-coordinates image bounds)) 1.48 - UV->geometry (triangle-transformation 1.49 - cutout-triangle 1.50 - (mesh-triangle mesh tri-index)) 1.51 - geometry-sensor-coords 1.52 - (map (fn [[u v]] (.mult UV->geometry (Vector3f. u v 0))) 1.53 - UV-sensor-coords)] 1.54 - {:UV UV-sensor-coords :geometry geometry-sensor-coords})) 1.55 - 1.56 -(defn-memo locate-feelers 1.57 - "Search the geometry's tactile UV profile for touch sensors, 1.58 - returning their positions in geometry-relative coordinates." 1.59 - [#^Geometry geo] 1.60 - (let [mesh (.getMesh geo) 1.61 - num-triangles (.getTriangleCount mesh)] 1.62 - (if-let [image (tactile-sensor-profile geo)] 1.63 - (map 1.64 - (partial sensors-in-triangle image mesh) 1.65 - (range num-triangles)) 1.66 - (repeat (.getTriangleCount mesh) {:UV nil :geometry nil})))) 1.67 - 1.68 -(defn-memo touch-topology 1.69 - "Return a sequence of vectors of the form [x y] describing the 1.70 - \"topology\" of the tactile sensors. Points that are close together 1.71 - in the touch-topology are generally close together in the simulation." 1.72 - [#^Gemoetry geo] 1.73 - (vec (collapse (reduce concat (map :UV (locate-feelers geo)))))) 1.74 - 1.75 -(defn-memo feeler-coordinates 1.76 - "The location of the touch sensors in world-space coordinates." 1.77 - [#^Geometry geo] 1.78 - (vec (map :geometry (locate-feelers geo)))) 1.79 +(defn tactile-sensor-profile 1.80 + "Return the touch-sensor distribution image in BufferedImage format, 1.81 + or nil if it does not exist." 1.82 + [#^Geometry obj] 1.83 + (if-let [image-path (meta-data obj "touch")] 1.84 + (load-image image-path))) 1.85 #+end_src 1.86 1.87 + 1.88 +** TODO add image showing example touch-uv map 1.89 +** TODO add metadata display for worm 1.90 + 1.91 * Triangle Manipulation Functions 1.92 1.93 +The rigid bodies which make up a creature have an underlying 1.94 +=Geometry=, which is a =Mesh= plus a =Material= and other important 1.95 +data involved with displaying the body. 1.96 + 1.97 +A =Mesh= is composed of =Triangles=, and each =Triangle= has three 1.98 +verticies which have coordinates in XYZ space and UV space. 1.99 + 1.100 +Here, =(triangles)= gets all the triangles which compose a mesh, and 1.101 +=(triangle-UV-coord)= returns the the UV coordinates of the verticies 1.102 +of a triangle. 1.103 + 1.104 #+begin_src clojure 1.105 (defn triangles 1.106 "Return a sequence of all the Triangles which compose a given 1.107 @@ -141,6 +131,12 @@ 1.108 #+end_src 1.109 1.110 * Schrapnel Conversion Functions 1.111 + 1.112 +It is convienent to treat a =Triangle= as a sequence of verticies, and 1.113 +a =Vector2f= and =Vector3f= as a sequence of floats. These conversion 1.114 +functions make this easy. If these classes implemented =Iterable= then 1.115 +this code would not be necessary. Hopefully they will in the future. 1.116 + 1.117 #+begin_src clojure 1.118 (defn triangle-seq [#^Triangle tri] 1.119 [(.get1 tri) (.get2 tri) (.get3 tri)]) 1.120 @@ -174,6 +170,13 @@ 1.121 1.122 * Triangle Affine Transforms 1.123 1.124 +The position of each hair is stored in a 2D image in UV 1.125 +coordinates. To place the hair in 3D space we must convert from UV 1.126 +coordinates to XYZ coordinates. Each =Triangle= has coordinates in 1.127 +both UV-space and XYZ-space, which defines a unique [[http://mathworld.wolfram.com/AffineTransformation.html ][Affine Transform]] 1.128 +for translating any coordinate within the UV triangle to the 1.129 +cooresponding coordinate in the XYZ triangle. 1.130 + 1.131 #+begin_src clojure 1.132 (defn triangle->matrix4f 1.133 "Converts the triangle into a 4x4 matrix: The first three columns 1.134 @@ -202,15 +205,103 @@ 1.135 (.invert (triangle->matrix4f tri-1)))) 1.136 #+end_src 1.137 1.138 -* Blender Meta-Data 1.139 +* Triangle Boundaries 1.140 + 1.141 +For efficiency's sake I will divide the UV-image into small squares 1.142 +which inscribe each UV-triangle, then extract the points which lie 1.143 +inside the triangle and map them to 3D-space using 1.144 +=(triangle-transform)= above. To do this I need a function, 1.145 +=(inside-triangle?)=, which determines whether a point is inside a 1.146 +triangle in 2D UV-space. 1.147 1.148 #+begin_src clojure 1.149 -(defn tactile-sensor-profile 1.150 - "Return the touch-sensor distribution image in BufferedImage format, 1.151 - or nil if it does not exist." 1.152 - [#^Geometry obj] 1.153 - (if-let [image-path (meta-data obj "touch")] 1.154 - (load-image image-path))) 1.155 +(defn convex-bounds 1.156 + "Returns the smallest square containing the given vertices, as a 1.157 + vector of integers [left top width height]." 1.158 + [uv-verts] 1.159 + (let [xs (map first uv-verts) 1.160 + ys (map second uv-verts) 1.161 + x0 (Math/floor (apply min xs)) 1.162 + y0 (Math/floor (apply min ys)) 1.163 + x1 (Math/ceil (apply max xs)) 1.164 + y1 (Math/ceil (apply max ys))] 1.165 + [x0 y0 (- x1 x0) (- y1 y0)])) 1.166 + 1.167 +(defn same-side? 1.168 + "Given the points p1 and p2 and the reference point ref, is point p 1.169 + on the same side of the line that goes through p1 and p2 as ref is?" 1.170 + [p1 p2 ref p] 1.171 + (<= 1.172 + 0 1.173 + (.dot 1.174 + (.cross (.subtract p2 p1) (.subtract p p1)) 1.175 + (.cross (.subtract p2 p1) (.subtract ref p1))))) 1.176 + 1.177 +(defn inside-triangle? 1.178 + "Is the point inside the triangle?" 1.179 + {:author "Dylan Holmes"} 1.180 + [#^Triangle tri #^Vector3f p] 1.181 + (let [[vert-1 vert-2 vert-3] (triangle-seq tri)] 1.182 + (and 1.183 + (same-side? vert-1 vert-2 vert-3 p) 1.184 + (same-side? vert-2 vert-3 vert-1 p) 1.185 + (same-side? vert-3 vert-1 vert-2 p)))) 1.186 +#+end_src 1.187 + 1.188 + 1.189 + 1.190 +* Sensor Related Functions 1.191 + 1.192 +These functions analyze the touch-sensor-profile image convert the 1.193 +location of each touch sensor from pixel coordinates to UV-coordinates 1.194 +and XYZ-coordinates. 1.195 + 1.196 +#+begin_src clojure 1.197 +(defn sensors-in-triangle 1.198 + "Locate the touch sensors in the triangle, returning a map of their 1.199 + UV and geometry-relative coordinates." 1.200 + [image mesh tri-index] 1.201 + (let [width (.getWidth image) 1.202 + height (.getHeight image) 1.203 + UV-vertex-coords (triangle-UV-coord mesh width height tri-index) 1.204 + bounds (convex-bounds UV-vertex-coords) 1.205 + 1.206 + cutout-triangle (points->triangle UV-vertex-coords) 1.207 + UV-sensor-coords 1.208 + (filter (comp (partial inside-triangle? cutout-triangle) 1.209 + (fn [[u v]] (Vector3f. u v 0))) 1.210 + (white-coordinates image bounds)) 1.211 + UV->geometry (triangle-transformation 1.212 + cutout-triangle 1.213 + (mesh-triangle mesh tri-index)) 1.214 + geometry-sensor-coords 1.215 + (map (fn [[u v]] (.mult UV->geometry (Vector3f. u v 0))) 1.216 + UV-sensor-coords)] 1.217 + {:UV UV-sensor-coords :geometry geometry-sensor-coords})) 1.218 + 1.219 +(defn-memo locate-feelers 1.220 + "Search the geometry's tactile UV profile for touch sensors, 1.221 + returning their positions in geometry-relative coordinates." 1.222 + [#^Geometry geo] 1.223 + (let [mesh (.getMesh geo) 1.224 + num-triangles (.getTriangleCount mesh)] 1.225 + (if-let [image (tactile-sensor-profile geo)] 1.226 + (map 1.227 + (partial sensors-in-triangle image mesh) 1.228 + (range num-triangles)) 1.229 + (repeat (.getTriangleCount mesh) {:UV nil :geometry nil})))) 1.230 + 1.231 +(defn-memo touch-topology 1.232 + "Return a sequence of vectors of the form [x y] describing the 1.233 + \"topology\" of the tactile sensors. Points that are close together 1.234 + in the touch-topology are generally close together in the simulation." 1.235 + [#^Gemoetry geo] 1.236 + (vec (collapse (reduce concat (map :UV (locate-feelers geo)))))) 1.237 + 1.238 +(defn-memo feeler-coordinates 1.239 + "The location of the touch sensors in world-space coordinates." 1.240 + [#^Geometry geo] 1.241 + (vec (map :geometry (locate-feelers geo)))) 1.242 #+end_src 1.243 1.244 * Physics Collision Objects 1.245 @@ -238,40 +329,6 @@ 1.246 (.subtract n+c (get-ray-origin geom tri)))) 1.247 #+end_src 1.248 1.249 -* Triangle Boundaries 1.250 -#+begin_src clojure 1.251 -(defn same-side? 1.252 - "Given the points p1 and p2 and the reference point ref, is point p 1.253 - on the same side of the line that goes through p1 and p2 as ref is?" 1.254 - [p1 p2 ref p] 1.255 - (<= 1.256 - 0 1.257 - (.dot 1.258 - (.cross (.subtract p2 p1) (.subtract p p1)) 1.259 - (.cross (.subtract p2 p1) (.subtract ref p1))))) 1.260 - 1.261 -(defn inside-triangle? 1.262 - "Is the point inside the triangle?" 1.263 - {:author "Dylan Holmes"} 1.264 - [#^Triangle tri #^Vector3f p] 1.265 - (let [[vert-1 vert-2 vert-3] (triangle-seq tri)] 1.266 - (and 1.267 - (same-side? vert-1 vert-2 vert-3 p) 1.268 - (same-side? vert-2 vert-3 vert-1 p) 1.269 - (same-side? vert-3 vert-1 vert-2 p)))) 1.270 - 1.271 -(defn convex-bounds 1.272 - "Returns the smallest square containing the given vertices, as a 1.273 - vector of integers [left top width height]." 1.274 - [uv-verts] 1.275 - (let [xs (map first uv-verts) 1.276 - ys (map second uv-verts) 1.277 - x0 (Math/floor (apply min xs)) 1.278 - y0 (Math/floor (apply min ys)) 1.279 - x1 (Math/ceil (apply max xs)) 1.280 - y1 (Math/ceil (apply max ys))] 1.281 - [x0 y0 (- x1 x0) (- y1 y0)])) 1.282 -#+end_src 1.283 1.284 * Skin Creation 1.285 1.286 @@ -366,8 +423,6 @@ 1.287 (:import (com.jme3.math Triangle Vector3f Vector2f Ray Matrix4f))) 1.288 #+end_src 1.289 1.290 -;; Every Mesh has many triangles, each with its own index. 1.291 -;; Every vertex has its own index as well. 1.292 1.293 * Source Listing 1.294 * Next