| 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 // This sample is based upon the Ray Tracer sample by Jonas Sicking at: | |
| 6 // http://www.khronos.org/webgl/wiki/Demo_Repository | |
| 7 | |
| 8 /** | |
| 9 * A sample GL application. | |
| 10 */ | |
| 11 library raytrace; | |
| 12 | |
| 13 import 'gl.dart'; | |
| 14 import 'dart:math' as Math; | |
| 15 | |
| 16 // Note: The first line of the fragment shader ("precision mediump float") | |
| 17 // is not portable. It is required for WebGL and OpenGL ES. Desktop OpenGL | |
| 18 // does not use precision specifiers. Some desktop systems treat this as a | |
| 19 // no-op and some treat it as a syntax error. In particular, this line needs | |
| 20 // to be removed to this this shader on a MAc. | |
| 21 const FRAGMENT_PROGRAM = """ | |
| 22 // TODO(vsm): Remove this ifdef. It's a temporary workaround to get | |
| 23 // this sample running on the Mac desktop emulator. | |
| 24 #ifdef GL_ES | |
| 25 precision mediump float; | |
| 26 #endif | |
| 27 | |
| 28 const vec3 lightDir = vec3(0.577350269, 0.577350269, -0.577350269); | |
| 29 varying vec3 vPosition; | |
| 30 uniform vec3 cameraPos; | |
| 31 uniform vec3 sphere1Center; | |
| 32 uniform vec3 sphere2Center; | |
| 33 uniform vec3 sphere3Center; | |
| 34 | |
| 35 bool intersectSphere(vec3 center, vec3 lStart, vec3 lDir, | |
| 36 out float dist) { | |
| 37 vec3 c = center - lStart; | |
| 38 float b = dot(lDir, c); | |
| 39 float d = b*b - dot(c, c) + 1.0; | |
| 40 if (d < 0.0) { | |
| 41 dist = 10000.0; | |
| 42 return false; | |
| 43 } | |
| 44 | |
| 45 dist = b - sqrt(d); | |
| 46 if (dist < 0.0) { | |
| 47 dist = 10000.0; | |
| 48 return false; | |
| 49 } | |
| 50 | |
| 51 return true; | |
| 52 } | |
| 53 | |
| 54 vec3 lightAt(vec3 N, vec3 V, vec3 color) { | |
| 55 vec3 L = lightDir; | |
| 56 vec3 R = reflect(-L, N); | |
| 57 | |
| 58 float c = 0.3 + 0.4 * pow(max(dot(R, V), 0.0), 30.0) + 0.7 * dot(L, N); | |
| 59 | |
| 60 if (c > 1.0) { | |
| 61 return mix(color, vec3(1.6, 1.6, 1.6), c - 1.0); | |
| 62 } | |
| 63 | |
| 64 return c * color; | |
| 65 } | |
| 66 | |
| 67 bool intersectWorld(vec3 lStart, vec3 lDir, out vec3 pos, | |
| 68 out vec3 normal, out vec3 color) { | |
| 69 float d1, d2, d3; | |
| 70 bool h1, h2, h3; | |
| 71 | |
| 72 h1 = intersectSphere(sphere1Center, lStart, lDir, d1); | |
| 73 h2 = intersectSphere(sphere2Center, lStart, lDir, d2); | |
| 74 h3 = intersectSphere(sphere3Center, lStart, lDir, d3); | |
| 75 | |
| 76 if (h1 && d1 < d2 && d1 < d3) { | |
| 77 pos = lStart + d1 * lDir; | |
| 78 normal = pos - sphere1Center; | |
| 79 color = vec3(0.0, 0.0, 0.9); | |
| 80 if (fract(pos.x / 1.5) > 0.5 ^^ | |
| 81 fract(pos.y / 1.5) > 0.5 ^^ | |
| 82 fract(pos.z / 1.5) > 0.5) { | |
| 83 color = vec3(1.0, 0.0, 1.0); | |
| 84 } | |
| 85 else { | |
| 86 color = vec3(1.0, 1.0, 0.0); | |
| 87 } | |
| 88 } | |
| 89 else if (h2 && d2 < d3) { | |
| 90 pos = lStart + d2 * lDir; | |
| 91 normal = pos - sphere2Center; | |
| 92 color = vec3(0.9, mod(normal.y * 2.5, 1.0), 0.0); | |
| 93 } | |
| 94 else if (h3) { | |
| 95 pos = lStart + d3 * lDir; | |
| 96 normal = pos - sphere3Center; | |
| 97 color = vec3(0.0, clamp(sphere3Center.y/1.5, 0.0, 0.9), | |
| 98 clamp(0.9 - sphere3Center.y/1.5, 0.0, 0.9)); | |
| 99 } | |
| 100 else if (lDir.y < -0.01) { | |
| 101 pos = lStart + ((lStart.y + 2.7) / -lDir.y) * lDir; | |
| 102 if (pos.x*pos.x + pos.z*pos.z > 30.0) { | |
| 103 return false; | |
| 104 } | |
| 105 normal = vec3(0.0, 1.0, 0.0); | |
| 106 if (fract(pos.x / 5.0) > 0.5 == fract(pos.z / 5.0) > 0.5) { | |
| 107 color = vec3(1.0); | |
| 108 } | |
| 109 else { | |
| 110 color = vec3(0.0); | |
| 111 } | |
| 112 } | |
| 113 else { | |
| 114 return false; | |
| 115 } | |
| 116 | |
| 117 return true; | |
| 118 } | |
| 119 | |
| 120 void main(void) | |
| 121 { | |
| 122 vec3 cameraDir = normalize(vPosition - cameraPos); | |
| 123 | |
| 124 vec3 p1, norm, p2; | |
| 125 vec3 col, colT, colM, col3; | |
| 126 if (intersectWorld(cameraPos, cameraDir, p1, | |
| 127 norm, colT)) { | |
| 128 col = lightAt(norm, -cameraDir, colT); | |
| 129 colM = (colT + vec3(0.2)) / 1.2; | |
| 130 cameraDir = reflect(cameraDir, norm); | |
| 131 if (intersectWorld(p1, cameraDir, p2, norm, colT)) { | |
| 132 col += lightAt(norm, -cameraDir, colT) * colM; | |
| 133 colM *= (colT + vec3(0.2)) / 1.2; | |
| 134 cameraDir = reflect(cameraDir, norm); | |
| 135 if (intersectWorld(p2, cameraDir, p1, norm, colT)) { | |
| 136 col += lightAt(norm, -cameraDir, colT) * colM; | |
| 137 } | |
| 138 } | |
| 139 | |
| 140 gl_FragColor = vec4(col, 1.0); | |
| 141 } | |
| 142 else { | |
| 143 gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); | |
| 144 } | |
| 145 } | |
| 146 """; | |
| 147 | |
| 148 const VERTEX_PROGRAM = """ | |
| 149 attribute vec2 aVertexPosition; | |
| 150 attribute vec3 aPlotPosition; | |
| 151 | |
| 152 varying vec3 vPosition; | |
| 153 | |
| 154 void main(void) | |
| 155 { | |
| 156 gl_Position = vec4(aVertexPosition, 1.0, 1.0); | |
| 157 vPosition = aPlotPosition; | |
| 158 } | |
| 159 """; | |
| 160 | |
| 161 loadShader(final type, final program) { | |
| 162 final shader = gl.createShader(type); | |
| 163 gl.shaderSource(shader, program); | |
| 164 gl.compileShader(shader); | |
| 165 if (gl.getShaderParameter(shader, WebGLRenderingContext.COMPILE_STATUS) != tru
e) { | |
| 166 final error = gl.getShaderInfoLog(shader); | |
| 167 log(error); | |
| 168 throw new Exception("Shader compilation error: $error"); | |
| 169 } | |
| 170 | |
| 171 return shader; | |
| 172 } | |
| 173 | |
| 174 var shaderProgram; | |
| 175 var aVertexPosition; | |
| 176 var aPlotPosition; | |
| 177 var cameraPos; | |
| 178 var sphere1Center; | |
| 179 var sphere2Center; | |
| 180 var sphere3Center; | |
| 181 var ratio; | |
| 182 | |
| 183 void initShaders() { | |
| 184 var vertexShader = loadShader(WebGLRenderingContext.VERTEX_SHADER, | |
| 185 VERTEX_PROGRAM); | |
| 186 var fragmentShader = loadShader(WebGLRenderingContext.FRAGMENT_SHADER, | |
| 187 FRAGMENT_PROGRAM); | |
| 188 | |
| 189 shaderProgram = gl.createProgram(); | |
| 190 if (shaderProgram == 0) { | |
| 191 throw new Exception("Could not create program."); | |
| 192 } | |
| 193 | |
| 194 gl.attachShader(shaderProgram, vertexShader); | |
| 195 gl.attachShader(shaderProgram, fragmentShader); | |
| 196 gl.linkProgram(shaderProgram); | |
| 197 | |
| 198 if (gl.getProgramParameter(shaderProgram, WebGLRenderingContext.LINK_STATUS) !
= true) { | |
| 199 final error = gl.getProgramInfoLog(shaderProgram); | |
| 200 throw new Exception("Program compilation error: $error"); | |
| 201 } | |
| 202 | |
| 203 gl.useProgram(shaderProgram); | |
| 204 | |
| 205 aVertexPosition = gl.getAttribLocation(shaderProgram, "aVertexPosition"); | |
| 206 gl.enableVertexAttribArray(aVertexPosition); | |
| 207 | |
| 208 aPlotPosition = gl.getAttribLocation(shaderProgram, "aPlotPosition"); | |
| 209 gl.enableVertexAttribArray(aPlotPosition); | |
| 210 | |
| 211 cameraPos = gl.getUniformLocation(shaderProgram, "cameraPos"); | |
| 212 sphere1Center = gl.getUniformLocation(shaderProgram, "sphere1Center"); | |
| 213 sphere2Center = gl.getUniformLocation(shaderProgram, "sphere2Center"); | |
| 214 sphere3Center = gl.getUniformLocation(shaderProgram, "sphere3Center"); | |
| 215 } | |
| 216 | |
| 217 // TODO(gram): This should go away at some point. For now it is a kludge | |
| 218 // to allow us to run same .dart file with WebGL and natively; the WebGL | |
| 219 // version will set this to true. | |
| 220 var wrapVertexArray = false; | |
| 221 | |
| 222 wrapVertices(a) => wrapVertexArray ? (new Float32Array.fromList(a)) : a; | |
| 223 | |
| 224 void initBuffers() { | |
| 225 var vertexPositionBuffer = gl.createBuffer(); | |
| 226 gl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, vertexPositionBuffer); | |
| 227 var vertices = [ | |
| 228 1.0, 1.0, | |
| 229 -1.0, 1.0, | |
| 230 1.0, -1.0, | |
| 231 -1.0, -1.0, | |
| 232 ]; | |
| 233 | |
| 234 gl.bufferData(WebGLRenderingContext.ARRAY_BUFFER, wrapVertices(vertices), | |
| 235 WebGLRenderingContext.STATIC_DRAW); | |
| 236 gl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, vertexPositionBuffer); | |
| 237 gl.vertexAttribPointer(aVertexPosition, 2, WebGLRenderingContext.FLOAT, | |
| 238 false,0, 0); | |
| 239 | |
| 240 var plotPositionBuffer = gl.createBuffer(); | |
| 241 gl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, plotPositionBuffer); | |
| 242 gl.vertexAttribPointer(aPlotPosition, 3, WebGLRenderingContext.FLOAT, | |
| 243 false, 0, 0); | |
| 244 } | |
| 245 | |
| 246 class Vector { | |
| 247 var x; | |
| 248 var y; | |
| 249 var z; | |
| 250 Vector(this.x, this.y, this.z); | |
| 251 } | |
| 252 | |
| 253 // TODO(gram): This should be using vector_math. | |
| 254 crossProd(v1, v2) => | |
| 255 new Vector(v1.y*v2.z - v2.y*v1.z, | |
| 256 v1.z*v2.x - v2.z*v1.x, | |
| 257 v1.x*v2.y - v2.x*v1.y); | |
| 258 | |
| 259 Vector normalize(v) { | |
| 260 var l = 1 / Math.sqrt(v.x*v.x + v.y*v.y + v.z*v.z); | |
| 261 return new Vector( v.x*l, v.y*l, v.z*l ); | |
| 262 } | |
| 263 | |
| 264 vectAdd(v1, v2) => new Vector( v1.x + v2.x, v1.y + v2.y, v1.z + v2.z ); | |
| 265 | |
| 266 vectSub(v1, v2) => new Vector( v1.x - v2.x, v1.y - v2.y, v1.z - v2.z ); | |
| 267 | |
| 268 vectMul(v, l) => new Vector( v.x*l, v.y*l, v.z*l ); | |
| 269 | |
| 270 void pushVec(v, arr) { | |
| 271 arr.addAll([v.x, v.y, v.z]); | |
| 272 } | |
| 273 | |
| 274 var t = 0; | |
| 275 | |
| 276 void drawScene() { | |
| 277 var x1 = Math.sin(t * 1.1) * 1.5; | |
| 278 var y1 = Math.cos(t * 1.3) * 1.5; | |
| 279 var z1 = Math.sin(t + Math.PI/3) * 1.5; | |
| 280 var x2 = Math.cos(t * 1.2) * 1.5; | |
| 281 var y2 = Math.sin(t * 1.4) * 1.5; | |
| 282 var z2 = Math.sin(t*1.25 - Math.PI/3) * 1.5; | |
| 283 var x3 = Math.cos(t * 1.15) * 1.5; | |
| 284 var y3 = Math.sin(t * 1.37) * 1.5; | |
| 285 var z3 = Math.sin(t*1.27) * 1.5; | |
| 286 | |
| 287 var cameraFrom = new Vector( | |
| 288 Math.sin(t * 0.4) * 18, | |
| 289 Math.sin(t * 0.13) * 5 + 5, | |
| 290 Math.cos(t * 0.4) * 18 ); | |
| 291 var cameraTo = new Vector(0.0, 0.0, 0.0); | |
| 292 var cameraPersp = 6.0; | |
| 293 var up = new Vector(0.0, 1.0, 0.0); | |
| 294 var cameraDir = normalize(vectSub(cameraTo, cameraFrom)); | |
| 295 | |
| 296 var cameraLeft = normalize(crossProd(cameraDir, up)); | |
| 297 var cameraUp = normalize(crossProd(cameraLeft, cameraDir)); | |
| 298 // cameraFrom + cameraDir * cameraPersp | |
| 299 var cameraCenter = vectAdd(cameraFrom, vectMul(cameraDir, cameraPersp)); | |
| 300 | |
| 301 // cameraCenter + cameraUp + cameraLeft * ratio | |
| 302 var cameraTopLeft = vectAdd(vectAdd(cameraCenter, cameraUp), | |
| 303 vectMul(cameraLeft, ratio)); | |
| 304 var cameraBotLeft = vectAdd(vectSub(cameraCenter, cameraUp), | |
| 305 vectMul(cameraLeft, ratio)); | |
| 306 var cameraTopRight = vectSub(vectAdd(cameraCenter, cameraUp), | |
| 307 vectMul(cameraLeft, ratio)); | |
| 308 var cameraBotRight = vectSub(vectSub(cameraCenter, cameraUp), | |
| 309 vectMul(cameraLeft, ratio)); | |
| 310 | |
| 311 var corners = []; | |
| 312 pushVec(cameraTopRight, corners); | |
| 313 pushVec(cameraTopLeft, corners); | |
| 314 pushVec(cameraBotRight, corners); | |
| 315 pushVec(cameraBotLeft, corners); | |
| 316 | |
| 317 gl.bufferData(WebGLRenderingContext.ARRAY_BUFFER, wrapVertices(corners), | |
| 318 WebGLRenderingContext.STATIC_DRAW); | |
| 319 | |
| 320 gl.uniform3f(cameraPos, cameraFrom.x, cameraFrom.y, cameraFrom.z); | |
| 321 gl.uniform3f(sphere1Center, x1, y1, z1); | |
| 322 gl.uniform3f(sphere2Center, x2, y2, z2); | |
| 323 gl.uniform3f(sphere3Center, x3, y3, z3); | |
| 324 | |
| 325 gl.drawArrays(WebGLRenderingContext.TRIANGLE_STRIP, 0, 4); | |
| 326 | |
| 327 t += 0.03; | |
| 328 if (t > Math.PI * 200) { | |
| 329 t -= Math.PI * 200; | |
| 330 } | |
| 331 } | |
| 332 | |
| 333 void setup(int width, int height) { | |
| 334 initShaders(); | |
| 335 gl.clearColor(0.0, 0.0, 0.0, 1.0); | |
| 336 gl.clearDepth(1.0); | |
| 337 initBuffers(); | |
| 338 resize(width, height); | |
| 339 } | |
| 340 | |
| 341 void resize(int width, int height) { | |
| 342 ratio = width / height; | |
| 343 gl.viewport(0, 0, width, height); | |
| 344 t -= 0.03; | |
| 345 drawScene(); | |
| 346 } | |
| 347 | |
| 348 void update() { | |
| 349 drawScene(); | |
| 350 } | |
| 351 | |
| 352 /* | |
| 353 TODO(gram): below are the current entry points for input events for the | |
| 354 native code version. We need to integrate these somehow with the WebGL | |
| 355 version: | |
| 356 | |
| 357 onMotionDown(num when, num x, num y) {} | |
| 358 onMotionUp(num when, num x, num y) {} | |
| 359 onMotionMove(num when, num x, num y) {} | |
| 360 onMotionCancel(num when, num x, num y) {} | |
| 361 onMotionOutside(num when, num x, num y) {} | |
| 362 onMotionPointerDown(num when, num x, num y) {} | |
| 363 onMotionPointerUp(num when, num x, num y) {} | |
| 364 onKeyDown(num when, int flags, int keycode, int metastate, int repeat) {} | |
| 365 onKeyUp(num when, int flags, int keycode, int metastate, int repeat) {} | |
| 366 onKeyMultiple(num when, int flags, int keycode, int metastate, int repeat) { | |
| 367 } | |
| 368 */ | |
| 369 | |
| OLD | NEW |