rlm@73
|
1 #+title: First attempt at a creature!
|
rlm@73
|
2 #+author: Robert McIntyre
|
rlm@73
|
3 #+email: rlm@mit.edu
|
rlm@73
|
4 #+description:
|
rlm@73
|
5 #+keywords: simulation, jMonkeyEngine3, clojure
|
rlm@73
|
6 #+SETUPFILE: ../../aurellem/org/setup.org
|
rlm@73
|
7 #+INCLUDE: ../../aurellem/org/level-0.org
|
rlm@73
|
8
|
rlm@129
|
9
|
rlm@129
|
10
|
rlm@99
|
11
|
rlm@73
|
12 * Intro
|
rlm@73
|
13 So far, I've made the following senses --
|
rlm@73
|
14 - Vision
|
rlm@73
|
15 - Hearing
|
rlm@73
|
16 - Touch
|
rlm@73
|
17 - Proprioception
|
rlm@73
|
18
|
rlm@73
|
19 And one effector:
|
rlm@73
|
20 - Movement
|
rlm@73
|
21
|
rlm@73
|
22 However, the code so far has only enabled these senses, but has not
|
rlm@73
|
23 actually implemented them. For example, there is still a lot of work
|
rlm@73
|
24 to be done for vision. I need to be able to create an /eyeball/ in
|
rlm@73
|
25 simulation that can be moved around and see the world from different
|
rlm@73
|
26 angles. I also need to determine weather to use log-polar or cartesian
|
rlm@73
|
27 for the visual input, and I need to determine how/wether to
|
rlm@73
|
28 disceritise the visual input.
|
rlm@73
|
29
|
rlm@73
|
30 I also want to be able to visualize both the sensors and the
|
rlm@104
|
31 effectors in pretty pictures. This semi-retarted creature will be my
|
rlm@73
|
32 first attempt at bringing everything together.
|
rlm@73
|
33
|
rlm@73
|
34 * The creature's body
|
rlm@73
|
35
|
rlm@73
|
36 Still going to do an eve-like body in blender, but due to problems
|
rlm@104
|
37 importing the joints, etc into jMonkeyEngine3, I'm going to do all
|
rlm@73
|
38 the connecting here in clojure code, using the names of the individual
|
rlm@73
|
39 components and trial and error. Later, I'll maybe make some sort of
|
rlm@73
|
40 creature-building modifications to blender that support whatever
|
rlm@73
|
41 discreitized senses I'm going to make.
|
rlm@73
|
42
|
rlm@73
|
43 #+name: body-1
|
rlm@73
|
44 #+begin_src clojure
|
rlm@73
|
45 (ns cortex.silly
|
rlm@73
|
46 "let's play!"
|
rlm@73
|
47 {:author "Robert McIntyre"})
|
rlm@73
|
48
|
rlm@73
|
49 ;; TODO remove this!
|
rlm@73
|
50 (require 'cortex.import)
|
rlm@73
|
51 (cortex.import/mega-import-jme3)
|
rlm@151
|
52 (use '(cortex world util body hearing touch vision sense))
|
rlm@73
|
53
|
rlm@73
|
54 (rlm.rlm-commands/help)
|
rlm@99
|
55 (import java.awt.image.BufferedImage)
|
rlm@99
|
56 (import javax.swing.JPanel)
|
rlm@99
|
57 (import javax.swing.SwingUtilities)
|
rlm@99
|
58 (import java.awt.Dimension)
|
rlm@99
|
59 (import javax.swing.JFrame)
|
rlm@99
|
60 (import java.awt.Dimension)
|
rlm@106
|
61 (import com.aurellem.capture.RatchetTimer)
|
rlm@99
|
62 (declare joint-create)
|
rlm@108
|
63 (use 'clojure.contrib.def)
|
rlm@73
|
64
|
rlm@73
|
65 (defn load-blender-model
|
rlm@73
|
66 "Load a .blend file using an asset folder relative path."
|
rlm@73
|
67 [^String model]
|
rlm@73
|
68 (.loadModel
|
rlm@73
|
69 (doto (asset-manager)
|
rlm@73
|
70 (.registerLoader BlenderModelLoader (into-array String ["blend"])))
|
rlm@73
|
71 model))
|
rlm@73
|
72
|
rlm@78
|
73 (defn blender-to-jme
|
rlm@78
|
74 "Convert from Blender coordinates to JME coordinates"
|
rlm@78
|
75 [#^Vector3f in]
|
rlm@78
|
76 (Vector3f. (.getX in)
|
rlm@78
|
77 (.getZ in)
|
rlm@78
|
78 (- (.getY in))))
|
rlm@74
|
79
|
rlm@96
|
80
|
rlm@87
|
81 (defmulti joint-dispatch
|
rlm@87
|
82 "Translate blender pseudo-joints into real JME joints."
|
rlm@88
|
83 (fn [constraints & _]
|
rlm@87
|
84 (:type constraints)))
|
rlm@87
|
85
|
rlm@87
|
86 (defmethod joint-dispatch :point
|
rlm@87
|
87 [constraints control-a control-b pivot-a pivot-b rotation]
|
rlm@87
|
88 (println-repl "creating POINT2POINT joint")
|
rlm@130
|
89 ;; bullet's point2point joints are BROKEN, so we must use the
|
rlm@130
|
90 ;; generic 6DOF joint instead of an actual Point2Point joint!
|
rlm@130
|
91
|
rlm@130
|
92 ;; should be able to do this:
|
rlm@130
|
93 (comment
|
rlm@130
|
94 (Point2PointJoint.
|
rlm@130
|
95 control-a
|
rlm@130
|
96 control-b
|
rlm@130
|
97 pivot-a
|
rlm@130
|
98 pivot-b))
|
rlm@130
|
99
|
rlm@130
|
100 ;; but instead we must do this:
|
rlm@130
|
101 (println-repl "substuting 6DOF joint for POINT2POINT joint!")
|
rlm@130
|
102 (doto
|
rlm@130
|
103 (SixDofJoint.
|
rlm@130
|
104 control-a
|
rlm@130
|
105 control-b
|
rlm@130
|
106 pivot-a
|
rlm@130
|
107 pivot-b
|
rlm@130
|
108 false)
|
rlm@130
|
109 (.setLinearLowerLimit Vector3f/ZERO)
|
rlm@130
|
110 (.setLinearUpperLimit Vector3f/ZERO)
|
rlm@130
|
111 ;;(.setAngularLowerLimit (Vector3f. 1 1 1))
|
rlm@130
|
112 ;;(.setAngularUpperLimit (Vector3f. 0 0 0))
|
rlm@130
|
113
|
rlm@130
|
114 ))
|
rlm@130
|
115
|
rlm@87
|
116
|
rlm@87
|
117 (defmethod joint-dispatch :hinge
|
rlm@87
|
118 [constraints control-a control-b pivot-a pivot-b rotation]
|
rlm@87
|
119 (println-repl "creating HINGE joint")
|
rlm@87
|
120 (let [axis
|
rlm@87
|
121 (if-let
|
rlm@87
|
122 [axis (:axis constraints)]
|
rlm@87
|
123 axis
|
rlm@87
|
124 Vector3f/UNIT_X)
|
rlm@87
|
125 [limit-1 limit-2] (:limit constraints)
|
rlm@87
|
126 hinge-axis
|
rlm@87
|
127 (.mult
|
rlm@87
|
128 rotation
|
rlm@87
|
129 (blender-to-jme axis))]
|
rlm@87
|
130 (doto
|
rlm@87
|
131 (HingeJoint.
|
rlm@87
|
132 control-a
|
rlm@87
|
133 control-b
|
rlm@87
|
134 pivot-a
|
rlm@87
|
135 pivot-b
|
rlm@87
|
136 hinge-axis
|
rlm@87
|
137 hinge-axis)
|
rlm@87
|
138 (.setLimit limit-1 limit-2))))
|
rlm@87
|
139
|
rlm@87
|
140 (defmethod joint-dispatch :cone
|
rlm@87
|
141 [constraints control-a control-b pivot-a pivot-b rotation]
|
rlm@87
|
142 (let [limit-xz (:limit-xz constraints)
|
rlm@87
|
143 limit-xy (:limit-xy constraints)
|
rlm@87
|
144 twist (:twist constraints)]
|
rlm@87
|
145
|
rlm@87
|
146 (println-repl "creating CONE joint")
|
rlm@87
|
147 (println-repl rotation)
|
rlm@87
|
148 (println-repl
|
rlm@87
|
149 "UNIT_X --> " (.mult rotation (Vector3f. 1 0 0)))
|
rlm@87
|
150 (println-repl
|
rlm@87
|
151 "UNIT_Y --> " (.mult rotation (Vector3f. 0 1 0)))
|
rlm@87
|
152 (println-repl
|
rlm@87
|
153 "UNIT_Z --> " (.mult rotation (Vector3f. 0 0 1)))
|
rlm@87
|
154 (doto
|
rlm@87
|
155 (ConeJoint.
|
rlm@87
|
156 control-a
|
rlm@87
|
157 control-b
|
rlm@87
|
158 pivot-a
|
rlm@87
|
159 pivot-b
|
rlm@87
|
160 rotation
|
rlm@87
|
161 rotation)
|
rlm@87
|
162 (.setLimit (float limit-xz)
|
rlm@87
|
163 (float limit-xy)
|
rlm@87
|
164 (float twist)))))
|
rlm@87
|
165
|
rlm@88
|
166 (defn connect
|
rlm@87
|
167 "here are some examples:
|
rlm@87
|
168 {:type :point}
|
rlm@87
|
169 {:type :hinge :limit [0 (/ Math/PI 2)] :axis (Vector3f. 0 1 0)}
|
rlm@87
|
170 (:axis defaults to (Vector3f. 1 0 0) if not provided for hinge joints)
|
rlm@87
|
171
|
rlm@89
|
172 {:type :cone :limit-xz 0]
|
rlm@89
|
173 :limit-xy 0]
|
rlm@89
|
174 :twist 0]} (use XZY rotation mode in blender!)"
|
rlm@87
|
175 [#^Node obj-a #^Node obj-b #^Node joint]
|
rlm@87
|
176 (let [control-a (.getControl obj-a RigidBodyControl)
|
rlm@87
|
177 control-b (.getControl obj-b RigidBodyControl)
|
rlm@87
|
178 joint-center (.getWorldTranslation joint)
|
rlm@87
|
179 joint-rotation (.toRotationMatrix (.getWorldRotation joint))
|
rlm@87
|
180 pivot-a (world-to-local obj-a joint-center)
|
rlm@87
|
181 pivot-b (world-to-local obj-b joint-center)]
|
rlm@89
|
182
|
rlm@87
|
183 (if-let [constraints
|
rlm@87
|
184 (map-vals
|
rlm@87
|
185 eval
|
rlm@87
|
186 (read-string
|
rlm@87
|
187 (meta-data joint "joint")))]
|
rlm@89
|
188 ;; A side-effect of creating a joint registers
|
rlm@89
|
189 ;; it with both physics objects which in turn
|
rlm@89
|
190 ;; will register the joint with the physics system
|
rlm@89
|
191 ;; when the simulation is started.
|
rlm@87
|
192 (do
|
rlm@87
|
193 (println-repl "creating joint between"
|
rlm@87
|
194 (.getName obj-a) "and" (.getName obj-b))
|
rlm@87
|
195 (joint-dispatch constraints
|
rlm@87
|
196 control-a control-b
|
rlm@87
|
197 pivot-a pivot-b
|
rlm@87
|
198 joint-rotation))
|
rlm@87
|
199 (println-repl "could not find joint meta-data!"))))
|
rlm@87
|
200
|
rlm@130
|
201
|
rlm@130
|
202
|
rlm@130
|
203
|
rlm@78
|
204 (defn assemble-creature [#^Node pieces joints]
|
rlm@78
|
205 (dorun
|
rlm@78
|
206 (map
|
rlm@78
|
207 (fn [geom]
|
rlm@78
|
208 (let [physics-control
|
rlm@78
|
209 (RigidBodyControl.
|
rlm@78
|
210 (HullCollisionShape.
|
rlm@78
|
211 (.getMesh geom))
|
rlm@78
|
212 (if-let [mass (meta-data geom "mass")]
|
rlm@78
|
213 (do
|
rlm@78
|
214 (println-repl
|
rlm@78
|
215 "setting" (.getName geom) "mass to" (float mass))
|
rlm@78
|
216 (float mass))
|
rlm@78
|
217 (float 1)))]
|
rlm@78
|
218
|
rlm@78
|
219 (.addControl geom physics-control)))
|
rlm@78
|
220 (filter #(isa? (class %) Geometry )
|
rlm@78
|
221 (node-seq pieces))))
|
rlm@78
|
222 (dorun
|
rlm@78
|
223 (map
|
rlm@78
|
224 (fn [joint]
|
rlm@133
|
225 (let [[obj-a obj-b] (joint-targets pieces joint)]
|
rlm@88
|
226 (connect obj-a obj-b joint)))
|
rlm@78
|
227 joints))
|
rlm@78
|
228 pieces)
|
rlm@74
|
229
|
rlm@116
|
230 (declare blender-creature)
|
rlm@74
|
231
|
rlm@78
|
232 (def hand "Models/creature1/one.blend")
|
rlm@74
|
233
|
rlm@78
|
234 (def worm "Models/creature1/try-again.blend")
|
rlm@78
|
235
|
rlm@90
|
236 (defn worm-model [] (load-blender-model worm))
|
rlm@90
|
237
|
rlm@80
|
238 (defn x-ray [#^ColorRGBA color]
|
rlm@80
|
239 (doto (Material. (asset-manager)
|
rlm@80
|
240 "Common/MatDefs/Misc/Unshaded.j3md")
|
rlm@80
|
241 (.setColor "Color" color)
|
rlm@80
|
242 (-> (.getAdditionalRenderState)
|
rlm@80
|
243 (.setDepthTest false))))
|
rlm@80
|
244
|
rlm@91
|
245 (defn colorful []
|
rlm@91
|
246 (.getChild (worm-model) "worm-21"))
|
rlm@90
|
247
|
rlm@90
|
248 (import jme3tools.converters.ImageToAwt)
|
rlm@90
|
249
|
rlm@90
|
250 (import ij.ImagePlus)
|
rlm@90
|
251
|
rlm@94
|
252
|
rlm@109
|
253
|
rlm@111
|
254 (defn test-eye []
|
rlm@117
|
255 (.getChild
|
rlm@117
|
256 (.getChild (worm-model) "eyes")
|
rlm@117
|
257 "eye"))
|
rlm@111
|
258
|
rlm@111
|
259
|
rlm@123
|
260
|
rlm@123
|
261 ;; Ears work the same way as vision.
|
rlm@123
|
262
|
rlm@123
|
263 ;; (hearing creature) will return [init-functions
|
rlm@123
|
264 ;; sensor-functions]. The init functions each take the world and
|
rlm@123
|
265 ;; register a SoundProcessor that does foureier transforms on the
|
rlm@123
|
266 ;; incommong sound data, making it available to each sensor function.
|
rlm@123
|
267
|
rlm@123
|
268 (defn creature-ears
|
rlm@128
|
269 "Return the children of the creature's \"ears\" node."
|
rlm@128
|
270 ;;dylan
|
rlm@128
|
271 ;;"The ear nodes which are children of the \"ears\" node in the
|
rlm@128
|
272 ;;creature."
|
rlm@123
|
273 [#^Node creature]
|
rlm@123
|
274 (if-let [ear-node (.getChild creature "ears")]
|
rlm@123
|
275 (seq (.getChildren ear-node))
|
rlm@123
|
276 (do (println-repl "could not find ears node") [])))
|
rlm@123
|
277
|
rlm@116
|
278
|
rlm@128
|
279 ;;dylan (defn follow-sense, adjoin-sense, attach-stimuli,
|
rlm@128
|
280 ;;anchor-qualia, augment-organ, with-organ
|
rlm@117
|
281
|
rlm@117
|
282
|
rlm@123
|
283 (defn update-listener-velocity
|
rlm@123
|
284 "Update the listener's velocity every update loop."
|
rlm@123
|
285 [#^Spatial obj #^Listener lis]
|
rlm@123
|
286 (let [old-position (atom (.getLocation lis))]
|
rlm@123
|
287 (.addControl
|
rlm@123
|
288 obj
|
rlm@123
|
289 (proxy [AbstractControl] []
|
rlm@123
|
290 (controlUpdate [tpf]
|
rlm@123
|
291 (let [new-position (.getLocation lis)]
|
rlm@123
|
292 (.setVelocity
|
rlm@123
|
293 lis
|
rlm@123
|
294 (.mult (.subtract new-position @old-position)
|
rlm@123
|
295 (float (/ tpf))))
|
rlm@123
|
296 (reset! old-position new-position)))
|
rlm@123
|
297 (controlRender [_ _])))))
|
rlm@123
|
298
|
rlm@123
|
299 (import com.aurellem.capture.audio.AudioSendRenderer)
|
rlm@123
|
300
|
rlm@123
|
301 (defn attach-ear
|
rlm@123
|
302 [#^Application world #^Node creature #^Spatial ear continuation]
|
rlm@123
|
303 (let [target (closest-node creature ear)
|
rlm@123
|
304 lis (Listener.)
|
rlm@123
|
305 audio-renderer (.getAudioRenderer world)
|
rlm@123
|
306 sp (sound-processor continuation)]
|
rlm@123
|
307 (.setLocation lis (.getWorldTranslation ear))
|
rlm@123
|
308 (.setRotation lis (.getWorldRotation ear))
|
rlm@123
|
309 (bind-sense target lis)
|
rlm@123
|
310 (update-listener-velocity target lis)
|
rlm@123
|
311 (.addListener audio-renderer lis)
|
rlm@123
|
312 (.registerSoundProcessor audio-renderer lis sp)))
|
rlm@123
|
313
|
rlm@123
|
314 (defn enable-hearing
|
rlm@123
|
315 [#^Node creature #^Spatial ear]
|
rlm@123
|
316 (let [hearing-data (atom [])]
|
rlm@123
|
317 [(fn [world]
|
rlm@123
|
318 (attach-ear world creature ear
|
rlm@123
|
319 (fn [data]
|
rlm@123
|
320 (reset! hearing-data (vec data)))))
|
rlm@123
|
321 [(fn []
|
rlm@123
|
322 (let [data @hearing-data
|
rlm@123
|
323 topology
|
rlm@123
|
324 (vec (map #(vector % 0) (range 0 (count data))))
|
rlm@123
|
325 scaled-data
|
rlm@123
|
326 (vec
|
rlm@123
|
327 (map
|
rlm@123
|
328 #(rem (int (* 255 (/ (+ 1 %) 2))) 256)
|
rlm@123
|
329 data))]
|
rlm@123
|
330 [topology scaled-data]))
|
rlm@123
|
331 ]]))
|
rlm@123
|
332
|
rlm@123
|
333 (defn hearing
|
rlm@123
|
334 [#^Node creature]
|
rlm@123
|
335 (reduce
|
rlm@123
|
336 (fn [[init-a senses-a]
|
rlm@123
|
337 [init-b senses-b]]
|
rlm@123
|
338 [(conj init-a init-b)
|
rlm@123
|
339 (into senses-a senses-b)])
|
rlm@123
|
340 [[][]]
|
rlm@123
|
341 (for [ear (creature-ears creature)]
|
rlm@123
|
342 (enable-hearing creature ear))))
|
rlm@123
|
343
|
rlm@128
|
344
|
rlm@128
|
345
|
rlm@128
|
346
|
rlm@128
|
347
|
rlm@128
|
348
|
rlm@128
|
349 ;; lower level --- nodes
|
rlm@128
|
350 ;; closest-node "parse/compile-x" -> makes organ, which is spatial, fn pair
|
rlm@128
|
351
|
rlm@128
|
352 ;; higher level -- organs
|
rlm@128
|
353 ;;
|
rlm@128
|
354
|
rlm@128
|
355 ;; higher level --- sense/effector
|
rlm@128
|
356 ;; these are the functions that provide world i/o, chinese-room style
|
rlm@128
|
357
|
rlm@128
|
358
|
rlm@134
|
359
|
rlm@116
|
360
|
rlm@116
|
361 (defn blender-creature
|
rlm@116
|
362 "Return a creature with all joints in place."
|
rlm@116
|
363 [blender-path]
|
rlm@116
|
364 (let [model (load-blender-model blender-path)
|
rlm@134
|
365 joints (creature-joints model)]
|
rlm@134
|
366 (assemble-creature model joints)))
|
rlm@116
|
367
|
rlm@126
|
368 (defn gray-scale [num]
|
rlm@126
|
369 (+ num
|
rlm@126
|
370 (bit-shift-left num 8)
|
rlm@126
|
371 (bit-shift-left num 16)))
|
rlm@126
|
372
|
rlm@130
|
373 (defn debug-touch-window
|
rlm@103
|
374 "creates function that offers a debug view of sensor data"
|
rlm@103
|
375 []
|
rlm@103
|
376 (let [vi (view-image)]
|
rlm@103
|
377 (fn
|
rlm@103
|
378 [[coords sensor-data]]
|
rlm@103
|
379 (let [image (points->image coords)]
|
rlm@103
|
380 (dorun
|
rlm@103
|
381 (for [i (range (count coords))]
|
rlm@103
|
382 (.setRGB image ((coords i) 0) ((coords i) 1)
|
rlm@126
|
383 (gray-scale (sensor-data i)))))
|
rlm@126
|
384
|
rlm@126
|
385
|
rlm@103
|
386 (vi image)))))
|
rlm@103
|
387
|
rlm@118
|
388 (defn debug-vision-window
|
rlm@118
|
389 "creates function that offers a debug view of sensor data"
|
rlm@118
|
390 []
|
rlm@118
|
391 (let [vi (view-image)]
|
rlm@118
|
392 (fn
|
rlm@118
|
393 [[coords sensor-data]]
|
rlm@118
|
394 (let [image (points->image coords)]
|
rlm@118
|
395 (dorun
|
rlm@118
|
396 (for [i (range (count coords))]
|
rlm@118
|
397 (.setRGB image ((coords i) 0) ((coords i) 1)
|
rlm@118
|
398 (sensor-data i))))
|
rlm@118
|
399 (vi image)))))
|
rlm@118
|
400
|
rlm@123
|
401 (defn debug-hearing-window
|
rlm@123
|
402 "view audio data"
|
rlm@123
|
403 [height]
|
rlm@123
|
404 (let [vi (view-image)]
|
rlm@123
|
405 (fn [[coords sensor-data]]
|
rlm@123
|
406 (let [image (BufferedImage. (count coords) height
|
rlm@123
|
407 BufferedImage/TYPE_INT_RGB)]
|
rlm@123
|
408 (dorun
|
rlm@123
|
409 (for [x (range (count coords))]
|
rlm@123
|
410 (dorun
|
rlm@123
|
411 (for [y (range height)]
|
rlm@123
|
412 (let [raw-sensor (sensor-data x)]
|
rlm@126
|
413 (.setRGB image x y (gray-scale raw-sensor)))))))
|
rlm@126
|
414
|
rlm@123
|
415 (vi image)))))
|
rlm@123
|
416
|
rlm@123
|
417
|
rlm@123
|
418
|
rlm@106
|
419 ;;(defn test-touch [world creature]
|
rlm@83
|
420
|
rlm@78
|
421
|
rlm@123
|
422
|
rlm@123
|
423
|
rlm@130
|
424 ;; here's how motor-control/ proprioception will work: Each muscle is
|
rlm@130
|
425 ;; defined by a 1-D array of numbers (the "motor pool") each of which
|
rlm@130
|
426 ;; represent muscle fibers. A muscle also has a scalar :strength
|
rlm@130
|
427 ;; factor which determines how strong the muscle as a whole is.
|
rlm@130
|
428 ;; The effector function for a muscle takes a number < (count
|
rlm@130
|
429 ;; motor-pool) and that number is said to "activate" all the muscle
|
rlm@130
|
430 ;; fibers whose index is lower than the number. Each fiber will apply
|
rlm@130
|
431 ;; force in proportion to its value in the array. Lower values cause
|
rlm@130
|
432 ;; less force. The lower values can be put at the "beginning" of the
|
rlm@130
|
433 ;; 1-D array to simulate the layout of actual human muscles, which are
|
rlm@130
|
434 ;; capable of more percise movements when exerting less force.
|
rlm@129
|
435
|
rlm@130
|
436 ;; I don't know how to encode proprioception, so for now, just return
|
rlm@130
|
437 ;; a function for each joint that returns a triplet of floats which
|
rlm@130
|
438 ;; represent relative roll, pitch, and yaw. Write display code for
|
rlm@130
|
439 ;; this though.
|
rlm@130
|
440
|
rlm@147
|
441 (defn muscle-fiber-values
|
rlm@147
|
442 "get motor pool strengths"
|
rlm@130
|
443 [#^BufferedImage image]
|
rlm@147
|
444 (vec
|
rlm@147
|
445 (let [width (.getWidth image)]
|
rlm@147
|
446 (for [x (range width)]
|
rlm@147
|
447 (- 255
|
rlm@147
|
448 (bit-and
|
rlm@147
|
449 0x0000FF
|
rlm@147
|
450 (.getRGB image x 0)))))))
|
rlm@147
|
451
|
rlm@147
|
452
|
rlm@147
|
453 (defn creature-muscles
|
rlm@147
|
454 "Return the children of the creature's \"muscles\" node."
|
rlm@147
|
455 [#^Node creature]
|
rlm@147
|
456 (if-let [muscle-node (.getChild creature "muscles")]
|
rlm@147
|
457 (seq (.getChildren muscle-node))
|
rlm@147
|
458 (do (println-repl "could not find muscles node") [])))
|
rlm@147
|
459
|
rlm@147
|
460 (defn single-muscle [#^Node parts #^Node muscle]
|
rlm@147
|
461 (let [target (closest-node parts muscle)
|
rlm@147
|
462 axis
|
rlm@147
|
463 (.mult (.getWorldRotation muscle) Vector3f/UNIT_Y)
|
rlm@147
|
464 strength (meta-data muscle "strength")
|
rlm@147
|
465 image-name (read-string (meta-data muscle "muscle"))
|
rlm@147
|
466 image
|
rlm@147
|
467 (ImageToAwt/convert
|
rlm@147
|
468 (.getImage (.loadTexture (asset-manager) image-name))
|
rlm@147
|
469 false false 0)
|
rlm@147
|
470 fibers (muscle-fiber-values image)
|
rlm@147
|
471 fiber-integral (reductions + fibers)
|
rlm@147
|
472 force-index (vec
|
rlm@147
|
473 (map
|
rlm@147
|
474 #(float (* strength (/ % (last
|
rlm@147
|
475 fiber-integral))))
|
rlm@147
|
476 fiber-integral))
|
rlm@147
|
477 control (.getControl target RigidBodyControl)]
|
rlm@147
|
478 (fn [n]
|
rlm@147
|
479 (let [pool-index (min n (count fibers))]
|
rlm@148
|
480 (.applyTorque control (.mult axis (force-index n)))))))
|
rlm@147
|
481
|
rlm@147
|
482
|
rlm@147
|
483 (defn enable-muscles
|
rlm@147
|
484 "Must be called on a creature after RigidBodyControls have been
|
rlm@147
|
485 created."
|
rlm@147
|
486 [#^Node creature]
|
rlm@147
|
487 (let [muscles (creature-muscles creature)]
|
rlm@147
|
488 (for [muscle muscles]
|
rlm@147
|
489 (single-muscle creature muscle))))
|
rlm@130
|
490
|
rlm@106
|
491 (defn test-creature [thing]
|
rlm@106
|
492 (let [x-axis
|
rlm@106
|
493 (box 1 0.01 0.01 :physical? false :color ColorRGBA/Red)
|
rlm@106
|
494 y-axis
|
rlm@106
|
495 (box 0.01 1 0.01 :physical? false :color ColorRGBA/Green)
|
rlm@106
|
496 z-axis
|
rlm@106
|
497 (box 0.01 0.01 1 :physical? false :color ColorRGBA/Blue)
|
rlm@106
|
498 creature (blender-creature thing)
|
rlm@106
|
499 touch-nerves (touch creature)
|
rlm@130
|
500 touch-debug-windows (map (fn [_] (debug-touch-window)) touch-nerves)
|
rlm@121
|
501 [init-vision-fns vision-data] (vision creature)
|
rlm@121
|
502 vision-debug (map (fn [_] (debug-vision-window)) vision-data)
|
rlm@118
|
503 me (sphere 0.5 :color ColorRGBA/Blue :physical? false)
|
rlm@123
|
504 [init-hearing-fns hearing-senses] (hearing creature)
|
rlm@123
|
505 hearing-windows (map (fn [_] (debug-hearing-window 50))
|
rlm@123
|
506 hearing-senses)
|
rlm@124
|
507 bell (AudioNode. (asset-manager)
|
rlm@128
|
508 "Sounds/pure.wav" false)
|
rlm@130
|
509 prop (proprioception creature)
|
rlm@135
|
510 prop-debug (proprioception-debug-window)
|
rlm@148
|
511
|
rlm@148
|
512 muscle-fns (enable-muscles creature)
|
rlm@123
|
513 ;; dream
|
rlm@123
|
514
|
rlm@106
|
515 ]
|
rlm@143
|
516
|
rlm@143
|
517
|
rlm@143
|
518 (apply
|
rlm@143
|
519 world
|
rlm@143
|
520 (with-movement
|
rlm@143
|
521 (.getChild creature "worm-21")
|
rlm@143
|
522 ["key-r" "key-t"
|
rlm@143
|
523 "key-f" "key-g"
|
rlm@143
|
524 "key-v" "key-b"]
|
rlm@143
|
525 [10 10 10 10 1 1]
|
rlm@143
|
526 [(nodify [creature
|
rlm@143
|
527 (box 10 2 10 :position (Vector3f. 0 -9 0)
|
rlm@143
|
528 :color ColorRGBA/Gray :mass 0)
|
rlm@143
|
529 x-axis y-axis z-axis
|
rlm@143
|
530 me
|
rlm@143
|
531 ])
|
rlm@143
|
532 (merge standard-debug-controls
|
rlm@143
|
533 {"key-return"
|
rlm@143
|
534 (fn [_ value]
|
rlm@143
|
535 (if value
|
rlm@143
|
536 (do
|
rlm@143
|
537 (println-repl "play-sound")
|
rlm@148
|
538 (.play bell))))
|
rlm@148
|
539 "key-h"
|
rlm@148
|
540 (fn [_ value]
|
rlm@148
|
541 (if value
|
rlm@148
|
542 (do
|
rlm@148
|
543 (println-repl "muscle activating!")
|
rlm@148
|
544 ((first muscle-fns) 199))))
|
rlm@148
|
545
|
rlm@148
|
546 })
|
rlm@143
|
547 (fn [world]
|
rlm@143
|
548 (light-up-everything world)
|
rlm@143
|
549 (enable-debug world)
|
rlm@143
|
550 (dorun (map #(% world) init-vision-fns))
|
rlm@143
|
551 (dorun (map #(% world) init-hearing-fns))
|
rlm@143
|
552
|
rlm@143
|
553 (add-eye world
|
rlm@143
|
554 (attach-eye creature (test-eye))
|
rlm@143
|
555 (comp (view-image) BufferedImage!))
|
rlm@143
|
556
|
rlm@143
|
557 (add-eye world (.getCamera world) no-op)
|
rlm@145
|
558 ;;(set-gravity world (Vector3f. 0 0 0))
|
rlm@143
|
559 ;;(com.aurellem.capture.Capture/captureVideo
|
rlm@143
|
560 ;; world (file-str "/home/r/proj/ai-videos/hand"))
|
rlm@143
|
561 ;;(.setTimer world (RatchetTimer. 60))
|
rlm@143
|
562 (speed-up world)
|
rlm@148
|
563 (set-gravity world (Vector3f. 0 0 0))
|
rlm@143
|
564 )
|
rlm@143
|
565 (fn [world tpf]
|
rlm@143
|
566 ;;(dorun
|
rlm@143
|
567 ;; (map #(%1 %2) touch-nerves (repeat (.getRootNode world))))
|
rlm@143
|
568
|
rlm@143
|
569 (prop-debug (prop))
|
rlm@143
|
570
|
rlm@143
|
571 (dorun
|
rlm@143
|
572 (map #(%1 (%2 (.getRootNode world)))
|
rlm@143
|
573 touch-debug-windows touch-nerves))
|
rlm@143
|
574
|
rlm@143
|
575 (dorun
|
rlm@143
|
576 (map #(%1 (%2))
|
rlm@143
|
577 vision-debug vision-data))
|
rlm@143
|
578 (dorun
|
rlm@143
|
579 (map #(%1 (%2)) hearing-windows hearing-senses))
|
rlm@143
|
580
|
rlm@143
|
581
|
rlm@143
|
582 ;;(println-repl (vision-data))
|
rlm@143
|
583 (.setLocalTranslation me (.getLocation (.getCamera world)))
|
rlm@143
|
584
|
rlm@143
|
585
|
rlm@143
|
586 )]
|
rlm@106
|
587 ;;(let [timer (atom 0)]
|
rlm@106
|
588 ;; (fn [_ _]
|
rlm@106
|
589 ;; (swap! timer inc)
|
rlm@106
|
590 ;; (if (= (rem @timer 60) 0)
|
rlm@106
|
591 ;; (println-repl (float (/ @timer 60))))))
|
rlm@143
|
592 ))))
|
rlm@83
|
593
|
rlm@109
|
594
|
rlm@116
|
595
|
rlm@116
|
596 ;; the camera will stay in its initial position/rotation with relation
|
rlm@116
|
597 ;; to the spatial.
|
rlm@116
|
598
|
rlm@116
|
599
|
rlm@117
|
600 (defn follow-test
|
rlm@117
|
601 "show a camera that stays in the same relative position to a blue cube."
|
rlm@117
|
602 []
|
rlm@116
|
603 (let [camera-pos (Vector3f. 0 30 0)
|
rlm@116
|
604 rock (box 1 1 1 :color ColorRGBA/Blue
|
rlm@116
|
605 :position (Vector3f. 0 10 0)
|
rlm@116
|
606 :mass 30
|
rlm@116
|
607 )
|
rlm@118
|
608 rot (.getWorldRotation rock)
|
rlm@116
|
609
|
rlm@116
|
610 table (box 3 1 10 :color ColorRGBA/Gray :mass 0
|
rlm@116
|
611 :position (Vector3f. 0 -3 0))]
|
rlm@116
|
612
|
rlm@116
|
613 (world
|
rlm@116
|
614 (nodify [rock table])
|
rlm@116
|
615 standard-debug-controls
|
rlm@116
|
616 (fn [world]
|
rlm@116
|
617 (let
|
rlm@116
|
618 [cam (doto (.clone (.getCamera world))
|
rlm@116
|
619 (.setLocation camera-pos)
|
rlm@116
|
620 (.lookAt Vector3f/ZERO
|
rlm@116
|
621 Vector3f/UNIT_X))]
|
rlm@123
|
622 (bind-sense rock cam)
|
rlm@116
|
623
|
rlm@116
|
624 (.setTimer world (RatchetTimer. 60))
|
rlm@116
|
625 (add-eye world cam (comp (view-image) BufferedImage!))
|
rlm@116
|
626 (add-eye world (.getCamera world) no-op))
|
rlm@116
|
627 )
|
rlm@118
|
628 (fn [_ _] (println-repl rot)))))
|
rlm@116
|
629
|
rlm@118
|
630
|
rlm@123
|
631
|
rlm@87
|
632 #+end_src
|
rlm@83
|
633
|
rlm@87
|
634 #+results: body-1
|
rlm@133
|
635 : #'cortex.silly/follow-test
|
rlm@78
|
636
|
rlm@78
|
637
|
rlm@78
|
638 * COMMENT purgatory
|
rlm@78
|
639 #+begin_src clojure
|
rlm@74
|
640
|
rlm@77
|
641 (defn bullet-trans* []
|
rlm@77
|
642 (let [obj-a (box 1.5 0.5 0.5 :color ColorRGBA/Red
|
rlm@77
|
643 :position (Vector3f. 5 0 0)
|
rlm@77
|
644 :mass 90)
|
rlm@77
|
645 obj-b (sphere 0.5 :color ColorRGBA/Blue
|
rlm@77
|
646 :position (Vector3f. -5 0 0)
|
rlm@77
|
647 :mass 0)
|
rlm@77
|
648 control-a (.getControl obj-a RigidBodyControl)
|
rlm@77
|
649 control-b (.getControl obj-b RigidBodyControl)
|
rlm@77
|
650 move-up? (atom nil)
|
rlm@77
|
651 move-down? (atom nil)
|
rlm@77
|
652 move-left? (atom nil)
|
rlm@77
|
653 move-right? (atom nil)
|
rlm@77
|
654 roll-left? (atom nil)
|
rlm@77
|
655 roll-right? (atom nil)
|
rlm@77
|
656 force 100
|
rlm@77
|
657 swivel
|
rlm@77
|
658 (.toRotationMatrix
|
rlm@77
|
659 (doto (Quaternion.)
|
rlm@77
|
660 (.fromAngleAxis (/ Math/PI 2)
|
rlm@77
|
661 Vector3f/UNIT_X)))
|
rlm@77
|
662 x-move
|
rlm@77
|
663 (doto (Matrix3f.)
|
rlm@77
|
664 (.fromStartEndVectors Vector3f/UNIT_X
|
rlm@77
|
665 (.normalize (Vector3f. 1 1 0))))
|
rlm@77
|
666
|
rlm@77
|
667 timer (atom 0)]
|
rlm@77
|
668 (doto
|
rlm@77
|
669 (ConeJoint.
|
rlm@77
|
670 control-a control-b
|
rlm@77
|
671 (Vector3f. -8 0 0)
|
rlm@77
|
672 (Vector3f. 2 0 0)
|
rlm@77
|
673 ;;swivel swivel
|
rlm@77
|
674 ;;Matrix3f/IDENTITY Matrix3f/IDENTITY
|
rlm@77
|
675 x-move Matrix3f/IDENTITY
|
rlm@77
|
676 )
|
rlm@77
|
677 (.setCollisionBetweenLinkedBodys false)
|
rlm@77
|
678 (.setLimit (* 1 (/ Math/PI 4)) ;; twist
|
rlm@77
|
679 (* 1 (/ Math/PI 4)) ;; swing span in X-Y plane
|
rlm@77
|
680 (* 0 (/ Math/PI 4)))) ;; swing span in Y-Z plane
|
rlm@77
|
681 (world (nodify
|
rlm@77
|
682 [obj-a obj-b])
|
rlm@77
|
683 (merge standard-debug-controls
|
rlm@77
|
684 {"key-r" (fn [_ pressed?] (reset! move-up? pressed?))
|
rlm@77
|
685 "key-t" (fn [_ pressed?] (reset! move-down? pressed?))
|
rlm@77
|
686 "key-f" (fn [_ pressed?] (reset! move-left? pressed?))
|
rlm@77
|
687 "key-g" (fn [_ pressed?] (reset! move-right? pressed?))
|
rlm@77
|
688 "key-v" (fn [_ pressed?] (reset! roll-left? pressed?))
|
rlm@77
|
689 "key-b" (fn [_ pressed?] (reset! roll-right? pressed?))})
|
rlm@77
|
690
|
rlm@77
|
691 (fn [world]
|
rlm@77
|
692 (enable-debug world)
|
rlm@77
|
693 (set-gravity world Vector3f/ZERO)
|
rlm@77
|
694 )
|
rlm@77
|
695
|
rlm@77
|
696 (fn [world _]
|
rlm@77
|
697
|
rlm@77
|
698 (if @move-up?
|
rlm@77
|
699 (.applyForce control-a
|
rlm@77
|
700 (Vector3f. force 0 0)
|
rlm@77
|
701 (Vector3f. 0 0 0)))
|
rlm@77
|
702 (if @move-down?
|
rlm@77
|
703 (.applyForce control-a
|
rlm@77
|
704 (Vector3f. (- force) 0 0)
|
rlm@77
|
705 (Vector3f. 0 0 0)))
|
rlm@77
|
706 (if @move-left?
|
rlm@77
|
707 (.applyForce control-a
|
rlm@77
|
708 (Vector3f. 0 force 0)
|
rlm@77
|
709 (Vector3f. 0 0 0)))
|
rlm@77
|
710 (if @move-right?
|
rlm@77
|
711 (.applyForce control-a
|
rlm@77
|
712 (Vector3f. 0 (- force) 0)
|
rlm@77
|
713 (Vector3f. 0 0 0)))
|
rlm@77
|
714
|
rlm@77
|
715 (if @roll-left?
|
rlm@77
|
716 (.applyForce control-a
|
rlm@77
|
717 (Vector3f. 0 0 force)
|
rlm@77
|
718 (Vector3f. 0 0 0)))
|
rlm@77
|
719 (if @roll-right?
|
rlm@77
|
720 (.applyForce control-a
|
rlm@77
|
721 (Vector3f. 0 0 (- force))
|
rlm@77
|
722 (Vector3f. 0 0 0)))
|
rlm@77
|
723
|
rlm@77
|
724 (if (zero? (rem (swap! timer inc) 100))
|
rlm@77
|
725 (.attachChild
|
rlm@77
|
726 (.getRootNode world)
|
rlm@77
|
727 (sphere 0.05 :color ColorRGBA/Yellow
|
rlm@77
|
728 :physical? false :position
|
rlm@77
|
729 (.getWorldTranslation obj-a)))))
|
rlm@77
|
730 )
|
rlm@77
|
731 ))
|
rlm@77
|
732
|
rlm@106
|
733 (defn test-joint [joint]
|
rlm@106
|
734 (let [[origin top bottom floor] (world-setup joint)
|
rlm@106
|
735 control (.getControl top RigidBodyControl)
|
rlm@106
|
736 move-up? (atom false)
|
rlm@106
|
737 move-down? (atom false)
|
rlm@106
|
738 move-left? (atom false)
|
rlm@106
|
739 move-right? (atom false)
|
rlm@106
|
740 roll-left? (atom false)
|
rlm@106
|
741 roll-right? (atom false)
|
rlm@106
|
742 timer (atom 0)]
|
rlm@106
|
743
|
rlm@106
|
744 (world
|
rlm@106
|
745 (nodify [top bottom floor origin])
|
rlm@106
|
746 (merge standard-debug-controls
|
rlm@106
|
747 {"key-r" (fn [_ pressed?] (reset! move-up? pressed?))
|
rlm@106
|
748 "key-t" (fn [_ pressed?] (reset! move-down? pressed?))
|
rlm@106
|
749 "key-f" (fn [_ pressed?] (reset! move-left? pressed?))
|
rlm@106
|
750 "key-g" (fn [_ pressed?] (reset! move-right? pressed?))
|
rlm@106
|
751 "key-v" (fn [_ pressed?] (reset! roll-left? pressed?))
|
rlm@106
|
752 "key-b" (fn [_ pressed?] (reset! roll-right? pressed?))})
|
rlm@106
|
753
|
rlm@106
|
754 (fn [world]
|
rlm@106
|
755 (light-up-everything world)
|
rlm@106
|
756 (enable-debug world)
|
rlm@106
|
757 (set-gravity world (Vector3f. 0 0 0))
|
rlm@106
|
758 )
|
rlm@106
|
759
|
rlm@106
|
760 (fn [world _]
|
rlm@106
|
761 (if (zero? (rem (swap! timer inc) 100))
|
rlm@106
|
762 (do
|
rlm@106
|
763 ;; (println-repl @timer)
|
rlm@106
|
764 (.attachChild (.getRootNode world)
|
rlm@106
|
765 (sphere 0.05 :color ColorRGBA/Yellow
|
rlm@106
|
766 :position (.getWorldTranslation top)
|
rlm@106
|
767 :physical? false))
|
rlm@106
|
768 (.attachChild (.getRootNode world)
|
rlm@106
|
769 (sphere 0.05 :color ColorRGBA/LightGray
|
rlm@106
|
770 :position (.getWorldTranslation bottom)
|
rlm@106
|
771 :physical? false))))
|
rlm@106
|
772
|
rlm@106
|
773 (if @move-up?
|
rlm@106
|
774 (.applyTorque control
|
rlm@106
|
775 (.mult (.getPhysicsRotation control)
|
rlm@106
|
776 (Vector3f. 0 0 10))))
|
rlm@106
|
777 (if @move-down?
|
rlm@106
|
778 (.applyTorque control
|
rlm@106
|
779 (.mult (.getPhysicsRotation control)
|
rlm@106
|
780 (Vector3f. 0 0 -10))))
|
rlm@106
|
781 (if @move-left?
|
rlm@106
|
782 (.applyTorque control
|
rlm@106
|
783 (.mult (.getPhysicsRotation control)
|
rlm@106
|
784 (Vector3f. 0 10 0))))
|
rlm@106
|
785 (if @move-right?
|
rlm@106
|
786 (.applyTorque control
|
rlm@106
|
787 (.mult (.getPhysicsRotation control)
|
rlm@106
|
788 (Vector3f. 0 -10 0))))
|
rlm@106
|
789 (if @roll-left?
|
rlm@106
|
790 (.applyTorque control
|
rlm@106
|
791 (.mult (.getPhysicsRotation control)
|
rlm@106
|
792 (Vector3f. -1 0 0))))
|
rlm@106
|
793 (if @roll-right?
|
rlm@106
|
794 (.applyTorque control
|
rlm@106
|
795 (.mult (.getPhysicsRotation control)
|
rlm@106
|
796 (Vector3f. 1 0 0))))))))
|
rlm@99
|
797 #+end_src
|
rlm@99
|
798
|
rlm@99
|
799
|
rlm@99
|
800 * COMMENT generate source
|
rlm@99
|
801 #+begin_src clojure :tangle ../src/cortex/silly.clj
|
rlm@99
|
802 <<body-1>>
|
rlm@99
|
803 #+end_src
|
rlm@99
|
804
|
rlm@99
|
805
|
rlm@94
|
806
|
rlm@94
|
807
|