Pare down your WebGL scripts with Browserify and a few supporting modules on simple scenes. The result is a smaller Javascript bundle with only the required code. While Three.js is a nice comprehensive library, including it can be overkill for a basic scene.
npm init
to
create a package.json. This file defines project dependencies.
mkdir 3dify
cd 3dify
npm init
npm install browserify-shader --save-dev
npm install glmat-4 --save
var mat4 = require('gl-mat4');
var svs = require('./vertex.c');
var sfs = require('./fragment.c');
setup();
// Adds a canvas to the page and start rendering the scene
function setup() {
var body = document.getElementsByTagName('body')[0];
var glCanvas = getCanvas(body);
//create a simple renderer and a simple triangle
var renderer = simpleRenderer(glCanvas.gl, 1, new Float32Array([-0.5,-0.5,-1.0,0.0,0.5,-1.0,0.5,-0.5,-1.0]));
//Create a matrix to transform the triangle
var matrix = mat4.create();
//Move it back 4 units
mat4.translate(matrix, matrix, [0.0, 0.0, -4.0]);
//Called when a frame is scheduled. A rapid sequence of scene draws creates the animation effect.
var renderFn = function(timestamp) {
mat4.rotateY(matrix, matrix, Math.PI/128);
renderer(matrix, [1, 0, 1]);
window.requestAnimationFrame(renderFn);
}
window.requestAnimationFrame(renderFn);
}
// Get A WebGL context
function getCanvas(parent) {
//Create a canvas with specified attributes and append it to the parent.
var canvas = document.createElement('canvas');
canvas.setAttribute('id', 'glcanvas');
canvas.setAttribute('width', '400');
canvas.setAttribute('height', '400');
parent.appendChild(canvas);
var gl = canvas.getContext('webgl');
return {canvas: canvas, gl : gl}
}
//Returns a simple rendering function that draws the passed in vertices.
function simpleRenderer(gl, aspect, vertices) {
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, svs());
gl.compileShader(vertexShader);
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, sfs());
gl.compileShader(fragmentShader);
var shaders = [vertexShader, fragmentShader];
var program = gl.createProgram();
shaders.forEach(function(shader) {
gl.attachShader(program, shader);
})
gl.linkProgram(program);
return function(parentNode, color) {
gl.clear(gl.GL_COLOR_BUFFER_BIT);
//Field of view is very similar to a cameras field of view.
var fieldOfView = Math.PI/2;
//Far edge of scene defines how far away an object can be from the camera before it disappears.
var farEdgeOfScene = 100;
//Near edge of scene defines how close an object can be from the camera before it disappears.
var nearEdgeOfScene = 1;
//Creates a perspective transformation from the above parameters.
var perspective = mat4.perspective(mat4.create(), fieldOfView, aspect, nearEdgeOfScene, farEdgeOfScene);
//Apply perspective to the parent transformation (translate + rotation)
var projection = mat4.multiply(mat4.create(), perspective, parentNode);
gl.useProgram(program);
var matrixLocation = gl.getUniformLocation(program, "u_matrix");
// Set the matrix.
gl.uniformMatrix4fv(matrixLocation, false, projection);
// set the color
var colorLocation = gl.getUniformLocation(program, "u_color");
gl.uniform4f(colorLocation, color[0], color[1], color[2], 1.0);
// Create a buffer for the positions
var vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
// look up where the vertex data needs to go.
var positionLocation = gl.getAttribLocation(program, "a_position");
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
gl.drawArrays(gl.TRIANGLES, 0, vertices.length/3);
}
}
precision mediump float;
uniform vec4 u_color;
void main() {
gl_FragColor = u_color;
}
attribute vec4 a_position;
uniform mat4 u_matrix;
void main() {
gl_Position = u_matrix * a_position;
}
Run watchify to watch files and compile them into a single bundle.js javascript file. Here the use of browserify-shader plugin allows the GLSL shaders to be require'd into the script. And --debug tells watchify to create a source map for managable source viewing/debugging
watchify --debug -t browserify-shader index.js -o bundle.js
To the right is an animation using the bundle.js created with the above source files and watchify.