Introduction to WebGL Programming

COS 350 - Computer Graphics

Example

Let's look closely at a simple example from text

Example

ClickedPoints.html

How does the program work?

Ignoring WebGL for the moment, what functionality is required?

ClickedPoints

open_canvas();
set_color();


What has to happen to draw points?

ClickedPoints

mouse_click_eventhandler() {
    get_mouse_location();
    draw_point(mouse_location);
}

javascript?

Draw Point

interact_with_video_card()
transfer_data()
tell_video_card_to_draw()

What else do we know?

Hide-then-expose browser window

ClickedPoints.html

Data?

Do we have a data structure?

ClickedPoints.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <title>Draw a point with a mouse click</title>
    </head>

    <body onload="main()">
        <canvas id="webgl" width="400" height="400">
        Please use a browser that supports "canvas"
        </canvas>

        <script src="lib/webgl-utils.js"></script>
        <script src="lib/webgl-debug.js"></script>
        <script src="lib/cuon-utils.js"></script>

        <script src="ClickedPoints.js"></script>
    </body>
</html>

ClickedPoints.html

<body onload="main()">

When is main() executed?

Where is main() found?

<canvas id="webgl" width="400" height="400">
Please use a browser that supports "canvas"
</canvas>

Name? Multiple canvases?

Canvas

Supports display image in web page, but

Even Simpler Example

Even Simpler Example

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <title>Draw a blue rectangle (canvas version)</title>
    </head>

    <body onload="main()">
        <canvas id="webgl" width="400" height="400">
        Please use a browser that supports "canvas"
        </canvas>

        <script src="DrawRectangle.js"></script>
    </body>
</html>

Even Simpler Example

// DrawTriangle.js (c) 2012 matsuda
function main() {  
    // Retrieve <canvas> element                        <- (1)
    var canvas = document.getElementById('webgl');  
    if (!canvas) { 
        console.log('Failed to retrieve the <canvas> element');
        return false; 
    } 

    // Get the rendering context for 2DCG               <- (2)
    var ctx = canvas.getContext('2d');

    // Draw a blue rectangle                            <- (3)
    // Set color to blue
    ctx.fillStyle = 'rgba(32, 32, 255, 1.0)';
    // Fill a rectangle with the color
    ctx.fillRect(120, 10, 150, 150);

    // Draw the corners of the rectangle
    ctx.fillStyle = 'rgba(255, 32, 32, 1.0)';
    ctx.fillRect(118, 8, 5, 5);
    ctx.fillStyle = 'rgba(32, 255, 32, 1.0)';
    ctx.fillRect(267, 157, 5, 5);
}

Canvas

var canvas = document.getElementByID('webgl');

Reference to canvas element

Rendering Context

Context

var ctx = canvas.getContext('2d');

Draw Rectangle

Set state

ctx.fillStyle = 'rgba(0, 0, 255, 1.0)';

Draw

ctx.fillRect(120, 10, 150, 150);

Draw Rectangle

Draw Rectangle

DrawRectangle uses HTML5 and canvas elements to draw simple 2D box in a window

WebGL - more complex

ClickedPoints main()

// retrieve canvas elements

// get rendering context

// initialize shaders

// get location of variables shared between main and shaders

// register event handler

// clear canvas

So, what code draws the boxes?

Canvas element and context

var canvas = document.getElementById('webgl');

var gl = getWebGLContext(canvas);

Note: this is different (not canvas.xxxxx())

Wrapper around setupWebGL(canvas) that allows debugging

setupWebGL is a function in webgl-utils.js, a standard library from Google

Initialize Shaders

Text files (or strings) as in OpenGL

OpenGL compiles

Embed as string in code

or

Read from file

Initialize Shaders

Functions provided to handle details

if(!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
    console.log('Failed to initialize shaders.');
    return;
}

"Shared" variables

Data transmitted to GPU

How can main() and shader code share data?

Cannot use global variables in shared memory

Cannot pass variables

So, transfer to GPU memory but must be able to connect

"Shared" variables

var a_Position = gl.getAttribLocation(gl.program, 'a_position');
//                           name in shader programs -^

Register event handler

canvas.onmousedown = function(ev) {
    click(ev, gl, canvas, a_Position);
};

Note: Anonymous function. Why?

Function must deal with location, what to do, etc. Should not rely on global variables.

But event handlers must have fixed signature (single parameter)

Clear Canvas

gl.clearColor(0.0, 0.0, 0.0, 1.0);  // set state of how to clear

gl.clear(gl.COLOR_BUFFER_BIT);      // do clearing!

So...

Where are the points drawn in response to mouse click?

Set up data

var g_points = [];

Then, define click() which is called by mouse click

Set up data

function click(ev, gl, canvas, a_Position) {
    // NOTE: a_Position is target for data on GPU

    var x = ev.clientX;
    var y = ev.clientY;

    // ...
}

Set up data

Convert mouse locations to coordinates in window

var rect = ev.target.getBoundingClientRect();

x = ((x - rect.left) - canvas.width/2) / (canvas.width/2);
y = (canvas.height/2 - (y - rect.top)) / (canvas.height/2);

Set up data

Set up data

g_points.push(x);
g_points.push(y);

What happens to data structure?

Looks like an array, treat as stack

Copy data to video card

var len = g_points.length;

for(var i = 0; i < len; i += 2) {
    gl.vertexAttrib3f(a_Position, g_points[i], g_points[i+1], 0.0);
    // functionName3f
    //     3 parameters type float

    gl.drawArrays(gl.Points, 0, 1);
    //             ^         ^  ^- draw 1 point
    //             |          \--- begin at 0
    //              \------------- what to draw
}

Copy data to video card

Copy data to video card

Efficiency?

Transfer 1 point, draw

Lots of communication

Data collection is handled in main() but passed to video card 1 at a time

processing flow

Shader programs

Shader programs

var VSHADER_SOURCE =
    'attribute vec4 a_Position;\n' +
    'void main() {\n' +
    '   gl_Position = a_Position;\n' +
    '   gl_PointSize = 10.0;\n' +
    '}\n';

Set position of vertex to be passed through system

Shader programs

var FSHADER_SOURCE =
    'void main() {\n' +
    '   gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' +
    '}\n';

Single string, function main()

gl_FragColor fragment color set to red

loading...