view org/skin.org @ 37:eeba17a4bd54

cleaning up the touch code
author Robert McIntyre <rlm@mit.edu>
date Thu, 03 Nov 2011 09:52:34 -0700
parents 97703c7f020e
children 2ce7400825c2
line wrap: on
line source
1 #+title: Simulated Sense of Touch
2 #+author: Robert McIntyre
3 #+email: rlm@mit.edu
4 #+description: Simulated touch for AI research using JMonkeyEngine and clojure.
5 #+keywords: simulation, tactile sense, jMonkeyEngine3, clojure
6 #+SETUPFILE: ../../aurellem/org/setup.org
7 #+INCLUDE: ../../aurellem/org/level-0.org
9 * Touch
11 My creatures need to be able to feel their environments. The idea here
12 is to thousands of small /touch receptors/ along the geometries which
13 make up the creature's body. The number of touch receptors in a given
14 area is determined by how complicated that area is, as determined by
15 the total number of triangles in that region. This way, complicated
16 regions like the hands/face, etc. get more touch receptors than
17 simpler areas of the body.
19 #+srcname: skin-main
20 #+begin_src clojure
21 (ns cortex.touch
22 "Simulate the sense of touch in jMonkeyEngine3. Enables any Geometry
23 to be outfitted with touch sensors with density proportional to the
24 density of triangles along the surface of the Geometry. Enables a
25 Geometry to know what parts of itself are touching nearby objects."
26 {:author "Robert McIntyre"}
27 (:use (cortex world util))
28 (:import com.jme3.scene.Geometry)
29 (:import com.jme3.collision.CollisionResult)
30 (:import com.jme3.math Triangle Vector3f Ray))
32 (defn triangles
33 "Return a sequence of all the Triangles which compose a given
34 Geometry."
35 [#^Geometry geom]
36 (let
37 [mesh (.getMesh geom)
38 triangles (transient [])]
39 (dorun
40 (for [n (range (.getTriangleCount mesh))]
41 (let [tri (Triangle.)]
42 (.getTriangle mesh n tri)
43 ;; (.calculateNormal tri)
44 ;; (.calculateCenter tri)
45 (conj! triangles tri))))
46 (persistent! triangles)))
48 (defn get-ray-origin
49 "Return the origin which a Ray would have to have to be in the exact
50 center of a particular Triangle in the Geometry in World
51 Coordinates."
52 [geom tri]
53 (let [new (Vector3f.)]
54 (.calculateCenter tri)
55 (.localToWorld geom (.getCenter tri) new) new))
57 (defn get-ray-direction
58 "Return the direction which a Ray would have to have to be in the
59 exact center of a particular Triangle in the Geometry, pointing
60 normal to the Triangle, in coordinates relative to the center of the
61 Triangle."
62 [geom tri]
63 (let [n+c (Vector3f.)]
64 (.calculateNormal tri)
65 (.calculateCenter tri)
66 (.localToWorld
67 geom
68 (.add (.getCenter tri) (.getNormal tri)) n+c)
69 (.subtract n+c (get-ray-origin geom tri))))
71 (defn normal-rays
72 "For each Triangle which comprises the Geometry, returns a Ray which
73 is centered on that Triangle, points outward in a normal direction,
74 and extends for =limit= distance."
75 [limit #^Geometry geom]
76 (vec
77 (map
78 (fn [tri]
79 (doto
80 (Ray. (get-ray-origin geom tri)
81 (get-ray-direction geom tri))
82 (.setLimit limit)))
83 (triangles geom))))
85 (defn touch-percieve
86 "Augment a Geometry with the sense of touch. Returns a sequence of
87 non-negative integers, one for each triangle, with the value of the
88 integer describing how many objects a ray of length =limit=, normal
89 to the triangle and originating from its center, encountered. The
90 Geometry itself is not counted among the results."
91 [limit geom node]
92 (let [normals (normal-rays limit geom)]
93 (doall
94 (for [ray normals]
95 (do
96 (let [results (CollisionResults.)]
97 (.collideWith node ray results)
98 (let [touch-objects
99 (set (filter #(not (= geom %))
100 (map #(.getGeometry %) results)))]
101 (count touch-objects))))))))
102 #+end_src
105 * Example
107 #+begin_src clojure
110 (defn ray-origin-debug
111 [ray color]
112 (make-shape
113 (assoc base-shape
114 :shape (Sphere. 5 5 0.05)
115 :name "arrow"
116 :color color
117 :texture false
118 :physical? false
119 :position
120 (.getOrigin ray))))
122 (defn ray-debug [ray color]
123 (make-shape
124 (assoc
125 base-shape
126 :name "debug-ray"
127 :physical? false
128 :shape (com.jme3.scene.shape.Line.
129 (.getOrigin ray)
130 (.add
131 (.getOrigin ray)
132 (.mult (.getDirection ray)
133 (float (.getLimit ray))))))))
136 (defn contact-color [contacts]
137 (case contacts
138 0 ColorRGBA/Gray
139 1 ColorRGBA/Red
140 2 ColorRGBA/Green
141 3 ColorRGBA/Yellow
142 4 ColorRGBA/Orange
143 5 ColorRGBA/Red
144 6 ColorRGBA/Magenta
145 7 ColorRGBA/Pink
146 8 ColorRGBA/White))
148 (defn update-ray-debug [node ray contacts]
149 (let [origin (.getChild node 0)]
150 (.setLocalTranslation origin (.getOrigin ray))
151 (.setColor (.getMaterial origin) "Color" (contact-color contacts))))
153 (defn init-node
154 [debug-node rays]
155 (println-repl "Init touch debug node.")
156 (.detachAllChildren debug-node)
157 (dorun
158 (for [ray rays]
159 (do
160 (.attachChild
161 debug-node
162 (doto (Node.)
163 (.attachChild (ray-origin-debug ray ColorRGBA/Gray))
164 (.attachChild (ray-debug ray ColorRGBA/Gray))
165 ))))))
167 (defn manage-ray-debug-node [debug-node geom touch-data limit]
168 (let [rays (normal-rays limit geom)]
169 (if (not= (count (.getChildren debug-node)) (count touch-data))
170 (init-node debug-node rays))
171 (dorun
172 (for [n (range (count touch-data))]
173 (update-ray-debug
174 (.getChild debug-node n) (nth rays n) (nth touch-data n))))))
178 (defn no-logging []
179 (.setLevel (Logger/getLogger "com.jme3") Level/OFF))
181 (defn set-accuracy [world new-accuracy]
182 (let [physics-manager (.getState (.getStateManager world) BulletAppState)]
183 (.setAccuracy (.getPhysicsSpace physics-manager) (float new-accuracy))))
185 (defn transparent-sphere []
186 (doto
187 (make-shape
188 (merge base-shape
189 {:position (Vector3f. 0 2 0)
190 :name "the blob."
191 :material "Common/MatDefs/Misc/Unshaded.j3md"
192 :texture "Textures/purpleWisp.png"
193 :physical? true
194 :mass 70
195 :color ColorRGBA/Blue
196 :shape (Sphere. 10 10 1)}))
197 (-> (.getMaterial)
198 (.getAdditionalRenderState)
199 (.setBlendMode RenderState$BlendMode/Alpha))
200 (.setQueueBucket RenderQueue$Bucket/Transparent)))
202 (defn transparent-box []
203 (doto
204 (make-shape
205 (merge base-shape
206 {:position (Vector3f. 0 2 0)
207 :name "box"
208 :material "Common/MatDefs/Misc/Unshaded.j3md"
209 :texture "Textures/purpleWisp.png"
210 :physical? true
211 :mass 70
212 :color ColorRGBA/Blue
213 :shape (Box. 1 1 1)}))
214 (-> (.getMaterial)
215 (.getAdditionalRenderState)
216 (.setBlendMode RenderState$BlendMode/Alpha))
217 (.setQueueBucket RenderQueue$Bucket/Transparent)))
219 (defn transparent-floor []
220 (doto
221 (box 5 0.2 5 :mass 0 :position (Vector3f. 0 -2 0)
222 :material "Common/MatDefs/Misc/Unshaded.j3md"
223 :texture "Textures/redWisp.png"
224 :name "floor")
225 (-> (.getMaterial)
226 (.getAdditionalRenderState)
227 (.setBlendMode RenderState$BlendMode/Alpha))
228 (.setQueueBucket RenderQueue$Bucket/Transparent)))
230 (defn test-skin []
231 (let [b
232 ;;(transparent-box)
233 (transparent-sphere)
234 ;;(sphere)
235 f (transparent-floor)
236 debug-node (Node.)
237 node (doto (Node.) (.attachChild b) (.attachChild f))
238 root-node (doto (Node.) (.attachChild node)
239 (.attachChild debug-node))
240 ]
242 (world
243 root-node
244 {"key-return" (fire-cannon-ball node)}
245 (fn [world]
246 ;; (Capture/SimpleCaptureVideo
247 ;; world
248 ;; (file-str "/home/r/proj/cortex/tmp/blob.avi"))
249 ;; (no-logging)
250 ;;(enable-debug world)
251 ;; (set-accuracy world (/ 1 60))
252 )
254 (fn [& _]
255 (let [sensitivity 0.2
256 touch-data (touch-percieve sensitivity b node)]
257 (manage-ray-debug-node debug-node b touch-data sensitivity)
258 )
259 (Thread/sleep 10)
260 ))))
263 #+end_src
269 * COMMENT code generation
270 #+begin_src clojure :tangle ../src/cortex/touch.clj :noweb yes
271 <<skin-main>>
272 #+end_src