OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 import "dart:math" as Math; | |
6 import "android_extension.dart"; | |
7 | |
8 const FRAGMENT_PROGRAM = """ | |
9 precision mediump float; | |
10 | |
11 const vec3 lightDir = vec3(0.577350269, 0.577350269, -0.577350269); | |
12 varying vec3 vPosition; | |
13 uniform vec3 cameraPos; | |
14 uniform vec3 sphere1Center; | |
15 uniform vec3 sphere2Center; | |
16 uniform vec3 sphere3Center; | |
17 | |
18 bool intersectSphere(vec3 center, vec3 lStart, vec3 lDir, | |
19 out float dist) { | |
20 vec3 c = center - lStart; | |
21 float b = dot(lDir, c); | |
22 float d = b*b - dot(c, c) + 1.0; | |
23 if (d < 0.0) { | |
24 dist = 10000.0; | |
25 return false; | |
26 } | |
27 | |
28 dist = b - sqrt(d); | |
29 if (dist < 0.0) { | |
30 dist = 10000.0; | |
31 return false; | |
32 } | |
33 | |
34 return true; | |
35 } | |
36 | |
37 vec3 lightAt(vec3 N, vec3 V, vec3 color) { | |
38 vec3 L = lightDir; | |
39 vec3 R = reflect(-L, N); | |
40 | |
41 float c = 0.3 + 0.4 * pow(max(dot(R, V), 0.0), 30.0) + 0.7 * dot(L, N); | |
42 | |
43 if (c > 1.0) { | |
44 return mix(color, vec3(1.6, 1.6, 1.6), c - 1.0); | |
45 } | |
46 | |
47 return c * color; | |
48 } | |
49 | |
50 bool intersectWorld(vec3 lStart, vec3 lDir, out vec3 pos, | |
51 out vec3 normal, out vec3 color) { | |
52 float d1, d2, d3; | |
53 bool h1, h2, h3; | |
54 | |
55 h1 = intersectSphere(sphere1Center, lStart, lDir, d1); | |
56 h2 = intersectSphere(sphere2Center, lStart, lDir, d2); | |
57 h3 = intersectSphere(sphere3Center, lStart, lDir, d3); | |
58 | |
59 if (h1 && d1 < d2 && d1 < d3) { | |
60 pos = lStart + d1 * lDir; | |
61 normal = pos - sphere1Center; | |
62 color = vec3(0.0, 0.0, 0.9); | |
63 if (fract(pos.x / 1.5) > 0.5 ^^ | |
64 fract(pos.y / 1.5) > 0.5 ^^ | |
65 fract(pos.z / 1.5) > 0.5) { | |
66 color = vec3(1.0, 0.0, 1.0); | |
67 } | |
68 else { | |
69 color = vec3(1.0, 1.0, 0.0); | |
70 } | |
71 } | |
72 else if (h2 && d2 < d3) { | |
73 pos = lStart + d2 * lDir; | |
74 normal = pos - sphere2Center; | |
75 color = vec3(0.9, mod(normal.y * 2.5, 1.0), 0.0); | |
76 } | |
77 else if (h3) { | |
78 pos = lStart + d3 * lDir; | |
79 normal = pos - sphere3Center; | |
80 color = vec3(0.0, clamp(sphere3Center.y/1.5, 0.0, 0.9), | |
81 clamp(0.9 - sphere3Center.y/1.5, 0.0, 0.9)); | |
82 } | |
83 else if (lDir.y < -0.01) { | |
84 pos = lStart + ((lStart.y + 2.7) / -lDir.y) * lDir; | |
85 if (pos.x*pos.x + pos.z*pos.z > 30.0) { | |
86 return false; | |
87 } | |
88 normal = vec3(0.0, 1.0, 0.0); | |
89 if (fract(pos.x / 5.0) > 0.5 == fract(pos.z / 5.0) > 0.5) { | |
90 color = vec3(1.0); | |
91 } | |
92 else { | |
93 color = vec3(0.0); | |
94 } | |
95 } | |
96 else { | |
97 return false; | |
98 } | |
99 | |
100 return true; | |
101 } | |
102 | |
103 void main(void) | |
104 { | |
105 vec3 cameraDir = normalize(vPosition - cameraPos); | |
106 | |
107 vec3 p1, norm, p2; | |
108 vec3 col, colT, colM, col3; | |
109 if (intersectWorld(cameraPos, cameraDir, p1, | |
110 norm, colT)) { | |
111 col = lightAt(norm, -cameraDir, colT); | |
112 colM = (colT + vec3(0.2)) / 1.2; | |
113 cameraDir = reflect(cameraDir, norm); | |
114 if (intersectWorld(p1, cameraDir, p2, norm, colT)) { | |
115 col += lightAt(norm, -cameraDir, colT) * colM; | |
116 colM *= (colT + vec3(0.2)) / 1.2; | |
117 cameraDir = reflect(cameraDir, norm); | |
118 if (intersectWorld(p2, cameraDir, p1, norm, colT)) { | |
119 col += lightAt(norm, -cameraDir, colT) * colM; | |
120 } | |
121 } | |
122 | |
123 gl_FragColor = vec4(col, 1.0); | |
124 } | |
125 else { | |
126 gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); | |
127 } | |
128 } | |
129 """; | |
130 | |
131 const VERTEX_PROGRAM = """ | |
132 attribute vec2 aVertexPosition; | |
133 attribute vec3 aPlotPosition; | |
134 | |
135 varying vec3 vPosition; | |
136 | |
137 void main(void) | |
138 { | |
139 gl_Position = vec4(aVertexPosition, 1.0, 1.0); | |
140 vPosition = aPlotPosition; | |
141 } | |
142 """; | |
143 | |
144 loadShader(final type, final program) { | |
145 final shader = gl.createShader(type); | |
146 gl.shaderSource(shader, program); | |
147 gl.compileShader(shader); | |
148 if (gl.getShaderParameter(shader, WebGLRenderingContext.COMPILE_STATUS) | |
149 != WebGLRenderingContext.TRUE) { | |
150 log("Could not compile shader: ${gl.getShaderInfoLog(shader)}"); | |
151 throw new Exception("Could not compile shader"); | |
152 } | |
153 | |
154 return shader; | |
155 } | |
156 | |
157 var shaderProgram; | |
158 var aVertexPosition; | |
159 var aPlotPosition; | |
160 var cameraPos; | |
161 var sphere1Center; | |
162 var sphere2Center; | |
163 var sphere3Center; | |
164 var ratio; | |
165 | |
166 initShaders() { | |
167 var vertexShader = loadShader(WebGLRenderingContext.VERTEX_SHADER, | |
168 VERTEX_PROGRAM); | |
169 var fragmentShader = loadShader(WebGLRenderingContext.FRAGMENT_SHADER, | |
170 FRAGMENT_PROGRAM); | |
171 | |
172 shaderProgram = gl.createProgram(); | |
173 if (shaderProgram == 0) { | |
174 throw new Exception("Could not create program."); | |
175 } | |
176 | |
177 gl.attachShader(shaderProgram, vertexShader); | |
178 gl.attachShader(shaderProgram, fragmentShader); | |
179 gl.linkProgram(shaderProgram); | |
180 | |
181 if (gl.getProgramParameter(shaderProgram, WebGLRenderingContext.LINK_STATUS) | |
182 != WebGLRenderingContext.TRUE) { | |
183 log("Could not link program: ${gl.getProgramInfoLog(shaderProgram)}"); | |
184 throw new Exception("Could not initialize shaders"); | |
185 } | |
186 | |
187 gl.useProgram(shaderProgram); | |
188 | |
189 aVertexPosition = gl.getAttribLocation(shaderProgram, "aVertexPosition"); | |
190 gl.enableVertexAttribArray(aVertexPosition); | |
191 | |
192 aPlotPosition = gl.getAttribLocation(shaderProgram, "aPlotPosition"); | |
193 gl.enableVertexAttribArray(aPlotPosition); | |
194 | |
195 cameraPos = gl.getUniformLocation(shaderProgram, "cameraPos"); | |
196 sphere1Center = gl.getUniformLocation(shaderProgram, "sphere1Center"); | |
197 sphere2Center = gl.getUniformLocation(shaderProgram, "sphere2Center"); | |
198 sphere3Center = gl.getUniformLocation(shaderProgram, "sphere3Center"); | |
199 } | |
200 | |
201 initBuffers() { | |
202 var vertexPositionBuffer = gl.createBuffer(); | |
203 gl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, vertexPositionBuffer); | |
204 var vertices = [ | |
205 1.0, 1.0, | |
206 -1.0, 1.0, | |
207 1.0, -1.0, | |
208 -1.0, -1.0, | |
209 ]; | |
210 | |
211 gl.bufferData(WebGLRenderingContext.ARRAY_BUFFER, vertices, | |
vsm
2012/11/30 17:00:30
Can you add a TODO above this line that vertices s
gram
2012/11/30 18:01:31
Done.
| |
212 WebGLRenderingContext.STATIC_DRAW); | |
213 gl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, vertexPositionBuffer); | |
214 gl.vertexAttribPointer(aVertexPosition, 2, WebGLRenderingContext.FLOAT, | |
215 false,0, 0); | |
216 | |
217 var plotPositionBuffer = gl.createBuffer(); | |
218 gl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, plotPositionBuffer); | |
219 gl.vertexAttribPointer(aPlotPosition, 3, WebGLRenderingContext.FLOAT, | |
220 false, 0, 0); | |
221 } | |
222 | |
223 class Vector { | |
224 var x; | |
225 var y; | |
226 var z; | |
227 Vector(this.x, this.y, this.z); | |
228 } | |
Cutch
2012/11/30 17:04:58
You should be using vector_math instead of impleme
gram
2012/11/30 18:01:31
I'll just add a TODO. This is a throwaway example
| |
229 | |
230 crossProd(v1, v2) { | |
231 return | |
232 new Vector( | |
233 v1.y*v2.z - v2.y*v1.z, | |
234 v1.z*v2.x - v2.z*v1.x, | |
235 v1.x*v2.y - v2.x*v1.y); | |
236 } | |
237 | |
238 normalize(v) { | |
239 var l = Math.sqrt(v.x*v.x + v.y*v.y + v.z*v.z); | |
240 return new Vector( v.x/l, v.y/l, v.z/l ); | |
241 } | |
242 | |
243 vectAdd(v1, v2) { | |
244 return new Vector( v1.x + v2.x, v1.y + v2.y, v1.z + v2.z ); | |
245 } | |
246 | |
247 vectSub(v1, v2) { | |
248 return new Vector( v1.x - v2.x, v1.y - v2.y, v1.z - v2.z ); | |
249 } | |
250 | |
251 vectMul(v, l) { | |
252 return new Vector( v.x*l, v.y*l, v.z*l ); | |
253 } | |
254 | |
255 pushVec(v, arr) { | |
256 arr.addAll([v.x, v.y, v.z]); | |
257 } | |
258 | |
259 var t = 0; | |
260 int width, height; | |
261 | |
262 drawScene() { | |
263 var x1 = Math.sin(t * 1.1) * 1.5; | |
264 var y1 = Math.cos(t * 1.3) * 1.5; | |
265 var z1 = Math.sin(t + Math.PI/3) * 1.5; | |
266 var x2 = Math.cos(t * 1.2) * 1.5; | |
267 var y2 = Math.sin(t * 1.4) * 1.5; | |
268 var z2 = Math.sin(t*1.25 - Math.PI/3) * 1.5; | |
269 var x3 = Math.cos(t * 1.15) * 1.5; | |
270 var y3 = Math.sin(t * 1.37) * 1.5; | |
271 var z3 = Math.sin(t*1.27) * 1.5; | |
272 | |
273 var cameraFrom = new Vector( | |
274 Math.sin(t * 0.4) * 18, | |
275 Math.sin(t * 0.13) * 5 + 5, | |
276 Math.cos(t * 0.4) * 18 ); | |
277 var cameraTo = new Vector(0.0, 0.0, 0.0); | |
278 var cameraPersp = 6.0; | |
279 var up = new Vector(0.0, 1.0, 0.0); | |
280 var cameraDir = normalize(vectSub(cameraTo, cameraFrom)); | |
281 | |
282 var cameraLeft = normalize(crossProd(cameraDir, up)); | |
283 var cameraUp = normalize(crossProd(cameraLeft, cameraDir)); | |
284 // cameraFrom + cameraDir * cameraPersp | |
285 var cameraCenter = vectAdd(cameraFrom, vectMul(cameraDir, cameraPersp)); | |
286 | |
287 // cameraCenter + cameraUp + cameraLeft * ratio | |
288 var cameraTopLeft = vectAdd(vectAdd(cameraCenter, cameraUp), | |
289 vectMul(cameraLeft, ratio)); | |
290 var cameraBotLeft = vectAdd(vectSub(cameraCenter, cameraUp), | |
291 vectMul(cameraLeft, ratio)); | |
292 var cameraTopRight = vectSub(vectAdd(cameraCenter, cameraUp), | |
293 vectMul(cameraLeft, ratio)); | |
294 var cameraBotRight = vectSub(vectSub(cameraCenter, cameraUp), | |
295 vectMul(cameraLeft, ratio)); | |
296 | |
297 //corners = [1.2, 1, -12, -1.2, 1, -12, 1.2, -1, -12, -1.2, -1, -12]; | |
298 var corners = []; | |
299 pushVec(cameraTopRight, corners); | |
300 pushVec(cameraTopLeft, corners); | |
301 pushVec(cameraBotRight, corners); | |
302 pushVec(cameraBotLeft, corners); | |
303 | |
304 gl.bufferData(WebGLRenderingContext.ARRAY_BUFFER, corners, | |
vsm
2012/11/30 17:00:30
Ditto on Float32Array.
gram
2012/11/30 18:01:31
Done.
| |
305 WebGLRenderingContext.STATIC_DRAW); | |
306 | |
307 gl.uniform3f(cameraPos, cameraFrom.x, cameraFrom.y, cameraFrom.z); | |
308 gl.uniform3f(sphere1Center, x1, y1, z1); | |
309 gl.uniform3f(sphere2Center, x2, y2, z2); | |
310 gl.uniform3f(sphere3Center, x3, y3, z3); | |
311 | |
312 gl.drawArrays(WebGLRenderingContext.TRIANGLE_STRIP, 0, 4); | |
313 | |
314 t += 0.03; | |
315 if (t > Math.PI * 200) { | |
316 t -= Math.PI * 200; | |
317 } | |
318 } | |
319 | |
320 setup(int w, int h) { | |
321 initShaders(); | |
322 gl.clearColor(0.0, 0.0, 0.0, 1.0); | |
323 gl.clearDepth(1.0); | |
324 initBuffers(); | |
325 resize(w, h); | |
326 } | |
327 | |
328 resize(int w, int h) { | |
329 width = w; | |
330 height = h; | |
331 ratio = width / height; | |
332 gl.viewport(0, 0, width, height); | |
333 t -= 0.03; | |
334 drawScene(); | |
335 return "resize $width $height"; | |
vsm
2012/11/30 17:00:30
Can you remove the return? This was for my debugg
gram
2012/11/30 18:01:31
Done.
| |
336 } | |
337 | |
338 update() { | |
339 drawScene(); | |
340 eglSwapBuffers(); | |
341 return "draw"; | |
vsm
2012/11/30 17:00:30
Ditto.
gram
2012/11/30 18:01:31
Done.
| |
342 } | |
343 | |
344 onMotionDown(double when, int x, int y) { | |
vsm
2012/11/30 17:00:30
We typically use "num" instead of "double" so you
gram
2012/11/30 18:01:31
The NDK event is providing a double and this mirro
vsm
2012/11/30 18:38:31
The style guide suggests that we do:
http://www.da
gram
2012/11/30 22:09:22
Well, it turned out I had the doubles and ints mix
| |
345 t = (x / width) * Math.PI * 200; | |
346 } | |
347 | |
348 onMotionUp(double when, int x, int y) {} | |
349 onMotionMove(double when, int x, int y) {} | |
350 onMotionCancel(double when, int x, int y) {} | |
351 onMotionOutside(double when, int x, int y) {} | |
352 onMotionPointerDown(double when, int x, int y) {} | |
353 onMotionPointerUp(double when, int x, int y) {} | |
354 onKeyDown(double when, int flags, int keycode, int metastate, int repeat) {} | |
355 onKeyUp(double when, int flags, int keycode, int metastate, int repeat) {} | |
356 onKeyMultiple(double when, int flags, int keycode, int metastate, int repeat) { | |
357 } | |
358 | |
OLD | NEW |