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