# HG changeset patch # User Robert McIntyre # Date 1320339154 25200 # Node ID eeba17a4bd54ddf6a091e5ec4feb229c5f5ee1c5 # Parent 91090f8a44140dd4a45f3f556b457eafc6ce1d1a cleaning up the touch code diff -r 91090f8a4414 -r eeba17a4bd54 org/skin.org --- a/org/skin.org Thu Nov 03 08:42:39 2011 -0700 +++ b/org/skin.org Thu Nov 03 09:52:34 2011 -0700 @@ -1,29 +1,38 @@ -#+title: SKIN! +#+title: Simulated Sense of Touch #+author: Robert McIntyre #+email: rlm@mit.edu -#+description: Simulating touch in JMonkeyEngine +#+description: Simulated touch for AI research using JMonkeyEngine and clojure. +#+keywords: simulation, tactile sense, jMonkeyEngine3, clojure #+SETUPFILE: ../../aurellem/org/setup.org #+INCLUDE: ../../aurellem/org/level-0.org -#+babel: :mkdirp yes :noweb yes -let's see what checkboxes look like: +* Touch -* Skin! +My creatures need to be able to feel their environments. The idea here +is to thousands of small /touch receptors/ along the geometries which +make up the creature's body. The number of touch receptors in a given +area is determined by how complicated that area is, as determined by +the total number of triangles in that region. This way, complicated +regions like the hands/face, etc. get more touch receptors than +simpler areas of the body. #+srcname: skin-main #+begin_src clojure -(ns body.skin) -(use 'cortex.world) -(use 'cortex.import) -(use 'clojure.contrib.def) -(cortex.import/mega-import-jme3) -(rlm.rlm-commands/help) - -(import java.util.logging.Level) -(import java.util.logging.Logger) -(use 'hello.brick-wall) - -(defn triangles [#^Geometry geom] +(ns cortex.touch + "Simulate the sense of touch in jMonkeyEngine3. Enables any Geometry + to be outfitted with touch sensors with density proportional to the + density of triangles along the surface of the Geometry. Enables a + Geometry to know what parts of itself are touching nearby objects." + {:author "Robert McIntyre"} + (:use (cortex world util)) + (:import com.jme3.scene.Geometry) + (:import com.jme3.collision.CollisionResult) + (:import com.jme3.math Triangle Vector3f Ray)) + +(defn triangles + "Return a sequence of all the Triangles which compose a given + Geometry." + [#^Geometry geom] (let [mesh (.getMesh geom) triangles (transient [])] @@ -31,26 +40,72 @@ (for [n (range (.getTriangleCount mesh))] (let [tri (Triangle.)] (.getTriangle mesh n tri) - (.calculateNormal tri) - (.calculateCenter 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)) + (.localToWorld geom (.getCenter tri) new) new)) (defn get-ray-direction + "Return the direction which a Ray would have to have to be in the + exact center of a particular Triangle in the Geometry, pointing + 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)) - )) + (.localToWorld + geom + (.add (.getCenter tri) (.getNormal tri)) n+c) + (.subtract n+c (get-ray-origin geom tri)))) + +(defn normal-rays + "For each Triangle which comprises the Geometry, returns a Ray which + is centered on that Triangle, points outward in a normal direction, + and extends for =limit= distance." + [limit #^Geometry geom] + (vec + (map + (fn [tri] + (doto + (Ray. (get-ray-origin geom tri) + (get-ray-direction geom tri)) + (.setLimit limit))) + (triangles geom)))) + +(defn touch-percieve + "Augment a Geometry with the sense of touch. Returns a sequence of + non-negative integers, one for each triangle, with the value of the + integer describing how many objects a ray of length =limit=, normal + to the triangle and originating from its center, encountered. The + Geometry itself is not counted among the results." + [limit geom node] + (let [normals (normal-rays limit geom)] + (doall + (for [ray normals] + (do + (let [results (CollisionResults.)] + (.collideWith node ray results) + (let [touch-objects + (set (filter #(not (= geom %)) + (map #(.getGeometry %) results)))] + (count touch-objects)))))))) +#+end_src + + +* Example + +#+begin_src clojure + (defn ray-origin-debug [ray color] @@ -81,7 +136,7 @@ (defn contact-color [contacts] (case contacts 0 ColorRGBA/Gray - 1 ColorRGBA/Blue + 1 ColorRGBA/Red 2 ColorRGBA/Green 3 ColorRGBA/Yellow 4 ColorRGBA/Orange @@ -90,18 +145,6 @@ 7 ColorRGBA/Pink 8 ColorRGBA/White)) -(defn normal-rays - "returns rays" - [limit #^Geometry geom] - (vec - (map - (fn [tri] - (doto - (Ray. (get-ray-origin geom tri) - (get-ray-direction geom tri)) - (.setLimit limit))) - (triangles geom)))) - (defn update-ray-debug [node ray contacts] (let [origin (.getChild node 0)] (.setLocalTranslation origin (.getOrigin ray)) @@ -130,18 +173,7 @@ (update-ray-debug (.getChild debug-node n) (nth rays n) (nth touch-data n)))))) -(defn touch-percieve [limit geom node] - (let [normals (normal-rays limit geom)] - (doall - (for [ray normals] - (do - (let [results (CollisionResults.)] - (.collideWith node ray results) - (let [touch-objects (set (filter #(not (= geom %)) - (map #(.getGeometry %) results)))] - ;;(dorun (map #(println-repl (.getName %)) touch-objects)) - (count touch-objects)))))))) (defn no-logging [] (.setLevel (Logger/getLogger "com.jme3") Level/OFF)) @@ -227,19 +259,15 @@ (Thread/sleep 10) )))) + #+end_src -#+results: skin-main -: #'body.skin/test-skin - - - * COMMENT code generation -#+begin_src clojure :tangle ../src/body/skin.clj :noweb yes +#+begin_src clojure :tangle ../src/cortex/touch.clj :noweb yes <> #+end_src