1 / 57

WebGL : Hands On

WebGL : Hands On. Zhenyao Mo Software Engineer, Google, Inc. Chrome GPU Team. What is WebGL ?. Plug-in free 3D graphics for the web Based on OpenGL ES 2.0 Same on desktops, laptops, mobile devices Javascript + Shaders. WebGL Availability. Available: Firefox, Chrome, Opera

bertha
Download Presentation

WebGL : Hands On

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. WebGL: Hands On Zhenyao Mo Software Engineer, Google, Inc. Chrome GPU Team

  2. What is WebGL? • Plug-in free 3D graphics for the web • Based on OpenGL ES 2.0 • Same on desktops, laptops, mobile devices • Javascript + Shaders

  3. WebGL Availability • Available: Firefox, Chrome, Opera • Available but behind a switch: Safari/Webkit • Unavailable: IE • Install Chrome Frame

  4. WebGL Availability: Chrome • Windows: 68.13% users have WebGL • 31.87%: Mostly XP users with old GPUs/drivers • Have SwiftShader, an optional software renderer • Mac: 99.36% • Linux: 34.06%

  5. GPU Pipeline

  6. Shaders • Small stateless programs which run on the GPU with a high degree of parallelism • A vertex shader applies to each vertex • A fragment shader applies to each pixel • GPU automatically decides which pixel belongs to which triangle • GPU automatically blends vertex shader’s output • Output each pixel’s color

  7. A Concrete Example • Adapted from Giles Thomas' Learning WebGL Lesson 2 • Code is checked in to http://webglsamples.googlecode.com/ under hello-webgl/

  8. Vertex Shader attribute vec3 positionAttr; attribute vec4 colorAttr; varying vec4 vColor; void main(void) { gl_Position = vec4(positionAttr, 1.0); vColor = colorAttr; } • Executed THREE times (because we have ONE triangle with THREE vertices)

  9. Input stream Vertex Shader attribute vec3 positionAttr; attribute vec4 colorAttr; varying vec4 vColor; void main(void) { gl_Position = vec4(positionAttr, 1.0); vColor = colorAttr; } Input stream

  10. Vertex Shader attribute vec3 positionAttr; attribute vec4 colorAttr; varying vec4 vColor; void main(void) { gl_Position = vec4(positionAttr, 1.0); vColor = colorAttr; } Output: passing down to fragment shader

  11. Vertex Shader attribute vec3 positionAttr; attribute vec4 colorAttr; varying vec4 vColor; void main(void) { gl_Position = vec4(positionAttr, 1.0); vColor = colorAttr; } Final position of each vertex

  12. Fragment Shader precision mediump float; varying vec4 vColor; void main(void) { gl_FragColor = vColor; } • The value of vColor comes from three vertices, a weighted combination. • Executed a dozen to tens of thousands of times, depending on the canvas size.

  13. Fragment Shader precision mediump float; varying vec4 vColor; void main(void) { gl_FragColor = vColor; } Data from vertex shader

  14. Fragment Shader precision mediump float; varying vec4 vColor; void main(void) { gl_FragColor = vColor; } Final color of each pixel

  15. Vertex vs Fragment Shader- Where to compute the color? http://www.khronos.org/webgl/wiki/Demo_Repository Teapot Per Vertex and Teaport Per Pixel

  16. Vertex vs Fragment Shader- Where to compute the color? http://www.khronos.org/webgl/wiki/Demo_Repository Teapot Per Vertex and Teaport Per Pixel

  17. Shader Text • The shader text for this sample is embedded in the web page using script elements. <script id="shader-vs" type="x-shader/x-vertex">    attribute vec3 positionAttr;   attribute vec4 colorAttr;   ... </script>  <script id="shader-fs" type="x-shader/x-fragment">    precision mediump float;   varying vec4 vColor;   ... </script>

  18. Initialize WebGL vargl; function initGL(canvas) {   try { gl = canvas.getContext("experimental-webgl");   } catch (e) { }   if (!gl)     alert("Could not initialiseWebGL, sorry :-("); } The type of context

  19. Loading a Shader • Create the shader object – vertex or fragment. • Specify its source code. • Compile it. • Check whether compilation succeeded. • Complete code follows. Some error checking elided.

  20. function getShader(gl, id) { var script = document.getElementById(id); varshader;   if (script.type == "x-shader/x-vertex") { shader = gl.createShader(gl.VERTEX_SHADER);   } else if (script.type == "x-shader/x-fragment") { shader = gl.createShader(gl.FRAGMENT_SHADER);   } gl.shaderSource(shader, script.text); gl.compileShader(shader);   if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {     alert(gl.getShaderInfoLog(shader));     return null;   }   return shader; }

  21. Create shader function getShader(gl, id) { var script = document.getElementById(id); varshader;   if (script.type == "x-shader/x-vertex") { shader = gl.createShader(gl.VERTEX_SHADER);   } else if (script.type == "x-shader/x-fragment") { shader = gl.createShader(gl.FRAGMENT_SHADER);   } gl.shaderSource(shader, script.text); gl.compileShader(shader);   if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {     alert(gl.getShaderInfoLog(shader));     return null;   }   return shader; }

  22. function getShader(gl, id) { var script = document.getElementById(id); varshader;   if (script.type == "x-shader/x-vertex") { shader = gl.createShader(gl.VERTEX_SHADER);   } else if (script.type == "x-shader/x-fragment") { shader = gl.createShader(gl.FRAGMENT_SHADER);   } gl.shaderSource(shader, script.text); gl.compileShader(shader);   if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {     alert(gl.getShaderInfoLog(shader));     return null;   }   return shader; } Upload shader source code

  23. function getShader(gl, id) { var script = document.getElementById(id); varshader;   if (script.type == "x-shader/x-vertex") { shader = gl.createShader(gl.VERTEX_SHADER);   } else if (script.type == "x-shader/x-fragment") { shader = gl.createShader(gl.FRAGMENT_SHADER);   } gl.shaderSource(shader, script.text); gl.compileShader(shader);   if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {     alert(gl.getShaderInfoLog(shader));     return null;   }   return shader; } Compile shader

  24. function getShader(gl, id) { var script = document.getElementById(id); varshader;   if (script.type == "x-shader/x-vertex") { shader = gl.createShader(gl.VERTEX_SHADER);   } else if (script.type == "x-shader/x-fragment") { shader = gl.createShader(gl.FRAGMENT_SHADER);   } gl.shaderSource(shader, script.text); gl.compileShader(shader);   if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {     alert(gl.getShaderInfoLog(shader));     return null;   }   return shader; } Check compile status

  25. Loading the Shader Program • A program object combines the vertex and fragment shaders. • Load each shader separately. • Attach each to the program. • Link the program. • Check whether linking succeeded. • Prepare vertex attributes for later assignment. • Complete code follows.

  26. var program; function initShaders() {   program = gl.createProgram(); varvertexShader = getShader(gl, "shader-vs"); gl.attachShader(program, vertexShader); varfragmentShader = getShader(gl, "shader-fs"); gl.attachShader(program, fragmentShader); gl.linkProgram(program);   if (!gl.getProgramParameter(program, gl.LINK_STATUS))     alert("Could not initialiseshaders"); gl.useProgram(program); program.positionAttr = gl.getAttribLocation(program, "positionAttr"); gl.enableVertexAttribArray(program.positionAttr); program.colorAttr = gl.getAttribLocation(program, "colorAttr"); gl.enableVertexAttribArray(program.colorAttr); }

  27. Create program var program; function initShaders() {   program = gl.createProgram(); varvertexShader = getShader(gl, "shader-vs"); gl.attachShader(program, vertexShader); varfragmentShader = getShader(gl, "shader-fs"); gl.attachShader(program, fragmentShader); gl.linkProgram(program);   if (!gl.getProgramParameter(program, gl.LINK_STATUS))     alert("Could not initialiseshaders"); gl.useProgram(program); program.positionAttr = gl.getAttribLocation(program, "positionAttr"); gl.enableVertexAttribArray(program.positionAttr); program.colorAttr = gl.getAttribLocation(program, "colorAttr"); gl.enableVertexAttribArray(program.colorAttr); }

  28. Attach vertex shader var program; function initShaders() {   program = gl.createProgram(); varvertexShader = getShader(gl, "shader-vs"); gl.attachShader(program, vertexShader); varfragmentShader = getShader(gl, "shader-fs"); gl.attachShader(program, fragmentShader); gl.linkProgram(program);   if (!gl.getProgramParameter(program, gl.LINK_STATUS))     alert("Could not initialiseshaders"); gl.useProgram(program); program.positionAttr = gl.getAttribLocation(program, "positionAttr"); gl.enableVertexAttribArray(program.positionAttr); program.colorAttr = gl.getAttribLocation(program, "colorAttr"); gl.enableVertexAttribArray(program.colorAttr); }

  29. var program; function initShaders() {   program = gl.createProgram(); varvertexShader = getShader(gl, "shader-vs"); gl.attachShader(program, vertexShader); varfragmentShader = getShader(gl, "shader-fs"); gl.attachShader(program, fragmentShader); gl.linkProgram(program);   if (!gl.getProgramParameter(program, gl.LINK_STATUS))     alert("Could not initialiseshaders"); gl.useProgram(program); program.positionAttr = gl.getAttribLocation(program, "positionAttr"); gl.enableVertexAttribArray(program.positionAttr); program.colorAttr = gl.getAttribLocation(program, "colorAttr"); gl.enableVertexAttribArray(program.colorAttr); } Attach fragment shader

  30. var program; function initShaders() {   program = gl.createProgram(); varvertexShader = getShader(gl, "shader-vs"); gl.attachShader(program, vertexShader); varfragmentShader = getShader(gl, "shader-fs"); gl.attachShader(program, fragmentShader); gl.linkProgram(program);   if (!gl.getProgramParameter(program, gl.LINK_STATUS))     alert("Could not initialiseshaders"); gl.useProgram(program); program.positionAttr = gl.getAttribLocation(program, "positionAttr"); gl.enableVertexAttribArray(program.positionAttr); program.colorAttr = gl.getAttribLocation(program, "colorAttr"); gl.enableVertexAttribArray(program.colorAttr); } Link program and check link status

  31. var program; function initShaders() {   program = gl.createProgram(); varvertexShader = getShader(gl, "shader-vs"); gl.attachShader(program, vertexShader); varfragmentShader = getShader(gl, "shader-fs"); gl.attachShader(program, fragmentShader); gl.linkProgram(program);   if (!gl.getProgramParameter(program, gl.LINK_STATUS))     alert("Could not initialiseshaders"); gl.useProgram(program); program.positionAttr = gl.getAttribLocation(program, "positionAttr"); gl.enableVertexAttribArray(program.positionAttr); program.colorAttr = gl.getAttribLocation(program, "colorAttr"); gl.enableVertexAttribArray(program.colorAttr); } Tell GPU to use this program

  32. var program; function initShaders() {   program = gl.createProgram(); varvertexShader = getShader(gl, "shader-vs"); gl.attachShader(program, vertexShader); varfragmentShader = getShader(gl, "shader-fs"); gl.attachShader(program, fragmentShader); gl.linkProgram(program);   if (!gl.getProgramParameter(program, gl.LINK_STATUS))     alert("Could not initialiseshaders"); gl.useProgram(program); program.positionAttr = gl.getAttribLocation(program, "positionAttr"); gl.enableVertexAttribArray(program.positionAttr); program.colorAttr = gl.getAttribLocation(program, "colorAttr"); gl.enableVertexAttribArray(program.colorAttr); } Prepare vertex attributes for later use.

  33. Setting Up Geometry • Allocate buffer object on the GPU. • Upload geometric data containing all vertex streams. • Many options: interleaved vs. non-interleaved data, using multiple buffer objects, etc. • Generally, want to use as few buffer objects as possible. Switching is expensive.

  34. var buffer; function initGeometry() {   buffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, buffer);   // Interleave vertex positions and colors varvertexData = [     // Vertex 1 position     0.0,  0.8,  0.0,     // Vertex 1 Color     1.0, 0.0, 0.0, 1.0,     // Vertex 2 position     -0.8, -0.8,  0.0,     // Vertex 2 color     0.0, 1.0, 0.0, 1.0,     // Vertex 3 position     0.8, -0.8,  0.0,     // Vertex 3 color     0.0, 0.0, 1.0, 1.0   ]; gl.bufferData(gl.ARRAY_BUFFER,     new Float32Array(vertexData), gl.STATIC_DRAW); }

  35. Create a buffer and make it the current buffer for future operation var buffer; function initGeometry() {   buffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, buffer);   // Interleave vertex positions and colors varvertexData = [     // Vertex 1 position     0.0,  0.8,  0.0,     // Vertex 1 Color     1.0, 0.0, 0.0, 1.0,     // Vertex 2 position     -0.8, -0.8,  0.0,     // Vertex 2 color     0.0, 1.0, 0.0, 1.0,     // Vertex 3 position     0.8, -0.8,  0.0,     // Vertex 3 color     0.0, 0.0, 1.0, 1.0   ]; gl.bufferData(gl.ARRAY_BUFFER,     new Float32Array(vertexData), gl.STATIC_DRAW); }

  36. var buffer; function initGeometry() {   buffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, buffer);   // Interleave vertex positions and colors varvertexData = [     // Vertex 1 position     0.0,  0.8,  0.0,     // Vertex 1 Color     1.0, 0.0, 0.0, 1.0,     // Vertex 2 position     -0.8, -0.8,  0.0,     // Vertex 2 color     0.0, 1.0, 0.0, 1.0,     // Vertex 3 position     0.8, -0.8,  0.0,     // Vertex 3 color     0.0, 0.0, 1.0, 1.0   ]; gl.bufferData(gl.ARRAY_BUFFER,     new Float32Array(vertexData), gl.STATIC_DRAW); }

  37. var buffer; function initGeometry() {   buffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, buffer);   // Interleave vertex positions and colors varvertexData = [     // Vertex 1 position     0.0,  0.8,  0.0,     // Vertex 1 Color     1.0, 0.0, 0.0, 1.0,     // Vertex 2 position     -0.8, -0.8,  0.0,     // Vertex 2 color     0.0, 1.0, 0.0, 1.0,     // Vertex 3 position     0.8, -0.8,  0.0,     // Vertex 3 color     0.0, 0.0, 1.0, 1.0   ]; gl.bufferData(gl.ARRAY_BUFFER,     new Float32Array(vertexData), gl.STATIC_DRAW); } Upload data to the buffer on GPU

  38. Draw the Scene • Clear the viewing area. • Set up vertex attribute streams. • Issue the draw call.

  39. function drawScene() { gl.viewport(0, 0, canvas.width, canvas.height); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); gl.bindBuffer(gl.ARRAY_BUFFER, buffer);   // There are 7 floating-point values per vertex var stride = 7 * Float32Array.BYTES_PER_ELEMENT;   // Set up position stream gl.vertexAttribPointer(program.positionAttr,     3, gl.FLOAT, false, stride, 0);   // Set up color stream gl.vertexAttribPointer(program.colorAttr,     4, gl.FLOAT, false, stride,     3 * Float32Array.BYTES_PER_ELEMENT); gl.drawArrays(gl.TRIANGLES, 0, 3); }

  40. Set up a region to draw function drawScene() { gl.viewport(0, 0, canvas.width, canvas.height); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); gl.bindBuffer(gl.ARRAY_BUFFER, buffer);   // There are 7 floating-point values per vertex var stride = 7 * Float32Array.BYTES_PER_ELEMENT;   // Set up position stream gl.vertexAttribPointer(program.positionAttr,     3, gl.FLOAT, false, stride, 0);   // Set up color stream gl.vertexAttribPointer(program.colorAttr,     4, gl.FLOAT, false, stride,     3 * Float32Array.BYTES_PER_ELEMENT); gl.drawArrays(gl.TRIANGLES, 0, 3); }

  41. function drawScene() { gl.viewport(0, 0, canvas.width, canvas.height); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); gl.bindBuffer(gl.ARRAY_BUFFER, buffer);   // There are 7 floating-point values per vertex var stride = 7 * Float32Array.BYTES_PER_ELEMENT;   // Set up position stream gl.vertexAttribPointer(program.positionAttr,     3, gl.FLOAT, false, stride, 0);   // Set up color stream gl.vertexAttribPointer(program.colorAttr,     4, gl.FLOAT, false, stride,     3 * Float32Array.BYTES_PER_ELEMENT); gl.drawArrays(gl.TRIANGLES, 0, 3); }

  42. function drawScene() { gl.viewport(0, 0, canvas.width, canvas.height); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); gl.bindBuffer(gl.ARRAY_BUFFER, buffer);   // There are 7 floating-point values per vertex var stride = 7 * Float32Array.BYTES_PER_ELEMENT;   // Set up position stream gl.vertexAttribPointer(program.positionAttr,     3, gl.FLOAT, false, stride, 0);   // Set up color stream gl.vertexAttribPointer(program.colorAttr,     4, gl.FLOAT, false, stride,     3 * Float32Array.BYTES_PER_ELEMENT); gl.drawArrays(gl.TRIANGLES, 0, 3); } Draw one triangle

  43. Achieving High Performance • OpenGL "big rules" are to minimize: • Draw calls • Buffer, texture, and program binds • Uniform variable changes • State switches (enabling/disabling) • WebGL "big rule": • Offload as much JavaScript to the GPU as possible

  44. Picking in Google Body • Highly detailed 3D model – over a MILLION triangles • Selection is very fast (Thanks to Body team for this information)

  45. Picking in Google BodyThrough Ray Tracing • Could consider doing ray-casting in JavaScript • Attempt to do quick discards if ray doesn't intersect bounding box • Still a lot of math to do in JavaScript

  46. Picking in Google BodyThrough GPU • When model is loaded, assign different color to each organ • Upon mouse click: • Render body offscreen with different set of shaders • Use threshold to determine whether to draw translucent layers • Read back color of pixel under mouse pointer • Same technique works at different levels of granularity

  47. Particle Systems • Particle demo from WebGL wiki • author: gman@google.com • http://www.khronos.org/webgl/wiki/Demo_Repository • Animates ~2000 particles at 60 FPS • Does all the animation math on the GPU

  48. Particle Systems: Implementation • Each particle's motion is defined by a set of parameters • Set up motion parameters when particle is created • Initial position, velocity, acceleration, spin • Send down one parameter each frame: time • Vertex shader evaluates equation of motion, moves particle • Absolute minimum amount of JavaScript work done per frame

More Related