OLD | NEW |
(Empty) | |
| 1 <!DOCTYPE html> |
| 2 <html> |
| 3 <head> |
| 4 <meta charset="utf-8"> |
| 5 <!-- |
| 6 |
| 7 /* |
| 8 ** Copyright (c) 2012 The Khronos Group Inc. |
| 9 ** |
| 10 ** Permission is hereby granted, free of charge, to any person obtaining a |
| 11 ** copy of this software and/or associated documentation files (the |
| 12 ** "Materials"), to deal in the Materials without restriction, including |
| 13 ** without limitation the rights to use, copy, modify, merge, publish, |
| 14 ** distribute, sublicense, and/or sell copies of the Materials, and to |
| 15 ** permit persons to whom the Materials are furnished to do so, subject to |
| 16 ** the following conditions: |
| 17 ** |
| 18 ** The above copyright notice and this permission notice shall be included |
| 19 ** in all copies or substantial portions of the Materials. |
| 20 ** |
| 21 ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| 22 ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| 23 ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
| 24 ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
| 25 ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
| 26 ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
| 27 ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. |
| 28 */ |
| 29 |
| 30 --> |
| 31 |
| 32 <title>OpenGL for the web</title> |
| 33 |
| 34 <script type="application/x-javascript" src="../util.js"></script> |
| 35 |
| 36 <script type="application/x-javascript"> |
| 37 |
| 38 function log(msg) { |
| 39 document.getElementById('note').textContent += "\n"+msg; |
| 40 } |
| 41 |
| 42 |
| 43 |
| 44 |
| 45 function init(ev) { |
| 46 var canvas = document.getElementById('canvas'); |
| 47 var gl = getGLContext(canvas); |
| 48 |
| 49 var shader = new Shader(gl, "ppix-vert", "ppix-frag"); |
| 50 shader.compile(); |
| 51 var fbo = new FBO(gl, canvas.width, canvas.height); |
| 52 var fbo2 = new FBO(gl, canvas.width, canvas.height); |
| 53 var fbo3 = new FBO(gl, canvas.width, canvas.height); |
| 54 var depth = new Shader(gl, "depth-vert", "depth-frag"); |
| 55 var identity = new Filter(gl, "identity-vert", "identity-frag"); |
| 56 var unpremult = new Filter(gl, "identity-vert", "unpremult-frag"); |
| 57 var hblur = new Filter(gl, "identity-vert", "hblur-frag"); |
| 58 var vblur = new Filter(gl, "identity-vert", "vblur-frag"); |
| 59 var hdof = new Filter(gl, "identity-vert", "hdof-frag"); |
| 60 var vdof = new Filter(gl, "identity-vert", "vdof-frag"); |
| 61 |
| 62 redraw(canvas, gl, shader, fbo, fbo2, fbo3, depth, identity, unpremult, hblu
r, vblur, hdof, vdof); |
| 63 |
| 64 setInterval(function(){ |
| 65 redraw(canvas, gl, shader, fbo, fbo2, fbo3, depth, identity, unpremult,
hblur, vblur, hdof, vdof); |
| 66 }, 33); |
| 67 } |
| 68 |
| 69 function drawCube (gl, shader, angle, axis, x,y,z, s, va, na, ta) { |
| 70 Matrix.copyMatrix(look, vmat); |
| 71 Matrix.translate3InPlace(x,y,z,vmat); |
| 72 Matrix.scale1InPlace(s,vmat); |
| 73 Matrix.rotateInPlace(angle, axis, vmat); |
| 74 |
| 75 // Note: we could just use mat3(MVMatrix) as the normal matrix |
| 76 // as MVMatrix has only rotations, translations and uniform scaling |
| 77 // <=> MVMatrix is a scaled orthonormal matrix |
| 78 // hence normalize(mat3(MVMatrix)*v) == normalize(mat3(transpose(inverse(MVM
atrix))*v) |
| 79 // |
| 80 // But let's do it the hard way to see if Matrix.inverse3x3 works... |
| 81 Matrix.inverseTo3x3InPlace(vmat, nmat); |
| 82 Matrix.transpose3x3InPlace(nmat); |
| 83 |
| 84 shader.uniformMatrix4fv("MVMatrix", vmat); |
| 85 shader.uniformMatrix3fv("NMatrix", nmat); |
| 86 |
| 87 var cube = Cube.getCachedVBO(gl); |
| 88 cube.draw(va, na, ta); |
| 89 } |
| 90 |
| 91 var carr = []; |
| 92 for (var i=0; i<25; i++) { |
| 93 carr.push([Math.random(), Math.random(), Math.random()]); |
| 94 } |
| 95 |
| 96 function drawScene (gl, shader, va, na, ta) { |
| 97 var ot = new Date().getTime(); |
| 98 var t = ot; |
| 99 |
| 100 shader.uniformMatrix4fv("PMatrix", pmat); |
| 101 for (var i=0; i<carr.length; i++){ |
| 102 var c = carr[i]; |
| 103 var f = c[1] < 0.5 ? 1 : -1; |
| 104 var t = ot; |
| 105 drawCube(gl, shader, |
| 106 (t/(f*400*(c[0]+0.5))) % (2*Math.PI), c, |
| 107 |
| 108 0.45+0.8*c[2], |
| 109 -0.4+Math.cos((i/carr.length*Math.PI*2)+t/1000), |
| 110 0.8+Math.sin((i/carr.length*Math.PI*2)+t/1000)*3.2, |
| 111 |
| 112 0.05 + Math.pow((c[0]+c[1]+c[2])*0.33, 2)*0.3, |
| 113 va, na, ta); |
| 114 } |
| 115 } |
| 116 |
| 117 var nmat = Matrix.newIdentity3x3(); |
| 118 var vmat = Matrix.newIdentity(); |
| 119 var vmat2 = Matrix.newIdentity(); |
| 120 var pmat = null; |
| 121 var look = Matrix.lookAt([4,-1,8], [-0.2,0,0], [0,1,0]); |
| 122 var useDoF = false; |
| 123 |
| 124 var firstFrame = true; |
| 125 |
| 126 function redraw(canvas, gl, shader, fbo, fbo2, fbo3, depth, identity, unpremult,
hblur, vblur, hdof, vdof) { |
| 127 |
| 128 var doDoF = useDoF; |
| 129 gl.viewport(0, 0, canvas.width, canvas.height); |
| 130 gl.clearColor(0.0, 0.0, 0.0, 0.0); |
| 131 gl.enable(gl.DEPTH_TEST); |
| 132 |
| 133 gl.bindFramebuffer(gl.FRAMEBUFFER, null); |
| 134 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); |
| 135 |
| 136 fbo.use(); |
| 137 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); |
| 138 |
| 139 shader.use(); |
| 140 |
| 141 var va = shader.attrib("Vertex"); |
| 142 var na = shader.attrib("Normal"); |
| 143 var ta = shader.attrib("Tex"); |
| 144 |
| 145 if (pmat == null) |
| 146 pmat = Matrix.perspective(30, canvas.width/canvas.height, 1, 100); |
| 147 |
| 148 shader.uniform4f("MaterialSpecular", 0.95, 0.9, 0.6, 1); |
| 149 shader.uniform4f("MaterialDiffuse", 0.50, 0.35, 0.35, 1); |
| 150 shader.uniform4f("MaterialAmbient", 0.0, 0.1, 0.2, 1); |
| 151 shader.uniform1f("MaterialShininess", 1.5); |
| 152 |
| 153 shader.uniform4f("GlobalAmbient", 0.1, 0.1, 0.1, 1); |
| 154 |
| 155 shader.uniform4f("LightPos", 1, 5, 3, 1.0); |
| 156 |
| 157 shader.uniform4f("LightSpecular", 0.9, 0.9, 0.9, 1); |
| 158 shader.uniform4f("LightDiffuse", 0.8, 0.8, 0.8, 1); |
| 159 shader.uniform4f("LightAmbient", 0.0, 0.06, 0.2, 1); |
| 160 shader.uniform1f("LightConstantAtt", 0.0); |
| 161 shader.uniform1f("LightLinearAtt", 0.1); |
| 162 shader.uniform1f("LightQuadraticAtt", 0.0); |
| 163 |
| 164 drawScene(gl, shader, va, na); |
| 165 |
| 166 if (doDoF || firstFrame) { |
| 167 |
| 168 fbo3.use(); |
| 169 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); |
| 170 depth.use(); |
| 171 var dva = depth.attrib("Vertex"); |
| 172 |
| 173 drawScene(gl, depth, dva); |
| 174 |
| 175 gl.disable(gl.DEPTH_TEST); |
| 176 gl.activeTexture(gl.TEXTURE1); |
| 177 gl.bindTexture(gl.TEXTURE_2D, fbo3.texture); |
| 178 gl.activeTexture(gl.TEXTURE0); |
| 179 |
| 180 |
| 181 for (var i=0; i<3; i++) { |
| 182 fbo2.use(); |
| 183 gl.bindTexture(gl.TEXTURE_2D, fbo.texture); |
| 184 |
| 185 hdof.apply(function(f){ |
| 186 f.uniform1i("Texture", 0); |
| 187 f.uniform1i("Depth", 1); |
| 188 f.uniform1f("iter", i); |
| 189 f.uniform1f("step", 1.0/canvas.width); |
| 190 }); |
| 191 |
| 192 fbo.use(); |
| 193 gl.bindTexture(gl.TEXTURE_2D, fbo2.texture); |
| 194 |
| 195 vdof.apply(function(f){ |
| 196 f.uniform1i("Texture", 0); |
| 197 f.uniform1i("Depth", 1); |
| 198 f.uniform1f("iter", i); |
| 199 f.uniform1f("step", 1.0/canvas.width); |
| 200 }); |
| 201 } |
| 202 |
| 203 } |
| 204 firstFrame = false; |
| 205 |
| 206 gl.bindFramebuffer(gl.FRAMEBUFFER, null); |
| 207 |
| 208 gl.activeTexture(gl.TEXTURE1); |
| 209 gl.bindTexture(gl.TEXTURE_2D, null); |
| 210 gl.activeTexture(gl.TEXTURE0); |
| 211 gl.bindTexture(gl.TEXTURE_2D, fbo.texture); |
| 212 |
| 213 // The DoF blur blurs the color from the transparent black background with |
| 214 // the cubes. To get rid of the border, we can treat it as premultiplied alp
ha. |
| 215 // To see the problem, try replacing unpremult with identity. |
| 216 unpremult.apply(function(f){ |
| 217 f.uniform1i("Texture", 0); |
| 218 }); |
| 219 |
| 220 } |
| 221 |
| 222 window.addEventListener("load", init, false); |
| 223 </script> |
| 224 |
| 225 <script id="ppix-vert" type="x-shader/x-vertex"> |
| 226 attribute vec3 Vertex; |
| 227 attribute vec3 Normal; |
| 228 attribute vec2 Tex; |
| 229 |
| 230 uniform mat4 PMatrix; |
| 231 uniform mat4 MVMatrix; |
| 232 uniform mat3 NMatrix; |
| 233 |
| 234 uniform vec4 MaterialAmbient; |
| 235 uniform vec4 MaterialDiffuse; |
| 236 |
| 237 uniform vec4 LightAmbient; |
| 238 uniform vec4 LightDiffuse; |
| 239 |
| 240 uniform vec4 GlobalAmbient; |
| 241 |
| 242 uniform vec4 LightPos; |
| 243 |
| 244 varying vec4 diffuse, ambientGlobal, ambient; |
| 245 varying vec3 normal, lightDir, halfVector; |
| 246 varying float dist; |
| 247 |
| 248 void main() |
| 249 { |
| 250 vec4 worldPos; |
| 251 vec3 lightVector; |
| 252 vec4 v = vec4(Vertex, 1.0); |
| 253 |
| 254 /* transform vertex normal into world space and normalize */ |
| 255 normal = normalize(NMatrix * Normal); |
| 256 |
| 257 /* transform vertex into world space and compute the vector |
| 258 from it to the light */ |
| 259 worldPos = MVMatrix * v; |
| 260 lightVector = vec3(LightPos - worldPos); |
| 261 lightDir = normalize(lightVector); |
| 262 dist = length(lightVector); |
| 263 |
| 264 /* Half-vector used in Blinn-Phong shading due to computational efficien
cy */ |
| 265 halfVector = normalize(lightVector - vec3(worldPos)); |
| 266 |
| 267 diffuse = MaterialDiffuse * LightDiffuse; |
| 268 |
| 269 /* The ambient terms have been separated since one of them */ |
| 270 /* suffers attenuation */ |
| 271 ambient = MaterialAmbient * LightAmbient; |
| 272 ambientGlobal = GlobalAmbient * MaterialAmbient; |
| 273 |
| 274 gl_Position = PMatrix * worldPos; |
| 275 } |
| 276 </script> |
| 277 |
| 278 <script id="ppix-frag" type="x-shader/x-fragment"> |
| 279 precision mediump float; |
| 280 |
| 281 uniform vec4 LightSpecular; |
| 282 uniform vec4 MaterialSpecular; |
| 283 uniform float MaterialShininess; |
| 284 |
| 285 uniform float LightConstantAtt; |
| 286 uniform float LightLinearAtt; |
| 287 uniform float LightQuadraticAtt; |
| 288 |
| 289 varying vec4 diffuse,ambientGlobal, ambient; |
| 290 varying vec3 normal, lightDir, halfVector; |
| 291 varying float dist; |
| 292 |
| 293 void main() |
| 294 { |
| 295 vec3 n, halfV, viewV, ldir; |
| 296 float NdotL, NdotHV; |
| 297 vec4 color = ambientGlobal; |
| 298 float att; |
| 299 |
| 300 n = normalize(normal); |
| 301 |
| 302 NdotL = max(dot(n, normalize(lightDir)), 0.0); |
| 303 |
| 304 if (NdotL > 0.0) { |
| 305 |
| 306 att = 1.0 / (LightConstantAtt + LightLinearAtt * dist + LightQuadratic
Att * dist * dist); |
| 307 |
| 308 color += att * (diffuse * NdotL + ambient); |
| 309 |
| 310 halfV = normalize(halfVector); |
| 311 NdotHV = max( dot(normal, halfV), 0.0 ); |
| 312 |
| 313 color += att * MaterialSpecular * LightSpecular * pow(NdotHV, Material
Shininess); |
| 314 } |
| 315 |
| 316 gl_FragColor = color; |
| 317 } |
| 318 </script> |
| 319 <script id="depth-vert" type="x-shader/x-vertex"> |
| 320 attribute vec3 Vertex; |
| 321 uniform mat4 PMatrix; |
| 322 uniform mat4 MVMatrix; |
| 323 varying float depth; |
| 324 void main() |
| 325 { |
| 326 gl_Position = PMatrix * (MVMatrix * vec4(Vertex, 1.0)); |
| 327 depth = 1.0-(gl_Position.z / gl_Position.w); |
| 328 } |
| 329 </script> |
| 330 <script id="depth-frag" type="x-shader/x-fragment"> |
| 331 precision mediump float; |
| 332 |
| 333 varying float depth; |
| 334 void main() |
| 335 { |
| 336 vec4 c = vec4(depth, 0.0, 0.0, 1.0); |
| 337 gl_FragColor = c; |
| 338 } |
| 339 </script> |
| 340 |
| 341 <script id="identity-vert" type="x-shader/x-vertex"> |
| 342 attribute vec3 Vertex; |
| 343 attribute vec2 Tex; |
| 344 |
| 345 varying vec4 texCoord0; |
| 346 void main() |
| 347 { |
| 348 texCoord0 = vec4(Tex,0.0,0.0); |
| 349 gl_Position = vec4(Vertex, 1.0); |
| 350 } |
| 351 </script> |
| 352 <script id="identity-frag" type="x-shader/x-fragment"> |
| 353 precision mediump float; |
| 354 |
| 355 uniform sampler2D Texture; |
| 356 |
| 357 varying vec4 texCoord0; |
| 358 void main() |
| 359 { |
| 360 vec4 c = texture2D(Texture, texCoord0.st); |
| 361 gl_FragColor = c; |
| 362 } |
| 363 </script> |
| 364 <script id="premult-frag" type="x-shader/x-fragment"> |
| 365 precision mediump float; |
| 366 |
| 367 uniform sampler2D Texture; |
| 368 |
| 369 varying vec4 texCoord0; |
| 370 void main() |
| 371 { |
| 372 vec4 c = texture2D(Texture, texCoord0.st); |
| 373 float a = c.a; |
| 374 c *= a; |
| 375 c.a = a; |
| 376 gl_FragColor = c; |
| 377 } |
| 378 </script> |
| 379 <script id="unpremult-frag" type="x-shader/x-fragment"> |
| 380 precision mediump float; |
| 381 |
| 382 uniform sampler2D Texture; |
| 383 |
| 384 varying vec4 texCoord0; |
| 385 void main() |
| 386 { |
| 387 vec4 c = texture2D(Texture, texCoord0.st); |
| 388 float a = c.a; |
| 389 c /= a; |
| 390 c.a = a; |
| 391 gl_FragColor = c; |
| 392 } |
| 393 </script> |
| 394 |
| 395 <script id="hblur-frag" type="x-shader/x-fragment"> |
| 396 precision mediump float; |
| 397 |
| 398 uniform sampler2D Texture; |
| 399 uniform float step; |
| 400 float kernel[7] = float[](0.046, 0.111, 0.202, 0.283, 0.202, 0.111, 0.046)
; |
| 401 |
| 402 varying vec4 texCoord0; |
| 403 void main() |
| 404 { |
| 405 int i=0; |
| 406 if (texture2D(Texture, texCoord0.st).a > 0.0) { |
| 407 vec4 sum = vec4(0.0); |
| 408 for (i=0; i<7; i++) { |
| 409 vec4 tmp = texture2D(Texture, texCoord0.st + vec2(i*step,0)); |
| 410 sum += tmp * kernel[i]; |
| 411 } |
| 412 gl_FragColor = sum; |
| 413 } else { |
| 414 gl_FragColor = texture2D(Texture, texCoord0.st); |
| 415 } |
| 416 } |
| 417 </script> |
| 418 <script id="vblur-frag" type="x-shader/x-fragment"> |
| 419 precision mediump float; |
| 420 |
| 421 uniform sampler2D Texture; |
| 422 uniform float step; |
| 423 float kernel[7] = float[](0.046, 0.111, 0.202, 0.283, 0.202, 0.111, 0.046)
; |
| 424 |
| 425 varying vec4 texCoord0; |
| 426 void main() |
| 427 { |
| 428 int i=0; |
| 429 if (texture2D(Texture, texCoord0.st).a > 0.0) { |
| 430 vec4 sum = vec4(0.0); |
| 431 for (i=0; i<7; i++) { |
| 432 vec4 tmp = texture2D(Texture, texCoord0.st + vec2(0,i*step)); |
| 433 sum += tmp * kernel[i]; |
| 434 } |
| 435 gl_FragColor = sum; |
| 436 } else { |
| 437 gl_FragColor = texture2D(Texture, texCoord0.st); |
| 438 } |
| 439 } |
| 440 </script> |
| 441 <script id="hdof-frag" type="x-shader/x-fragment"> |
| 442 precision mediump float; |
| 443 |
| 444 uniform sampler2D Texture; |
| 445 uniform sampler2D Depth; |
| 446 uniform float step; |
| 447 uniform float iter; |
| 448 float kernel[7] = { 0.046, 0.111, 0.202, 0.283, 0.202, 0.111, 0.046 }; |
| 449 |
| 450 varying vec4 texCoord0; |
| 451 void main() |
| 452 { |
| 453 vec4 tmp; |
| 454 vec4 sum = vec4(0.0); |
| 455 bool b = (iter < -26.0+36.0*(1.0-texture2D(Depth, texCoord0.st).r) && te
xture2D(Texture, texCoord0.st).a > 0.0); |
| 456 tmp = texture2D(Texture, texCoord0.st + vec2(float(0-3)*step,0)); |
| 457 sum += tmp * kernel[0]; |
| 458 tmp = texture2D(Texture, texCoord0.st + vec2(float(1-3)*step,0)); |
| 459 sum += tmp * kernel[1]; |
| 460 tmp = texture2D(Texture, texCoord0.st + vec2(float(2-3)*step,0)); |
| 461 sum += tmp * kernel[2]; |
| 462 tmp = texture2D(Texture, texCoord0.st + vec2(float(3-3)*step,0)); |
| 463 sum += tmp * kernel[3]; |
| 464 tmp = texture2D(Texture, texCoord0.st + vec2(float(4-3)*step,0)); |
| 465 sum += tmp * kernel[4]; |
| 466 tmp = texture2D(Texture, texCoord0.st + vec2(float(5-3)*step,0)); |
| 467 sum += tmp * kernel[5]; |
| 468 tmp = texture2D(Texture, texCoord0.st + vec2(float(6-3)*step,0)); |
| 469 sum += tmp * kernel[6]; |
| 470 gl_FragColor = mix(texture2D(Texture, texCoord0.st), sum, b ? 1.0 : 0.0)
; |
| 471 } |
| 472 </script> |
| 473 <script id="vdof-frag" type="x-shader/x-fragment"> |
| 474 precision mediump float; |
| 475 |
| 476 uniform sampler2D Texture; |
| 477 uniform sampler2D Depth; |
| 478 uniform float step; |
| 479 uniform float iter; |
| 480 float kernel[7] = float[7](0.046, 0.111, 0.202, 0.283, 0.202, 0.111, 0.046
); |
| 481 |
| 482 varying vec4 texCoord0; |
| 483 void main() |
| 484 { |
| 485 vec4 tmp; |
| 486 vec4 sum = vec4(0.0); |
| 487 bool b = (iter < -26.0+36.0*(1.0-texture2D(Depth, texCoord0.st).r) && te
xture2D(Texture, texCoord0.st).a > 0.0); |
| 488 tmp = texture2D(Texture, texCoord0.st + vec2(0,float(0-3)*step)); |
| 489 sum += tmp * kernel[0]; |
| 490 tmp = texture2D(Texture, texCoord0.st + vec2(0,float(1-3)*step)); |
| 491 sum += tmp * kernel[1]; |
| 492 tmp = texture2D(Texture, texCoord0.st + vec2(0,float(2-3)*step)); |
| 493 sum += tmp * kernel[2]; |
| 494 tmp = texture2D(Texture, texCoord0.st + vec2(0,float(3-3)*step)); |
| 495 sum += tmp * kernel[3]; |
| 496 tmp = texture2D(Texture, texCoord0.st + vec2(0,float(4-3)*step)); |
| 497 sum += tmp * kernel[4]; |
| 498 tmp = texture2D(Texture, texCoord0.st + vec2(0,float(5-3)*step)); |
| 499 sum += tmp * kernel[5]; |
| 500 tmp = texture2D(Texture, texCoord0.st + vec2(0,float(6-3)*step)); |
| 501 sum += tmp * kernel[6]; |
| 502 gl_FragColor = mix(texture2D(Texture, texCoord0.st), sum, b ? 1.0 : 0.0)
; |
| 503 } |
| 504 </script> |
| 505 |
| 506 <style> |
| 507 * { margin: 0px; padding: 0px; } |
| 508 html { |
| 509 background-color: #707888; |
| 510 color: #222222; |
| 511 } |
| 512 #canvas { |
| 513 position: absolute; |
| 514 cursor: pointer; |
| 515 top: 115px; left: 550px; |
| 516 } |
| 517 #note { |
| 518 position: absolute; |
| 519 top: 4px; |
| 520 left: 4px; |
| 521 } |
| 522 #content { |
| 523 margin-left: 99px; |
| 524 padding-left: 8px; |
| 525 padding-right: 8px; |
| 526 padding-bottom: 16px; |
| 527 width: 600px; |
| 528 background-color: rgba(255,255,255,1.0); |
| 529 text-align: center; |
| 530 border-left: 1px solid rgba(0,0,0,0.5); |
| 531 border-right: 2px solid rgba(0,0,0,0.75); |
| 532 } |
| 533 h1 { |
| 534 padding-top: 24px; |
| 535 padding-bottom: 16px; |
| 536 margin-bottom: 24px; |
| 537 border-bottom: 1px solid black; |
| 538 font-family: Times New Roman, Serif; |
| 539 font-weight: bold; |
| 540 font-size: 40px; |
| 541 } |
| 542 #content p { |
| 543 text-indent: 24px; |
| 544 margin-left: 24px; |
| 545 margin-right: 32px; |
| 546 text-align: justify; |
| 547 font-family: Serif; |
| 548 padding-bottom: 16px; |
| 549 } |
| 550 #above { |
| 551 position: absolute; |
| 552 top: 300px; |
| 553 left: 716px; |
| 554 padding: 10px 20px; |
| 555 background-color: rgba(0,225,0,0.5); |
| 556 border-left: 2px solid rgba(0,64,0,0.75); |
| 557 color: white; |
| 558 font-size: small; |
| 559 font-family: sans-serif; |
| 560 } |
| 561 #above p { |
| 562 text-align: center; |
| 563 } |
| 564 </style> |
| 565 |
| 566 </head><body> |
| 567 <canvas id="canvas" width="400" height="400" title="Click to toggle DOF shad
er" onclick="useDoF = !useDoF"></canvas> |
| 568 <pre id="note"></pre> |
| 569 |
| 570 <div id="content"> |
| 571 <h1>OpenGL for the web</h1> |
| 572 <p> |
| 573 The WebGL specification gives web developers access to an |
| 574 OpenGL ES 2.0 drawing context for the canvas tag. What that means is |
| 575 that you can finally harness the power of the GPU for awesome visuals |
| 576 and heavy-duty number crunching in your web apps. </p><p> OpenGL ES 2.0 is a sub
set of OpenGL 2.0 aimed at embedded |
| 577 devices and game consoles. As such, it's a very minimalistic low-level |
| 578 API, even more so than desktop OpenGL. In fact, if you took desktop |
| 579 OpenGL and stripped out everything but shaders, vertex arrays and |
| 580 textures, you'd get something quite like OpenGL ES 2.0. </p> |
| 581 <p> |
| 582 As there is no fixed-function pipeline, you need to write GLSL shaders to
draw <i>anything</i>. |
| 583 And you need to do your own transformation math, including keeping |
| 584 track of the transformation matrix stack. So the raw API is really not |
| 585 for the faint of heart; you do need to know your 3D math and shading |
| 586 equations. </p> |
| 587 <p> For example, to draw the spinning cubes on the |
| 588 right - around 200 lines of application code, 250 lines of shaders and |
| 589 800 lines of library code - I had to scrounge the internet for <a href="http://w
ww.lighthouse3d.com/opengl/glsl/index.php?pointlight">GLSL shaders</a> |
| 590 to do the transformation and lighting, write a small matrix math |
| 591 library in JavaScript and a DOF blur shader. While highly educational, |
| 592 it was also a rather steep hill to climb. </p> |
| 593 <p> So, the intended audience of the raw context |
| 594 interface are not really end-users, but library developers who can |
| 595 write easy-to-use interfaces to the functionality, and 3D developers |
| 596 who require a high level of control over the rendering pipeline. </p> |
| 597 <p> The really cool thing about the OpenGL Canvas is |
| 598 that it doesn't make policy decisions. There's no single set-in-stone |
| 599 use case for it: In addition to 3D graphics, you can also use it for |
| 600 filtering images, visualizing fluid dynamics, doing real-time video |
| 601 effects, or just crunching a whole lot of FP math. If you can do it on |
| 602 the GPU, you're in luck! </p> |
| 603 </div> |
| 604 <div id="above"> |
| 605 <p>You can also place content above the canvas</p> |
| 606 </div> |
| 607 </body></html> |
OLD | NEW |