rlm@23
|
1 #+title: Eyes
|
rlm@23
|
2 #+author: Robert McIntyre
|
rlm@23
|
3 #+email: rlm@mit.edu
|
rlm@23
|
4 #+description: Simulating senses for AI research using JMonkeyEngine3
|
rlm@23
|
5 #+SETUPFILE: ../../aurellem/org/setup.org
|
rlm@23
|
6 #+INCLUDE: ../../aurellem/org/level-0.org
|
rlm@23
|
7 #+babel: :mkdirp yes :noweb yes :exports both
|
rlm@23
|
8
|
rlm@23
|
9
|
rlm@23
|
10
|
rlm@23
|
11 ** Eyes
|
rlm@23
|
12
|
rlm@23
|
13 Ultimately I want to make creatures with eyes. Each eye can be
|
rlm@23
|
14 independely moved and should see its own version of the world
|
rlm@23
|
15 depending on where it is.
|
rlm@23
|
16 #+srcname: eyes
|
rlm@23
|
17 #+begin_src clojure
|
rlm@23
|
18 (ns body.eye)
|
rlm@23
|
19 (use 'cortex.world)
|
rlm@23
|
20 (use 'cortex.import)
|
rlm@23
|
21 (use 'clojure.contrib.def)
|
rlm@23
|
22 (cortex.import/mega-import-jme3)
|
rlm@23
|
23 (rlm.rlm-commands/help)
|
rlm@23
|
24 (import java.nio.ByteBuffer)
|
rlm@23
|
25 (import java.awt.image.BufferedImage)
|
rlm@23
|
26 (import java.awt.Color)
|
rlm@23
|
27 (import java.awt.Dimension)
|
rlm@23
|
28 (import java.awt.Graphics)
|
rlm@23
|
29 (import java.awt.Graphics2D)
|
rlm@23
|
30 (import java.awt.event.WindowAdapter)
|
rlm@23
|
31 (import java.awt.event.WindowEvent)
|
rlm@23
|
32 (import java.awt.image.BufferedImage)
|
rlm@23
|
33 (import java.nio.ByteBuffer)
|
rlm@23
|
34 (import javax.swing.JFrame)
|
rlm@23
|
35 (import javax.swing.JPanel)
|
rlm@23
|
36 (import javax.swing.SwingUtilities)
|
rlm@23
|
37 (import javax.swing.ImageIcon)
|
rlm@23
|
38 (import javax.swing.JOptionPane)
|
rlm@23
|
39 (import java.awt.image.ImageObserver)
|
rlm@23
|
40
|
rlm@23
|
41
|
rlm@23
|
42
|
rlm@23
|
43 (defn scene-processor
|
rlm@23
|
44 "deals with converting FrameBuffers to BufferedImages so
|
rlm@23
|
45 that the continuation function can be defined only in terms
|
rlm@23
|
46 of what it does with BufferedImages"
|
rlm@23
|
47 [continuation]
|
rlm@23
|
48 (let [byte-buffer (atom nil)
|
rlm@23
|
49 renderer (atom nil)
|
rlm@23
|
50 image (atom nil)]
|
rlm@23
|
51 (proxy [SceneProcessor] []
|
rlm@23
|
52 (initialize
|
rlm@23
|
53 [renderManager viewPort]
|
rlm@23
|
54 (let [cam (.getCamera viewPort)
|
rlm@23
|
55 width (.getWidth cam)
|
rlm@23
|
56 height (.getHeight cam)]
|
rlm@23
|
57 (reset! renderer (.getRenderer renderManager))
|
rlm@23
|
58 (reset! byte-buffer
|
rlm@23
|
59 (BufferUtils/createByteBuffer
|
rlm@23
|
60 (* width height 4)))
|
rlm@23
|
61 (reset! image (BufferedImage. width height
|
rlm@23
|
62 BufferedImage/TYPE_4BYTE_ABGR))))
|
rlm@23
|
63 (isInitialized [] (not (nil? @byte-buffer)))
|
rlm@23
|
64 (reshape [_ _ _])
|
rlm@23
|
65 (preFrame [_])
|
rlm@23
|
66 (postQueue [_])
|
rlm@23
|
67 (postFrame
|
rlm@23
|
68 [#^FrameBuffer fb]
|
rlm@23
|
69 (.clear @byte-buffer)
|
rlm@23
|
70 (.readFrameBuffer @renderer fb @byte-buffer)
|
rlm@23
|
71 (Screenshots/convertScreenShot @byte-buffer @image)
|
rlm@23
|
72 (continuation @image))
|
rlm@23
|
73 (cleanup []))))
|
rlm@23
|
74
|
rlm@23
|
75 (defn add-eye
|
rlm@23
|
76 "Add an eye to the world, and call continuation on
|
rlm@23
|
77 every frame produced"
|
rlm@23
|
78 [world camera continuation]
|
rlm@23
|
79 (let [width (.getWidth camera)
|
rlm@23
|
80 height (.getHeight camera)
|
rlm@23
|
81 render-manager (.getRenderManager world)
|
rlm@23
|
82 viewport (.createMainView render-manager "eye-view" camera)]
|
rlm@23
|
83 (doto viewport
|
rlm@23
|
84 (.setBackgroundColor ColorRGBA/Black)
|
rlm@23
|
85 (.setClearFlags true true true)
|
rlm@23
|
86 (.addProcessor (scene-processor continuation))
|
rlm@23
|
87 (.attachScene (.getRootNode world)))))
|
rlm@23
|
88
|
rlm@23
|
89 (defn make-display-frame [display width height]
|
rlm@23
|
90 (SwingUtilities/invokeLater
|
rlm@23
|
91 (fn []
|
rlm@23
|
92 (.setPreferredSize display (Dimension. width height))
|
rlm@23
|
93 (doto (JFrame. "Eye Camera!")
|
rlm@23
|
94 (-> (.getContentPane) (.add display))
|
rlm@23
|
95 (.setDefaultCloseOperation JFrame/DISPOSE_ON_CLOSE)
|
rlm@23
|
96 (.pack)
|
rlm@23
|
97 (.setLocationRelativeTo nil)
|
rlm@23
|
98 (.setResizable false)
|
rlm@23
|
99 (.setVisible true)))))
|
rlm@23
|
100
|
rlm@23
|
101 (defn image-monitor [#^BufferedImage image]
|
rlm@23
|
102 (proxy [JPanel] []
|
rlm@23
|
103 (paintComponent
|
rlm@23
|
104 [g]
|
rlm@23
|
105 (proxy-super paintComponent g)
|
rlm@23
|
106 (locking image
|
rlm@23
|
107 (.drawImage g image 0 0
|
rlm@23
|
108 (proxy [ImageObserver]
|
rlm@23
|
109 []
|
rlm@23
|
110 (imageUpdate
|
rlm@23
|
111 []
|
rlm@23
|
112 (proxy-super imageUpdate))))))))
|
rlm@23
|
113
|
rlm@23
|
114 (defn movie-image []
|
rlm@23
|
115 (let [setup
|
rlm@23
|
116 (runonce
|
rlm@23
|
117 (fn [#^BufferedImage image]
|
rlm@23
|
118 (let [width (.getWidth image)
|
rlm@23
|
119 height (.getHeight image)
|
rlm@23
|
120 display (image-monitor image)
|
rlm@23
|
121 frame (make-display-frame display width height)]
|
rlm@23
|
122 display)))]
|
rlm@23
|
123 (fn [#^BufferedImage image]
|
rlm@23
|
124 (.repaint (setup image)))))
|
rlm@23
|
125
|
rlm@23
|
126
|
rlm@23
|
127 (defn observer
|
rlm@23
|
128 "place thy eye!"
|
rlm@23
|
129 [world camera]
|
rlm@23
|
130 (let [eye camera
|
rlm@23
|
131 width (.getWidth eye)
|
rlm@23
|
132 height (.getHeight eye)]
|
rlm@23
|
133 (no-exceptions
|
rlm@23
|
134 (add-eye
|
rlm@23
|
135 world
|
rlm@23
|
136 eye
|
rlm@23
|
137 (movie-image)))))
|
rlm@23
|
138 #+end_src
|
rlm@23
|
139
|
rlm@23
|
140 #+srcname: test-vision
|
rlm@23
|
141 #+begin_src clojure
|
rlm@23
|
142
|
rlm@23
|
143 (ns test.vision)
|
rlm@23
|
144 (use 'cortex.world)
|
rlm@23
|
145 (use 'cortex.import)
|
rlm@23
|
146 (use 'clojure.contrib.def)
|
rlm@23
|
147 (use 'body.eye)
|
rlm@23
|
148 (cortex.import/mega-import-jme3)
|
rlm@23
|
149 (rlm.rlm-commands/help)
|
rlm@23
|
150 (import java.nio.ByteBuffer)
|
rlm@23
|
151 (import java.awt.image.BufferedImage)
|
rlm@23
|
152 (import java.awt.Color)
|
rlm@23
|
153 (import java.awt.Dimension)
|
rlm@23
|
154 (import java.awt.Graphics)
|
rlm@23
|
155 (import java.awt.Graphics2D)
|
rlm@23
|
156 (import java.awt.event.WindowAdapter)
|
rlm@23
|
157 (import java.awt.event.WindowEvent)
|
rlm@23
|
158 (import java.awt.image.BufferedImage)
|
rlm@23
|
159 (import java.nio.ByteBuffer)
|
rlm@23
|
160 (import javax.swing.JFrame)
|
rlm@23
|
161 (import javax.swing.JPanel)
|
rlm@23
|
162 (import javax.swing.SwingUtilities)
|
rlm@23
|
163 (import javax.swing.ImageIcon)
|
rlm@23
|
164 (import javax.swing.JOptionPane)
|
rlm@23
|
165 (import java.awt.image.ImageObserver)
|
rlm@23
|
166
|
rlm@23
|
167
|
rlm@23
|
168 (def width 200)
|
rlm@23
|
169 (def height 200)
|
rlm@23
|
170
|
rlm@23
|
171 (defn camera []
|
rlm@23
|
172 (doto (Camera. width height)
|
rlm@23
|
173 (.setFrustumPerspective 45 1 1 1000)
|
rlm@23
|
174 (.setLocation (Vector3f. -3 0 -5))
|
rlm@23
|
175 (.lookAt Vector3f/ZERO Vector3f/UNIT_Y)))
|
rlm@23
|
176
|
rlm@23
|
177 (defn camera2 []
|
rlm@23
|
178 (doto (Camera. width height)
|
rlm@23
|
179 (.setFrustumPerspective 45 1 1 1000)
|
rlm@23
|
180 (.setLocation (Vector3f. 3 0 -5))
|
rlm@23
|
181 (.lookAt Vector3f/ZERO Vector3f/UNIT_Y)))
|
rlm@23
|
182
|
rlm@23
|
183 (defn setup-fn [world]
|
rlm@23
|
184 (let [eye (camera)
|
rlm@23
|
185 width (.getWidth eye)
|
rlm@23
|
186 height (.getHeight eye)]
|
rlm@23
|
187 (no-exceptions
|
rlm@23
|
188 (add-eye
|
rlm@23
|
189 world
|
rlm@23
|
190 eye
|
rlm@23
|
191 (runonce visual))
|
rlm@23
|
192 (add-eye
|
rlm@23
|
193 world
|
rlm@23
|
194 (camera2)
|
rlm@23
|
195 (runonce visual)))))
|
rlm@23
|
196
|
rlm@23
|
197 (defn spider-eye [position]
|
rlm@23
|
198 (doto (Camera. 200 200 )
|
rlm@23
|
199 (.setFrustumPerspective 45 1 1 1000)
|
rlm@23
|
200 (.setLocation position)
|
rlm@23
|
201 (.lookAt Vector3f/ZERO Vector3f/UNIT_Y)))
|
rlm@23
|
202
|
rlm@23
|
203 (defn setup-fn* [world]
|
rlm@23
|
204 (let [eye (camera)
|
rlm@23
|
205 width (.getWidth eye)
|
rlm@23
|
206 height (.getHeight eye)]
|
rlm@23
|
207 ;;(.setClearFlags (.getViewPort world) true true true)
|
rlm@23
|
208 (observer world (.getCamera world))
|
rlm@23
|
209 (observer world (spider-eye (Vector3f. 3 0 -5)))
|
rlm@23
|
210 ;;(observer world (spider-eye (Vector3f. 0 0 -5)))
|
rlm@23
|
211 ;; (observer world (spider-eye (Vector3f. -3 0 -5)))
|
rlm@23
|
212 ;; (observer world (spider-eye (Vector3f. 0 3 -5)))
|
rlm@23
|
213 ;; (observer world (spider-eye (Vector3f. 0 -3 -5)))
|
rlm@23
|
214 ;; (observer world (spider-eye (Vector3f. 3 3 -5)))
|
rlm@23
|
215 ;; (observer world (spider-eye (Vector3f. -3 3 -5)))
|
rlm@23
|
216 ;; (observer world (spider-eye (Vector3f. 3 -3 -5)))
|
rlm@23
|
217 ;; (observer world (spider-eye (Vector3f. -3 -3 -5)))
|
rlm@23
|
218
|
rlm@23
|
219 )
|
rlm@23
|
220 world)
|
rlm@23
|
221
|
rlm@23
|
222 (defn test-world []
|
rlm@23
|
223 (let [thing (box 1 1 1 :physical? false)]
|
rlm@23
|
224 (world
|
rlm@23
|
225 (doto (Node.)
|
rlm@23
|
226 (.attachChild thing))
|
rlm@23
|
227 {}
|
rlm@23
|
228 setup-fn
|
rlm@23
|
229 (fn [world tpf]
|
rlm@23
|
230 (.rotate thing (* tpf 0.2) 0 0)
|
rlm@23
|
231 ))))
|
rlm@23
|
232
|
rlm@23
|
233
|
rlm@23
|
234 #+end_src
|
rlm@23
|
235
|
rlm@23
|
236
|
rlm@23
|
237 #+results: eyes
|
rlm@23
|
238 : #'body.eye/test-world
|
rlm@23
|
239
|
rlm@23
|
240 Note the use of continuation passing style for connecting the eye to a
|
rlm@23
|
241 function to process the output. The example code will create two
|
rlm@23
|
242 videos of the same rotating cube from different angles, sutiable for
|
rlm@23
|
243 stereoscopic vision.
|
rlm@24
|
244
|
rlm@24
|
245
|
rlm@24
|
246
|
rlm@24
|
247 * COMMENT code generation
|
rlm@24
|
248 #+begin_src clojure :tangle ../src/body/eye.clj
|
rlm@24
|
249 <<eyes>>
|
rlm@24
|
250 #+end_src
|
rlm@24
|
251
|
rlm@24
|
252 #+begin_src clojure :tangle ../src/test/vision.clj
|
rlm@24
|
253 <<test-vision>>
|
rlm@24
|
254 #+end_src
|