WebGL (Abstraction) for All
James Milner
@JamesLMilner
loxodrome.io
WebGL?
WebGL is a library for displaying graphics in the browser
It Uses HTML5 Canvas
Why WebGL?
But...
Greg Tavares
"what many people don't [realise] is that WebGL is a rasterization API, not a 3D API"
It's API is also low level
Alongside our WebGL JavaScript API we require shaders
Vertex Shaders, Fragment Shaders
Introducing GLSL ES
Graphics Library Shader Language
<!-- Drawing a green square -->
<script id="2d-vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;
void main() {
gl_Position = vec4(a_position, 0, 1); // X, Y, Z, W
}
</script>
<script id="2d-fragment-shader" type="x-shader/x-fragment">
void main() {
gl_FragColor = vec4(0, 1, 0, 1); // Green (RGBA)
}
</script>
Credit: dev.opera.com
Lets Examine Some Code...
<html>
<head>
<title>Learning WebGL — lesson 1</title>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
<script type="text/javascript" src="glMatrix-0.9.5.min.js"></script>
<script id="shader-fs" type="x-shader/x-fragment">
precision mediump float;
void main(void) {
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
</script>
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec3 aVertexPosition;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
void main(void) {
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
}
</script>
<script type="text/javascript">
var gl;
function initGL(canvas) {
try {
var gl = canvas.getContext("experimental-webgl");
if (!gl) {
gl = canvas.getContext("webgl");
}
gl.viewportWidth = canvas.width;
gl.viewportHeight = canvas.height;
} catch (e) {
}
if (!gl) {
alert("Could not initialise WebGL, sorry :-(");
}
}
function getShader(gl, id) {
var shaderScript = document.getElementById(id);
if (!shaderScript) {
return null; // No shader script with that id
}
var str = ""; //concatenate the whole shader together
var k = shaderScript.firstChild;
while (k) {
if (k.nodeType == 3) { //text will have nodeType property will return 3.
str += k.textContent;
}
k = k.nextSibling;
}
var shader;
if (shaderScript.type == "x-shader/x-fragment") {
shader = gl.createShader(gl.FRAGMENT_SHADER); // if fragment
} else if (shaderScript.type == "x-shader/x-vertex") {
shader = gl.createShader(gl.VERTEX_SHADER); // if vertex
} else {
return null;
}
gl.shaderSource(shader, str); // link type and source
gl.compileShader(shader); // compile shader
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert(gl.getShaderInfoLog(shader));
return null;
}
return shader;
}
var shaderProgram;
function initShaders() {
var fragmentShader = getShader(gl, "shader-fs");
var vertexShader = getShader(gl, "shader-vs");
shaderProgram = gl.createProgram(); // create shader program
gl.attachShader(shaderProgram, vertexShader); // add vertex shader
gl.attachShader(shaderProgram, fragmentShader); // add vertex shader
gl.linkProgram(shaderProgram); // Link the two to program
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert("Could not initialise shaders");
}
gl.useProgram(shaderProgram);
shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
}
var mvMatrix = mat4.create(); // glMatrix functions
var pMatrix = mat4.create();
function setMatrixUniforms() {
gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, pMatrix);
gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mvMatrix);
}
var triangleVertexPositionBuffer;
var squareVertexPositionBuffer;
function initBuffers() {
//Triangle
triangleVertexPositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);
var vertices = [
0.0, 1.0, 0.0,
-1.0, -1.0, 0.1,
1.0, -1.0, 0.0
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
triangleVertexPositionBuffer.itemSize = 3;
triangleVertexPositionBuffer.numItems = 3;
//Square
squareVertexPositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer);
vertices = [
1.0, 1.0, 0.0,
-1.0, 1.0, 0.0,
1.0, -1.0, 0.0,
-1.0, -1.0, 0.0
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
squareVertexPositionBuffer.itemSize = 3;
squareVertexPositionBuffer.numItems = 4;
}
function drawScene() {
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// Clears the color and depth buffers
mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, pMatrix);
// Field of View = 45 , width-to-height ratio of canvas, min view distance, max view distance
mat4.identity(mvMatrix);
mat4.translate(mvMatrix, [-1.5, 0.0, -7.0]);
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, triangleVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
setMatrixUniforms();
gl.drawArrays(gl.TRIANGLES, 0, triangleVertexPositionBuffer.numItems);
mat4.translate(mvMatrix, [3.0, 0.0, 0.0]);
gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, squareVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
setMatrixUniforms();
gl.drawArrays(gl.TRIANGLE_STRIP, 0, squareVertexPositionBuffer.numItems);
}
function webGLStart() {
var canvas = document.getElementById("lesson01-canvas"); //Get Canvas
initGL(canvas);
initShaders();
initBuffers();
gl.clearColor(0.0, 0.0, 0.0, 1.0); //Black
gl.enable(gl.DEPTH_TEST);
drawScene();
}
</script>
</head>
<body onload="webGLStart();">
<a href="http://learningwebgl.com/blog/?p=28"><< Back to Lesson 1</a><br />
<canvas id="lesson01-canvas" style="border: none;" width="500" height="500"></canvas>
<br/>
<a href="http://learningwebgl.com/blog/?p=28"><< Back to Lesson 1</a><br />
</body>
</html>
Frameworks will help us move faster
Raw WebGL
TWGL
Three.js
Babylon.js
Scene.js
OSG.js
GLGE
Increasing Abstraction
CopperLicht
PhiloGL
Which is best?
It depends
I like Three.js
WebGL & libraries have great potential & use cases
Here's some examples of places I've ended up using it
WebGL in Academia
Lacuna: a 3D Web GIS
WebGL for Fun
WebGL in my Day Job
Take Aways
- WebGL is great but has a low level API
- Abstraction libraries help here
- Give a library a try, build something cool
- Appreciate feedback on our latest JS API!
Thanks
WebGL (Abstraction) for All
By James Milner
WebGL (Abstraction) for All
How to leverage abstraction libraries for WebGL for fun, knowledge and profit.
- 1,623