Introduction to OpenGL/GLSL and WebGL

GLSL Objectives n Give you an overview of the software that you will be using this semester

n OpenGL, WebGL, and GLSL

n What are they?

n How do you use them?

n What does the code look like?

n Evolution

n All of them are required to write modern graphics code, although alternatives exist What is OpenGL? n An application programming interface (API) n A (low-level) Graphics rendering API n Generate high-quality images from geometric and image primitives Maximal Portability n Display device independent n Window system independent n independent

Without a standard API (such as OpenGL) - impossible to port

(100, 50) Line(100,50,150,80) - device/lib 1

(150, 100) Moveto(100,50) - device/lib 2 Lineto(150,100) Brief History of OpenGL n Originated from a proprietary API called Iris GL from , Inc. n Provide access to graphics hardware capabilities at the lowest possible level that still provides hardware independence n The evolution is controlled by OpenGL Architecture Review Board, or ARB. n OpenGL 1.0 API finalized in 1992, first implementation in 1993 n In 2006, OpenGL ARB became a workgroup of the n 10+ revisions since 1992 OpenGL Evolution n 1.1 (1997): vertex arrays and texture objects n 1.2 (1998): 3D textures n 1.3 (2001): cubemap textures, compressed textures, multitextures n 1.4 (2002): generation, shadow map textures, etc n 1.5 (2003): vertex buffer object, shadow comparison functions, occlusion queries, non- power-of-2 textures OpenGL Evolution n 2.0 (2004): vertex and fragment shading (GLSL 1.1), , etc n 2.1 (2006): GLSL 1.2, pixel buffer objects, etc n 3.0 (2008): GLSL 1.3, deprecation model, etc n 3.1 (2009): GLSL 1.4, texture buffer objects, move much of deprecated functions to ARB compatible extension n 3.2 (2009) n 4.X (2012 and on) OpenGL Basics

n OpenGL’s primary function – Rendering n Rendering? – converting geometric/mathematical object descriptions into frame buffer values n OpenGL can render:

n Geometric primitives

n Bitmaps and Images (Raster primitives) OpenGL Example

Cube with flat color Cube with lighting Cube with textures WebGL n JavaScript implementation of OpenGL

n Run in all modern browsers (Chrome, Safari, Firefox, IE, etc).

n Application can be located on a remote server

n Rendering is done within browser using local hardware

n Uses HTML5

n Integrated with standard Web packages and apps (CSS, jQuery, etc.) What do you need to know n Web Environment and Execution n Modern OpenGL basics

n Pipeline architecture

n (vertex and fragment) based OpenGL

n OpenGL (GLSL) n Javascript OpenGL ES and WebGL n OpenGL ES

n A subset of OpenGL 3.1 API (lightweight)

n Designed for (mobile phones etc.)

n based n WebGL

n Javascript implementation of ES 2.0

n Runs on browswers WebGL Rendering Pipeline WebGL Programming n General Structure:

n Set up canvas to render to

n Generate data/geometry in application

n Create shader programs

n Create buffer objects and load data to them

n Connect buffer objects and data to shader variables

n Set up proper viewing and lighting conditions

n Render WebGL Programming n WebGL needs a place to render into

n HTML5 canvas element n All the code can be put in a single HTML file n Or you can put setup code in an HTML file and your application code in separate Javascript files

n HTML file includes shaders

n HTML file reads in application and utilities Example 0

n A very simple example that creates a canvas but display nothing except a yellow background

hwshen WebGL — code00 WebGL Javascript
code00.js

var gl; function webGLStart() { function initGL(canvas) { var canvas = document.getElementById("code00- try { canvas"); gl = canvas.getContext("experimental-"); initGL(canvas); gl.viewportWidth = canvas.width; gl.clearColor(1.0, 1.0, 0.0, 1.0); // yellow gl.viewportHeight = canvas.height; drawScene(); } catch (e) { } } if (!gl) { alert("Could not initialise WebGL, sorry :-("); } viewport } function drawScene() { gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); } Simple OpenGL commands n HTML will call webGLStart(); n canvas is an HTML5 element for drawing n You need a OpenGL context from the canvas for storing internal states

n canvas.getContext(); n All OpenGL commands in WebGL start with ‘gl.’

n gl.viewport(); specify the display area

n gl.clearColor(); specify the background color

n gl.clear(); clear the foreground and background Output Example 1 n Now let’s draw something (two triangles) on the canvas n You will need to provide vertex and fragment shaders n Github: https://github.com/imindseye/WebGL- tutorial simple-triangles.html

hwshen WebGL — code01 Fragment Vertex Shader simple-triangles.html (cont’d)


simple-triangles.js var gl; function initGL(canvas) { function webGLStart() { // same as before …. var canvas = document.getElementById("code00- canvas"); … initGL(canvas); } initShaders(); function initShaderers() { initBuffers(); // setup shaders gl.clearColor(1.0, 1.0, 0.0, 1.0); // yellow // load the , compile and link the code drawScene(); // in shaders_setup.js } } function initBuffers() { // set up vertex buffer objects for geometry // I will explain next … function drawScene() } gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer); gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, squareVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0); gl.drawArrays(gl.TRIANGLE_STRIP, 0, squareVertexPositionBuffer.numItems); } Output simple-triangles.js n In order to fully understand open-canvas.js, we need to explain

n Vertex Buffer Objects – this is how you define your geometry

n Shader setup and simple GLSL concepts

n How to draw the scene n Below I will start with Shaders setup and then Vertex Buffer Objects (VBO) OpenGL Shading Language (GLSL) n A -like language and incorporated into OpenGL 2.0 and on n Used to write vertex program and fragment program n No distinction in the syntax between a vertex program and a fragment program n Platform independent Setup of Shader Prgorams n A shader is defined as an array of strings n Steps to set up shaders

1. Create a shader program

2. Create shader objects (vertex and fragment)

3. Send source code to the shader objects

4. Compile the shader

1. Create program object by linking compiled shaders together

2. Use the linked program object shaders_setup.js function initShaders() {

shaderProgram = gl.createProgram(); // create a shader program

var fragmentShader = getShader(gl, "shader-fs"); // create and compile a vertex shader object var vertexShader = getShader(gl, "shader-vs"); // create and compile a fragment shader object

gl.attachShader(shaderProgram, vertexShader); // attach the vertex shader to the shader program gl.attachShader(shaderProgram, fragmentShader); // attach the fragment shader gl.linkProgram(shaderProgram); // link the vertex and fragment shaders

if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { alert("Could not initialise shaders"); }

gl.useProgram(shaderProgram); // use the shader program } shaders_setup.js

function getShader(gl, id) { var shaderScript = document.getElementById(id); if (!shaderScript) { return null; } var str = ""; var shader; var k = shaderScript.firstChild; while (k) { if (shaderScript.type == "x-shader/x-fragment") { if (k.nodeType == 3) { shader = gl.createShader(gl.FRAGMENT_SHADER); str += k.textContent; } else if (shaderScript.type == "x-shader/x-vertex") { } shader = gl.createShader(gl.VERTEX_SHADER); k = k.nextSibling; } else { } return null; } gl.shaderSource(shader, str); gl.compileShader(shader);

if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { alert(gl.getShaderInfoLog(shader)); return null; } return shader; } Vertex Buffer Objects

n Provide per-vertex input to the GPU

n Vertex: a point where the edges of geometry meet

n All geometric primitives are composed of vertices, their attributes, and the connectivity n Allow significant increases in vertex throughput between CPU and GPU n The mechanism to provide generic attributes to the shader, and store vertex data in video memory

n User’s program is free to define an arbitrary set of per- vertex attributes to the vertex shader Create a VBO

n Step 1: generate a new buffer object with gl.createBuffer()

n This function returns an identifier for the buffer object n Step 2: Bind the buffer with a particular buffer type with gl.bindBuffer()

n Specify the target (i.e. what kind of buffer) to which the buffer object is bound

n Choice: gl.ARRAY_BUFFER, gl.ELEMENT_ARRAY_BUFFER, gl.PIXEL_PACK_BUFFER, gl.PIXEL_UNPACK_BUFFER

n gl.ARRAY_BUFFER is to provide vertex attributes, and

n gl.ELEMENT_ARRAY_BUFFER is to provide triangle indices n Step 3: Copy the vertex data to the buffer object

n gl.bufferData(target, data, usage)

n Usage is the access pattern: gl.STATIC_, gl.STREAM_, gl.DYNAMIC_{DRAW, COPY, READ} simple-triangles.js var gl; function initGL(canvas) { function webGLStart() { // same as before …. var canvas = document.getElementById("code00- canvas"); … initGL(canvas); } initShaders(); function initShaderers() { initBuffers(); // setup shaders gl.clearColor(1.0, 1.0, 0.0, 1.0); // yellow // load the source, compile and link the code drawScene(); // in shaders_setup.js } } function initBuffers() { // set up vertex buffer objects for geometry // I will explain next … function drawScene() } gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer); gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, squareVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0); gl.drawArrays(gl.TRIANGLE_STRIP, 0, squareVertexPositionBuffer.numItems); } simple-triangles.js function initBuffers() { squareVertexPositionBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer); vertices = [ -0.5, -0.5, 0.0, 3 numbers (x,y,z) per vertex 0.5, -0.5, 0.0, 0.5, 0.5, 0.0, 6 vertices total -0.5, -0.5, 0.0, This is for our own book 0.5, 0.5, 0.0, Keeping. not related to WebGL -0.5, 0.5, 0.0 ]; gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); squareVertexPositionBuffer.itemSize = 3; squareVertexPositionBuffer.numItems = 6; }

The data are now sent to GPU I will talk about how to draw the buffer in a moment, but let me first talk about setting up shaders simple-triangles.js

Use VBO for drawing: 1.Make the vbo created earlier as active - gl.bindBuffer() 2.Connect the buffer to an vertex attribute in the shader (explained next) 3.Draw the vertex array – gldrawArrays(type, offset, numbers of vertices)

The buffer we created earlier function drawScene() { gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer); gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, squareVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0); gl.drawArrays(gl.TRIANGLES, 0, squareVertexPositionBuffer.numItems); } simple-triangles.js

Use VBO for drawing: 1.Make the vbo created earlier as active - gl.bindBuffer() 2.Connect the buffer to an vertex attribute in the shader (explained next) 3.Draw the vertex array – gldrawArrays(type, offset, numbers of vertices) function drawScene() { gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer); gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, squareVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0); gl.drawArrays(gl.TRIANGLE_STRIP, 0, squareVertexPositionBuffer.numItems); } simple-triangles.js

Use VBO for drawing: 1.Make the vbo created earlier as active - gl.bindBuffer() 2.Connect the buffer to an vertex attribute in the shader 3.Draw the vertex array – gldrawArrays(type, offset, numbers of vertices) Location of the vertex attribute in the shader: How many floats in each vertex Explained in the next slide

function drawScene() { gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer); gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, squareVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0); gl.drawArrays(gl.TRIANGLES, 0, squareVertexPositionBuffer.numItems); } How many vertices to pass simple-triangles.js

What is “Location of Vertex Attribute in the shader” and how to get it? Vertex shader in HTML This is the attribute variable in the attribute vec3 aVertexPosition; shader where the vertex position buffer object is connected to void main(void) { gl_Position = vec4(aVertexPosition, 1.0); code01.js }

Query the location of the variable simple-triangles.js

Now Connect the buffer to an vertex attribute in the shader

simple-triangles.js function drawScene() { gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer); gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, squareVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0); gl.drawArrays(gl.TRIANGLES, 0, squareVertexPositionBuffer.numItems); } color-triangles.js

n How to add more than one vertex attribute?

n You can add as many vertex attributes as you want

n code02.html

How to pass vertex color? attribute vec3 aVertexPosition; attribute vec3 aVertexColor; varying vec4 vColor;

void main(void) { gl_Position = vec4(aVertexPosition, 1.0); vColor = vec4(aVertexColor, 1.0); } color-triangles.js n Query the locations of both aVertexPosition and aVeretxColor color-triangles.js shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);

shaderProgram.vertexColorAttribute = gl.getAttribLocation(shaderProgram, "aVertexColor"); gl.enableVertexAttribArray(shaderProgram.vertexColorAttribute);

n Create another VBO for color (next page) color-triangles.js n Create a color VBO

color-triangles.js squareVertexColorBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexColorBuffer); var colors = [ 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0 ]; gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW); squareVertexColorBuffer.itemSize = 3; // RGBA four components squareVertexColorBuffer.numItems = 4; // four colors

Again, note these two are not part of VBO. Just record it down For later use in drawScene() color-triangles.js

n Now draw with both position and color VBOs

color-triangles.js function drawScene() { gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer); gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, squareVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);

gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexColorBuffer); gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, squareVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0);

gl.drawArrays(gl.TRIANGLE_STRIP, 0, squareVertexPositionBuffer.numItems);

} WebGL Geometric Primitives

POINTS, LINES, TRIANGLES WebGL Geometric Primitives More TRIANGLES Compact TRIANGLE FAN Var vertices = [ v1 v3.x , v3.y, v3.z, Var vertices = [ v1.x , v1.y, v1.z, v1.x , v1.y, v1.z, v2.x , v2.y, v2.z, T1 v3 v2 v2.x , v2.y, v2.z, T1 v4.x , v4.y, v4.z, T2 v3.x , v3.y, v3.z, v5.x , v5.y, v5.z T3 v2.x , v2.y, v2.z, ]; v4 v3.x , v3.y, v3.z, T2 v5 v4.x , v4.y, v4.z, TRIANGLE STRIP v3.x , v3.y, v3.z, v4.x , v4.y, v4.z, T3 Var vertices = [ v5.x , v5.y, v5.z v1.x , v1.y, v1.z, ]; v2.x , v2.y, v2.z, v3.x , v3.y, v3.z, v4.x , v4.y, v4.z, v5.x , v5.y, v5.z ]; Indexed Triangles n A more general way to represent a triangle set n Store vertex positions and their connectivity separately

v1 var vertices = [ var indices = [ v1.x , v1.y, v1.z, 0, 1, 2, 1, 3, 2, 2, 3, 4 v2.x , v2.y, v2.z, ] T1 v2 v3 v3.x , v3.y, v3.z, T2 v4.x , v4.y, v4.z, T3 v5.x , v5.y, v5.z T1 T2 T3 v4 ]; v5 n How to represent this way using VBO? Element Array for Triangle Indices n A more general way to represent a triangle set n Element-array.html/js in class

// create an Array Buffer for the vertex positions as before … …

// now create an element array buffer for the indices

var indices = [0,1,2,1,3,2,2,3,4]; VertexIndexBuffer = gl.createBuffer(); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, VertexIndexBuffer); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW); VertexIndexBuffer.itemsize = 1; VertexIndexBuffer.numItems = 9; // 9 index numbers in the buffer, used later Element Array for Triangle Indices n Now draw the triangles …. gl.bindBuffer(gl.ARRAY_BUFFER, VertexPositionBuffer); gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, VertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);

gl.bindBuffer(gl.ARRAY_BUFFER, VertexColorBuffer); gl.vertexAttribPointer(shaderProgram.ColorAttribute, VertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0);

// draw elementary arrays - triangle indices gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, VertexIndexBuffer);

gl.drawElements(gl.TRIANGLES, VertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);

Offset, meaning you can draw a partial set if you want