diff 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
line wrap: on
line diff
     1.1 --- a/org/skin.org	Fri Feb 03 06:04:30 2012 -0700
     1.2 +++ b/org/skin.org	Fri Feb 03 06:15:34 2012 -0700
     1.3 @@ -25,11 +25,15 @@
     1.4    density of triangles along the surface of the Geometry. Enables a
     1.5    Geometry to know what parts of itself are touching nearby objects."
     1.6    {:author "Robert McIntyre"}
     1.7 -  (:use (cortex world util))
     1.8 +  (:use (cortex world util sense))
     1.9    (:import com.jme3.scene.Geometry)
    1.10    (:import com.jme3.collision.CollisionResults)
    1.11 +  (:import jme3tools.converters.ImageToAwt)
    1.12    (:import (com.jme3.math Triangle Vector3f Ray)))
    1.13     
    1.14 +(use 'clojure.contrib.def)
    1.15 +(cortex.import/mega-import-jme3)
    1.16 +
    1.17  (defn triangles
    1.18    "Return a sequence of all the Triangles which compose a given
    1.19    Geometry." 
    1.20 @@ -56,8 +60,7 @@
    1.21      (.localToWorld geom (.getCenter tri) new) new))
    1.22  
    1.23  (defn get-ray-direction
    1.24 -  "Return the direction which a Ray would have to have to be in the
    1.25 -  exact center of a particular Triangle in the Geometry, pointing
    1.26 +  "Return the direction which a Ray would have to have to be to point
    1.27    normal to the Triangle, in coordinates relative to the center of the
    1.28    Triangle."
    1.29    [geom tri]
    1.30 @@ -69,37 +72,239 @@
    1.31       (.add (.getCenter tri) (.getNormal tri)) n+c)
    1.32      (.subtract n+c (get-ray-origin geom tri))))
    1.33  
    1.34 -(defn normal-rays
    1.35 -  "For each Triangle which comprises the Geometry, returns a Ray which
    1.36 -  is centered on that Triangle, points outward in a normal direction,
    1.37 -  and extends for =limit= distance."
    1.38 -  [limit #^Geometry geom]
    1.39 -  (vec
    1.40 -   (map 
    1.41 -    (fn [tri]
    1.42 -      (doto 
    1.43 -          (Ray. (get-ray-origin geom tri)
    1.44 -                (get-ray-direction geom tri))
    1.45 -        (.setLimit limit)))
    1.46 -    (triangles geom))))
    1.47 +;; Every Mesh has many triangles, each with its own index.
    1.48 +;; Every vertex has its own index as well.
    1.49  
    1.50 -(defn touch-percieve
    1.51 -  "Augment a Geometry with the sense of touch. Returns a sequence of
    1.52 -  non-negative integers, one for each triangle, with the value of the
    1.53 -  integer describing how many objects a ray of length =limit=, normal
    1.54 -  to the triangle and originating from its center, encountered. The
    1.55 -  Geometry itself is not counted among the results."
    1.56 -  [limit geom node]
    1.57 -  (let [normals  (normal-rays limit geom)]
    1.58 -    (doall
    1.59 -     (for [ray normals]
    1.60 +(defn tactile-sensor-image
    1.61 +  "Return the touch-sensor distribution image in BufferedImage format,
    1.62 +   or nil if it does not exist."
    1.63 +  [#^Geometry obj]
    1.64 +  (if-let [image-path (meta-data obj "touch")]
    1.65 +    (ImageToAwt/convert
    1.66 +     (.getImage
    1.67 +      (.loadTexture
    1.68 +       (asset-manager)
    1.69 +       image-path))
    1.70 +    false false 0)))
    1.71 +     
    1.72 +
    1.73 +
    1.74 +(defn triangle
    1.75 +  "Get the triangle specified by triangle-index from the mesh within
    1.76 +  bounds."
    1.77 +  [#^Mesh mesh triangle-index]
    1.78 +  (let [scratch (Triangle.)]
    1.79 +    (.getTriangle mesh triangle-index scratch)
    1.80 +    scratch))
    1.81 +
    1.82 +(defn triangle-vertex-indices
    1.83 +  "Get the triangle vertex indices of a given triangle from a given
    1.84 +   mesh."
    1.85 +  [#^Mesh mesh triangle-index]
    1.86 +  (let [indices (int-array 3)]
    1.87 +    (.getTriangle mesh triangle-index indices)
    1.88 +    (vec indices)))
    1.89 +
    1.90 +(defn vertex-UV-coord
    1.91 +  "Get the uv-coordinates of the vertex named by vertex-index"
    1.92 +  [#^Mesh mesh vertex-index]
    1.93 +  (let [UV-buffer
    1.94 +        (.getData
    1.95 +         (.getBuffer
    1.96 +          mesh
    1.97 +          VertexBuffer$Type/TexCoord))]
    1.98 +    [(.get UV-buffer (* vertex-index 2))
    1.99 +     (.get UV-buffer (+ 1 (* vertex-index 2)))]))
   1.100 +
   1.101 +(defn triangle-UV-coord
   1.102 +  "Get the uv-cooridnates of the triangle's verticies."
   1.103 +  [#^Mesh mesh width height triangle-index]
   1.104 +  (map (fn [[u v]] (vector (* width u) (* height v)))
   1.105 +       (map (partial vertex-UV-coord mesh)
   1.106 +            (triangle-vertex-indices mesh triangle-index))))
   1.107 +  
   1.108 +(defn same-side?
   1.109 +  "Given the points p1 and p2 and the reference point ref, is point p
   1.110 +  on the same side of the line that goes through p1 and p2 as ref is?" 
   1.111 +  [p1 p2 ref p]
   1.112 +  (<=
   1.113 +   0
   1.114 +   (.dot 
   1.115 +    (.cross (.subtract p2 p1) (.subtract p p1))
   1.116 +    (.cross (.subtract p2 p1) (.subtract ref p1)))))
   1.117 +
   1.118 +(defn triangle-seq [#^Triangle tri]
   1.119 +  [(.get1 tri) (.get2 tri) (.get3 tri)])
   1.120 +
   1.121 +(defn vector3f-seq [#^Vector3f v]
   1.122 +  [(.getX v) (.getY v) (.getZ v)])
   1.123 +
   1.124 +(defn inside-triangle?
   1.125 +  "Is the point inside the triangle?"
   1.126 +  {:author "Dylan Holmes"}
   1.127 +  [#^Triangle tri #^Vector3f p]
   1.128 +  (let [[vert-1 vert-2 vert-3] (triangle-seq tri)]
   1.129 +    (and
   1.130 +     (same-side? vert-1 vert-2 vert-3 p)
   1.131 +     (same-side? vert-2 vert-3 vert-1 p)
   1.132 +     (same-side? vert-3 vert-1 vert-2 p))))
   1.133 +
   1.134 +(defn triangle->matrix4f
   1.135 +  "Converts the triangle into a 4x4 matrix: The first three columns
   1.136 +   contain the vertices of the triangle; the last contains the unit
   1.137 +   normal of the triangle. The bottom row is filled with 1s."
   1.138 +  [#^Triangle t]
   1.139 +  (let [mat (Matrix4f.)
   1.140 +        [vert-1 vert-2 vert-3]
   1.141 +        ((comp vec map) #(.get t %) (range 3))
   1.142 +        unit-normal (do (.calculateNormal t)(.getNormal t))
   1.143 +        vertices [vert-1 vert-2 vert-3 unit-normal]]
   1.144 +    (dorun 
   1.145 +     (for [row (range 4) col (range 3)]
   1.146         (do
   1.147 -         (let [results (CollisionResults.)]
   1.148 -           (.collideWith node ray results)
   1.149 -           (let [touch-objects
   1.150 -                 (set (filter #(not (= geom %))
   1.151 -                              (map #(.getGeometry %) results)))]
   1.152 -             (count touch-objects))))))))
   1.153 +         (.set mat col row (.get (vertices row)col))
   1.154 +         (.set mat 3 row 1))))
   1.155 +    mat))
   1.156 +
   1.157 +(defn triangle-transformation
   1.158 +  "Returns the affine transformation that converts each vertex in the
   1.159 +   first triangle into the corresponding vertex in the second
   1.160 +   triangle."
   1.161 +  [#^Triangle tri-1 #^Triangle tri-2]
   1.162 +  (.mult 
   1.163 +   (triangle->matrix4f tri-2)
   1.164 +   (.invert (triangle->matrix4f tri-1))))
   1.165 +
   1.166 +(defn point->vector2f [[u v]]
   1.167 +  (Vector2f. u v))
   1.168 +
   1.169 +(defn vector2f->vector3f [v]
   1.170 +  (Vector3f. (.getX v) (.getY v) 0))
   1.171 +
   1.172 +(defn map-triangle [f #^Triangle tri]
   1.173 +  (Triangle.
   1.174 +   (f 0 (.get1 tri))
   1.175 +   (f 1 (.get2 tri))
   1.176 +   (f 2 (.get3 tri))))
   1.177 +
   1.178 +(defn points->triangle
   1.179 +  "Convert a list of points into a triangle."
   1.180 +  [points]
   1.181 +  (apply #(Triangle. %1 %2 %3)
   1.182 +         (map (fn [point]
   1.183 +                (let [point (vec point)]
   1.184 +                  (Vector3f. (get point 0 0)
   1.185 +                             (get point 1 0)
   1.186 +                             (get point 2 0))))
   1.187 +              (take 3 points))))
   1.188 +
   1.189 +(defn convex-bounds
   1.190 +  ;;dylan
   1.191 +  "Returns the smallest square containing the given
   1.192 +vertices, as a vector of integers [left top width height]."
   1.193 + ;; "Dimensions of the smallest integer bounding square of the list of
   1.194 + ;;  2D verticies in the form: [x y width height]."
   1.195 +  [uv-verts]
   1.196 +  (let [xs (map first uv-verts)
   1.197 +        ys (map second uv-verts)
   1.198 +        x0 (Math/floor (apply min xs))
   1.199 +        y0 (Math/floor (apply min ys))
   1.200 +        x1 (Math/ceil (apply max xs))
   1.201 +        y1 (Math/ceil (apply max ys))]
   1.202 +    [x0 y0 (- x1 x0) (- y1 y0)]))
   1.203 +
   1.204 +(defn sensors-in-triangle
   1.205 +  ;;dylan
   1.206 +  "Locate the touch sensors in the triangle, returning a map of their UV and geometry-relative coordinates."
   1.207 +  ;;"Find the locations of the touch sensors within a triangle in both
   1.208 +  ;; UV and gemoetry relative coordinates."
   1.209 +  [image mesh tri-index]
   1.210 +  (let [width (.getWidth image)
   1.211 +        height (.getHeight image)
   1.212 +        UV-vertex-coords (triangle-UV-coord mesh width height tri-index)
   1.213 +        bounds (convex-bounds UV-vertex-coords)
   1.214 +        
   1.215 +        cutout-triangle (points->triangle UV-vertex-coords)
   1.216 +        UV-sensor-coords
   1.217 +        (filter (comp (partial inside-triangle? cutout-triangle)
   1.218 +                      (fn [[u v]] (Vector3f. u v 0)))
   1.219 +                (white-coordinates image bounds))
   1.220 +        UV->geometry (triangle-transformation
   1.221 +                      cutout-triangle
   1.222 +                      (triangle mesh tri-index))
   1.223 +        geometry-sensor-coords
   1.224 +        (map (fn [[u v]] (.mult UV->geometry (Vector3f. u v 0)))
   1.225 +             UV-sensor-coords)]
   1.226 +  {:UV UV-sensor-coords :geometry geometry-sensor-coords}))
   1.227 +
   1.228 +(defn-memo locate-feelers
   1.229 +  "Search the geometry's tactile UV image for touch sensors, returning
   1.230 +  their positions in geometry-relative coordinates."
   1.231 +  [#^Geometry geo]
   1.232 +  (let [mesh (.getMesh geo)
   1.233 +        num-triangles (.getTriangleCount mesh)]
   1.234 +    (if-let [image (tactile-sensor-image geo)]
   1.235 +      (map
   1.236 +       (partial sensors-in-triangle image mesh)
   1.237 +       (range num-triangles))
   1.238 +      (repeat (.getTriangleCount mesh) {:UV nil :geometry nil}))))
   1.239 +
   1.240 +
   1.241 +
   1.242 +(defn-memo touch-topology [#^Gemoetry geo]
   1.243 +  (vec (collapse (reduce concat (map :UV (locate-feelers geo))))))
   1.244 +
   1.245 +(defn-memo feeler-coordinates [#^Geometry geo]
   1.246 +  (vec (map :geometry (locate-feelers geo))))
   1.247 +
   1.248 +(defn enable-touch [#^Geometry geo]
   1.249 +  (let [feeler-coords (feeler-coordinates geo)
   1.250 +        tris (triangles geo)
   1.251 +        limit 0.1
   1.252 +        ;;results (CollisionResults.)
   1.253 +        ]
   1.254 +    (if (empty? (touch-topology geo))
   1.255 +      nil
   1.256 +      (fn [node]
   1.257 +        (let [sensor-origins 
   1.258 +              (map
   1.259 +               #(map (partial local-to-world geo) %)
   1.260 +               feeler-coords)
   1.261 +              triangle-normals 
   1.262 +              (map (partial get-ray-direction geo)
   1.263 +                   tris)
   1.264 +              rays
   1.265 +              (flatten
   1.266 +               (map (fn [origins norm]
   1.267 +                      (map #(doto (Ray. % norm)
   1.268 +                              (.setLimit limit)) origins))
   1.269 +                    sensor-origins triangle-normals))]
   1.270 +          (vector
   1.271 +           (touch-topology geo)
   1.272 +           (vec
   1.273 +            (for [ray rays]
   1.274 +              (do
   1.275 +                (let [results (CollisionResults.)]
   1.276 +                  (.collideWith node ray results)
   1.277 +                  (let [touch-objects
   1.278 +                        (filter #(not (= geo (.getGeometry %)))
   1.279 +                                results)]
   1.280 +                    (- 255
   1.281 +                       (if (empty? touch-objects) 255
   1.282 +                           (rem 
   1.283 +                            (int
   1.284 +                             (* 255 (/ (.getDistance
   1.285 +                                        (first touch-objects)) limit)))
   1.286 +                            256))))))))))))))
   1.287 +                         
   1.288 +  
   1.289 +(defn touch [#^Node pieces]
   1.290 +  (filter (comp not nil?)
   1.291 +          (map enable-touch
   1.292 +               (filter #(isa? (class %) Geometry)
   1.293 +                       (node-seq pieces)))))
   1.294 +
   1.295 +
   1.296  #+end_src
   1.297  
   1.298