# HG changeset patch # User Robert McIntyre # Date 1329010947 25200 # Node ID 0589c35f04f23ab4e32692cff648831ae5f8a75f # Parent 2a7f57e7efdb0f5cd801251ff46b35a9b6158284 wrote intro for touch.org diff -r 2a7f57e7efdb -r 0589c35f04f2 org/ideas.org --- a/org/ideas.org Sat Feb 11 14:12:17 2012 -0700 +++ b/org/ideas.org Sat Feb 11 18:42:27 2012 -0700 @@ -98,6 +98,7 @@ - [ ] show sensor maps in AWT display? -- 2 days - [ ] add iteraterator constructs to Vector3f, Vector2f, etc. - [ ] upgrade to clojure 1.3, replace all defvars with new def + - [ ] get Vector3f, Triangle to implement iterable diff -r 2a7f57e7efdb -r 0589c35f04f2 org/touch.org --- a/org/touch.org Sat Feb 11 14:12:17 2012 -0700 +++ b/org/touch.org Sat Feb 11 18:42:27 2012 -0700 @@ -11,179 +11,34 @@ Touch is critical to navigation and spatial reasoning and as such I need a simulated version of it to give to my AI creatures. -#+name: skin-main +However, touch in my virtual can not exactly correspond to human touch +because my creatures are made out of completely rigid segments that +don't deform like human skin. + +Human skin has a wide array of touch sensors, each of which speciliaze +in detecting different vibrational modes and pressures. These sensors +can integrate a vast expanse of skin (i.e. your entire palm), or a +tiny patch of skin at the tip of your finger. The hairs of the skin +help detect objects before they even come into contact with the skin +proper. + +Instead of measuring deformation or vibration, I surround each rigid +part with a plenitude of hair-like objects which do not interact with +the physical world. Physical objects can pass through them with no +effect. The hairs are able to measure contact with other objects, and +constantly report how much of their extent is covered. So, even though +the creature's body parts do not deform, the hairs create a margin +around those body parts which achieves a sense of touch which is a +hybrid between a human's sense of deformation and sense from hairs. + +Implementing touch in jMonkeyEngine follows a different techinal route +than vision and hearing. Those two senses piggybacked off +jMonkeyEngine's 3D audio and video rendering subsystems. To simulate +Touch, I use jMonkeyEngine's physics system to execute many small +collision detections, one for each "hair". + +* Sensor Related Functions #+begin_src clojure -(in-ns 'cortex.touch) - -(defn triangles - "Return a sequence of all the Triangles which compose a given - Geometry." - [#^Geometry geom] - (let - [mesh (.getMesh geom) - triangles (transient [])] - (dorun - (for [n (range (.getTriangleCount mesh))] - (let [tri (Triangle.)] - (.getTriangle mesh n tri) - ;; (.calculateNormal tri) - ;; (.calculateCenter tri) - (conj! triangles tri)))) - (persistent! triangles))) - -(defn get-ray-origin - "Return the origin which a Ray would have to have to be in the exact - center of a particular Triangle in the Geometry in World - Coordinates." - [geom tri] - (let [new (Vector3f.)] - (.calculateCenter tri) - (.localToWorld geom (.getCenter tri) new) new)) - -(defn get-ray-direction - "Return the direction which a Ray would have to have to be to point - normal to the Triangle, in coordinates relative to the center of the - Triangle." - [geom tri] - (let [n+c (Vector3f.)] - (.calculateNormal tri) - (.calculateCenter tri) - (.localToWorld - geom - (.add (.getCenter tri) (.getNormal tri)) n+c) - (.subtract n+c (get-ray-origin geom tri)))) - -;; Every Mesh has many triangles, each with its own index. -;; Every vertex has its own index as well. - -(defn tactile-sensor-profile - "Return the touch-sensor distribution image in BufferedImage format, - or nil if it does not exist." - [#^Geometry obj] - (if-let [image-path (meta-data obj "touch")] - (load-image image-path))) - -(defn mesh-triangle - "Get the triangle specified by triangle-index from the mesh within - bounds." - [#^Mesh mesh triangle-index] - (let [scratch (Triangle.)] - (.getTriangle mesh triangle-index scratch) - scratch)) - -(defn triangle-vertex-indices - "Get the triangle vertex indices of a given triangle from a given - mesh." - [#^Mesh mesh triangle-index] - (let [indices (int-array 3)] - (.getTriangle mesh triangle-index indices) - (vec indices))) - -(defn vertex-UV-coord - "Get the UV-coordinates of the vertex named by vertex-index" - [#^Mesh mesh vertex-index] - (let [UV-buffer - (.getData - (.getBuffer - mesh - VertexBuffer$Type/TexCoord))] - [(.get UV-buffer (* vertex-index 2)) - (.get UV-buffer (+ 1 (* vertex-index 2)))])) - -(defn triangle-UV-coord - "Get the UV-cooridnates of the triangle's verticies." - [#^Mesh mesh width height triangle-index] - (map (fn [[u v]] (vector (* width u) (* height v))) - (map (partial vertex-UV-coord mesh) - (triangle-vertex-indices mesh triangle-index)))) - -(defn same-side? - "Given the points p1 and p2 and the reference point ref, is point p - on the same side of the line that goes through p1 and p2 as ref is?" - [p1 p2 ref p] - (<= - 0 - (.dot - (.cross (.subtract p2 p1) (.subtract p p1)) - (.cross (.subtract p2 p1) (.subtract ref p1))))) - -(defn triangle-seq [#^Triangle tri] - [(.get1 tri) (.get2 tri) (.get3 tri)]) - -(defn vector3f-seq [#^Vector3f v] - [(.getX v) (.getY v) (.getZ v)]) - -(defn inside-triangle? - "Is the point inside the triangle?" - {:author "Dylan Holmes"} - [#^Triangle tri #^Vector3f p] - (let [[vert-1 vert-2 vert-3] (triangle-seq tri)] - (and - (same-side? vert-1 vert-2 vert-3 p) - (same-side? vert-2 vert-3 vert-1 p) - (same-side? vert-3 vert-1 vert-2 p)))) - -(defn triangle->matrix4f - "Converts the triangle into a 4x4 matrix: The first three columns - contain the vertices of the triangle; the last contains the unit - normal of the triangle. The bottom row is filled with 1s." - [#^Triangle t] - (let [mat (Matrix4f.) - [vert-1 vert-2 vert-3] - ((comp vec map) #(.get t %) (range 3)) - unit-normal (do (.calculateNormal t)(.getNormal t)) - vertices [vert-1 vert-2 vert-3 unit-normal]] - (dorun - (for [row (range 4) col (range 3)] - (do - (.set mat col row (.get (vertices row)col)) - (.set mat 3 row 1)))) - mat)) - -(defn triangle-transformation - "Returns the affine transformation that converts each vertex in the - first triangle into the corresponding vertex in the second - triangle." - [#^Triangle tri-1 #^Triangle tri-2] - (.mult - (triangle->matrix4f tri-2) - (.invert (triangle->matrix4f tri-1)))) - -(defn point->vector2f [[u v]] - (Vector2f. u v)) - -(defn vector2f->vector3f [v] - (Vector3f. (.getX v) (.getY v) 0)) - -(defn map-triangle [f #^Triangle tri] - (Triangle. - (f 0 (.get1 tri)) - (f 1 (.get2 tri)) - (f 2 (.get3 tri)))) - -(defn points->triangle - "Convert a list of points into a triangle." - [points] - (apply #(Triangle. %1 %2 %3) - (map (fn [point] - (let [point (vec point)] - (Vector3f. (get point 0 0) - (get point 1 0) - (get point 2 0)))) - (take 3 points)))) - -(defn convex-bounds - "Returns the smallest square containing the given vertices, as a - vector of integers [left top width height]." - [uv-verts] - (let [xs (map first uv-verts) - ys (map second uv-verts) - x0 (Math/floor (apply min xs)) - y0 (Math/floor (apply min ys)) - x1 (Math/ceil (apply max xs)) - y1 (Math/ceil (apply max ys))] - [x0 y0 (- x1 x0) (- y1 y0)])) - (defn sensors-in-triangle "Locate the touch sensors in the triangle, returning a map of their UV and geometry-relative coordinates." @@ -229,7 +84,198 @@ "The location of the touch sensors in world-space coordinates." [#^Geometry geo] (vec (map :geometry (locate-feelers geo)))) +#+end_src +* Triangle Manipulation Functions + +#+begin_src clojure +(defn triangles + "Return a sequence of all the Triangles which compose a given + Geometry." + [#^Geometry geom] + (let + [mesh (.getMesh geom) + triangles (transient [])] + (dorun + (for [n (range (.getTriangleCount mesh))] + (let [tri (Triangle.)] + (.getTriangle mesh n tri) + ;; (.calculateNormal tri) + ;; (.calculateCenter tri) + (conj! triangles tri)))) + (persistent! triangles))) + +(defn mesh-triangle + "Get the triangle specified by triangle-index from the mesh within + bounds." + [#^Mesh mesh triangle-index] + (let [scratch (Triangle.)] + (.getTriangle mesh triangle-index scratch) + scratch)) + +(defn triangle-vertex-indices + "Get the triangle vertex indices of a given triangle from a given + mesh." + [#^Mesh mesh triangle-index] + (let [indices (int-array 3)] + (.getTriangle mesh triangle-index indices) + (vec indices))) + +(defn vertex-UV-coord + "Get the UV-coordinates of the vertex named by vertex-index" + [#^Mesh mesh vertex-index] + (let [UV-buffer + (.getData + (.getBuffer + mesh + VertexBuffer$Type/TexCoord))] + [(.get UV-buffer (* vertex-index 2)) + (.get UV-buffer (+ 1 (* vertex-index 2)))])) + +(defn triangle-UV-coord + "Get the UV-cooridnates of the triangle's verticies." + [#^Mesh mesh width height triangle-index] + (map (fn [[u v]] (vector (* width u) (* height v))) + (map (partial vertex-UV-coord mesh) + (triangle-vertex-indices mesh triangle-index)))) +#+end_src + +* Schrapnel Conversion Functions +#+begin_src clojure +(defn triangle-seq [#^Triangle tri] + [(.get1 tri) (.get2 tri) (.get3 tri)]) + +(defn vector3f-seq [#^Vector3f v] + [(.getX v) (.getY v) (.getZ v)]) + +(defn point->vector2f [[u v]] + (Vector2f. u v)) + +(defn vector2f->vector3f [v] + (Vector3f. (.getX v) (.getY v) 0)) + +(defn map-triangle [f #^Triangle tri] + (Triangle. + (f 0 (.get1 tri)) + (f 1 (.get2 tri)) + (f 2 (.get3 tri)))) + +(defn points->triangle + "Convert a list of points into a triangle." + [points] + (apply #(Triangle. %1 %2 %3) + (map (fn [point] + (let [point (vec point)] + (Vector3f. (get point 0 0) + (get point 1 0) + (get point 2 0)))) + (take 3 points)))) +#+end_src + +* Triangle Affine Transforms + +#+begin_src clojure +(defn triangle->matrix4f + "Converts the triangle into a 4x4 matrix: The first three columns + contain the vertices of the triangle; the last contains the unit + normal of the triangle. The bottom row is filled with 1s." + [#^Triangle t] + (let [mat (Matrix4f.) + [vert-1 vert-2 vert-3] + ((comp vec map) #(.get t %) (range 3)) + unit-normal (do (.calculateNormal t)(.getNormal t)) + vertices [vert-1 vert-2 vert-3 unit-normal]] + (dorun + (for [row (range 4) col (range 3)] + (do + (.set mat col row (.get (vertices row)col)) + (.set mat 3 row 1)))) + mat)) + +(defn triangle-transformation + "Returns the affine transformation that converts each vertex in the + first triangle into the corresponding vertex in the second + triangle." + [#^Triangle tri-1 #^Triangle tri-2] + (.mult + (triangle->matrix4f tri-2) + (.invert (triangle->matrix4f tri-1)))) +#+end_src + +* Blender Meta-Data + +#+begin_src clojure +(defn tactile-sensor-profile + "Return the touch-sensor distribution image in BufferedImage format, + or nil if it does not exist." + [#^Geometry obj] + (if-let [image-path (meta-data obj "touch")] + (load-image image-path))) +#+end_src + +* Physics Collision Objects +#+begin_src clojure +(defn get-ray-origin + "Return the origin which a Ray would have to have to be in the exact + center of a particular Triangle in the Geometry in World + Coordinates." + [geom tri] + (let [new (Vector3f.)] + (.calculateCenter tri) + (.localToWorld geom (.getCenter tri) new) new)) + +(defn get-ray-direction + "Return the direction which a Ray would have to have to be to point + normal to the Triangle, in coordinates relative to the center of the + Triangle." + [geom tri] + (let [n+c (Vector3f.)] + (.calculateNormal tri) + (.calculateCenter tri) + (.localToWorld + geom + (.add (.getCenter tri) (.getNormal tri)) n+c) + (.subtract n+c (get-ray-origin geom tri)))) +#+end_src + +* Triangle Boundaries +#+begin_src clojure +(defn same-side? + "Given the points p1 and p2 and the reference point ref, is point p + on the same side of the line that goes through p1 and p2 as ref is?" + [p1 p2 ref p] + (<= + 0 + (.dot + (.cross (.subtract p2 p1) (.subtract p p1)) + (.cross (.subtract p2 p1) (.subtract ref p1))))) + +(defn inside-triangle? + "Is the point inside the triangle?" + {:author "Dylan Holmes"} + [#^Triangle tri #^Vector3f p] + (let [[vert-1 vert-2 vert-3] (triangle-seq tri)] + (and + (same-side? vert-1 vert-2 vert-3 p) + (same-side? vert-2 vert-3 vert-1 p) + (same-side? vert-3 vert-1 vert-2 p)))) + +(defn convex-bounds + "Returns the smallest square containing the given vertices, as a + vector of integers [left top width height]." + [uv-verts] + (let [xs (map first uv-verts) + ys (map second uv-verts) + x0 (Math/floor (apply min xs)) + y0 (Math/floor (apply min ys)) + x1 (Math/ceil (apply max xs)) + y1 (Math/ceil (apply max ys))] + [x0 y0 (- x1 x0) (- y1 y0)])) +#+end_src + +* Skin Creation + +#+begin_src clojure (defn touch-fn "Returns a function which returns tactile sensory data when called inside a running simulation." @@ -283,7 +329,11 @@ (map touch-fn (filter #(isa? (class %) Geometry) (node-seq creature))))) +#+end_src +* Visualizing Touch + +#+begin_src clojure (defn view-touch "Creates a function which accepts a list of touch sensor-data and displays each element to the screen." @@ -316,6 +366,13 @@ (:import (com.jme3.math Triangle Vector3f Vector2f Ray Matrix4f))) #+end_src +;; Every Mesh has many triangles, each with its own index. +;; Every vertex has its own index as well. + +* Source Listing +* Next + + * COMMENT Code Generation #+begin_src clojure :tangle ../src/cortex/touch.clj <>