Created
August 23, 2013 02:01
-
-
Save jgroszko/6314805 to your computer and use it in GitHub Desktop.
A Simple WebGL Framework
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/********/ | |
/* Cube */ | |
/********/ | |
var Cube = function(gl, shaderProgram) { | |
this.gl = gl; | |
this.shaderProgram = shaderProgram; | |
var vertexData = [ | |
-1.0, -1.0, 1.0, 0.0, 0.0, 1.0, | |
1.0, -1.0, 1.0, 0.0, 0.0, 1.0, | |
1.0, 1.0, 1.0, 0.0, 0.0, 1.0, | |
-1.0, 1.0, 1.0, 0.0, 0.0, 1.0, | |
-1.0, -1.0, -1.0, 0.0, 0.0, -1.0, | |
-1.0, 1.0, -1.0, 0.0, 0.0, -1.0, | |
1.0, 1.0, -1.0, 0.0, 0.0, -1.0, | |
1.0, -1.0, -1.0, 0.0, 0.0, -1.0, | |
-1.0, 1.0, -1.0, 0.0, 1.0, 0.0, | |
-1.0, 1.0, 1.0, 0.0, 1.0, 0.0, | |
1.0, 1.0, 1.0, 0.0, 1.0, 0.0, | |
1.0, 1.0, -1.0, 0.0, 1.0, 0.0, | |
-1.0, -1.0, -1.0, 0.0, -1.0, 0.0, | |
1.0, -1.0, -1.0, 0.0, -1.0, 0.0, | |
1.0, -1.0, 1.0, 0.0, -1.0, 0.0, | |
-1.0, -1.0, 1.0, 0.0, -1.0, 0.0, | |
1.0, -1.0, -1.0, -1.0, 0.0, 0.0, | |
1.0, 1.0, -1.0, -1.0, 0.0, 0.0, | |
1.0, 1.0, 1.0, -1.0, 0.0, 0.0, | |
1.0, -1.0, 1.0, -1.0, 0.0, 0.0, | |
-1.0, 1.0, -1.0, 1.0, 0.0, 0.0, | |
-1.0, 1.0, 1.0, 1.0, 0.0, 0.0, | |
-1.0, -1.0, 1.0, 1.0, 0.0, 0.0, | |
-1.0, -1.0, -1.0, 1.0, 0.0, 0.0 | |
]; | |
this.vertexCount = 24; | |
this.vertexBuffer = gl.createBuffer(); | |
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); | |
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW); | |
var indexData = [ | |
0, 1, 2, 0, 2, 3, | |
4, 5, 6, 4, 6, 7, | |
8, 9, 10, 8, 10, 11, | |
12, 13, 14, 12, 14, 15, | |
16, 17, 18, 16, 18, 19, | |
20, 21, 22, 20, 22, 23 | |
]; | |
this.indexCount = 36; | |
this.indexBuffer = gl.createBuffer(); | |
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); | |
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indexData), gl.STATIC_DRAW); | |
shaderProgram.uniformValues.uColor = [0.8, 0.8, 0.8, 1.0]; | |
}; | |
Cube.prototype.draw = function() { | |
var gl = this.gl; | |
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); | |
gl.vertexAttribPointer(this.shaderProgram.getAttribLocation("aVertexPosition"), | |
3, gl.FLOAT, false, Float32Array.BYTES_PER_ELEMENT * 6, | |
0); | |
gl.vertexAttribPointer(this.shaderProgram.getAttribLocation("aNormal"), | |
3, gl.FLOAT, false, Float32Array.BYTES_PER_ELEMENT * 6, | |
Float32Array.BYTES_PER_ELEMENT * 3); | |
this.shaderProgram.apply(); | |
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); | |
gl.drawElements(gl.TRIANGLES, this.indexCount, gl.UNSIGNED_SHORT, 0); | |
}; | |
/**********/ | |
/* Camera */ | |
/**********/ | |
var Camera = function(gl, canvas) { | |
this.gl = gl; | |
this.canvas = canvas; | |
this.viewMatrix = mat4.lookAt([5.0, 5.0, 5.0], | |
[0.0, 0.0, 0.0], | |
[0.0, 1.0, 0.0]); | |
this.perspectiveMatrix = mat4.perspective(45, | |
canvas.width / canvas.height, | |
0.1, 100.0); | |
this.pvMatrix = mat4.multiply(this.perspectiveMatrix, this.viewMatrix, mat4.create()); | |
// So we're not allocating a new matrix on every apply() | |
this.nMatrix = mat4.create(); | |
}; | |
Camera.prototype.apply = function(shader, mMatrix) { | |
shader.uniformValues.uPVMatrix = this.pvMatrix; | |
shader.uniformValues.uMMatrix = mMatrix; | |
shader.uniformValues.uNMatrix = mat4.transpose(mat4.inverse(mMatrix, this.nMatrix)); | |
}; | |
/******************/ | |
/* Shader Program */ | |
/******************/ | |
var ShaderProgram = function(gl, vertexShaderId, fragmentShaderId) { | |
var fragmentShader = this._getShader(gl, fragmentShaderId), | |
vertexShader = this._getShader(gl, vertexShaderId), | |
shaderProgram = gl.createProgram(); | |
gl.attachShader(shaderProgram, vertexShader); | |
gl.attachShader(shaderProgram, fragmentShader); | |
gl.linkProgram(shaderProgram); | |
if(!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { | |
alert(gl.getShaderInfoLog(shaderProgram)); | |
return null; | |
} | |
gl.useProgram(shaderProgram); | |
this.uniformLocations = {}; | |
this.uniformValues = {}; | |
this.attribLocations = {}; | |
this.gl = gl; | |
this.shaderProgram = shaderProgram; | |
}; | |
ShaderProgram.prototype.getAttribLocation = function(name) { | |
if(!(name in this.attribLocations)) { | |
this.attribLocations[name] = this.gl.getAttribLocation(this.shaderProgram, name); | |
if(this.attribLocations[name] === -1) { | |
console.log("Unable to find attribute " + name); | |
} | |
} | |
return this.attribLocations[name]; | |
}; | |
ShaderProgram.prototype.enableAttributes = function() { | |
for(var attrname in this.attribLocations) { | |
if(this.attribLocations[attrname] >= 0) { | |
this.gl.enableVertexAttribArray(this.attribLocations[attrname]); | |
} | |
} | |
}; | |
ShaderProgram.prototype.getUniformLocation = function(name) { | |
if(!(name in this.uniformLocations)) { | |
var loc = this.gl.getUniformLocation(this.shaderProgram, name); | |
if(loc === null) { | |
console.log("Unable to find uniform " + name); | |
return null; | |
} | |
this.uniformLocations[name] = loc; | |
} | |
return this.uniformLocations[name]; | |
}; | |
ShaderProgram.prototype.applyUniforms = function() { | |
var gl = this.gl; | |
for(var name in this.uniformValues) { | |
var location = this.getUniformLocation(name); | |
if(location === null) { | |
console.log("Skipping " + name); | |
continue; | |
} | |
if(typeof this.uniformValues[name] === "boolean" || | |
typeof this.uniformValues[name] === "number") { | |
gl.uniform1i(location, this.uniformValues[name]); | |
} | |
else if(this.uniformValues[name].length >= 16) { | |
gl.uniformMatrix4fv(location, false, this.uniformValues[name]); | |
} | |
else if(this.uniformValues[name].length == 4) { | |
gl.uniform4fv(location, this.uniformValues[name]); | |
} | |
else if(this.uniformValues[name].length == 3) { | |
gl.uniform3fv(location, this.uniformValues[name]); | |
} | |
} | |
}; | |
ShaderProgram.prototype.apply = function() { | |
this.gl.useProgram(this.shaderProgram); | |
this.applyUniforms(); | |
this.enableAttributes(); | |
}; | |
ShaderProgram.prototype._getShader = function(gl, id) { | |
var elem = document.getElementById(id); | |
var source = ""; | |
var k = elem.firstChild; | |
while(k) { | |
if(k.nodeType == 3) { | |
source += k.textContent; | |
} | |
k = k.nextSibling; | |
} | |
var shader; | |
if(elem.type == 'x-shader/x-fragment') { | |
shader = gl.createShader(gl.FRAGMENT_SHADER); | |
} | |
else if(elem.type == 'x-shader/x-vertex') { | |
shader = gl.createShader(gl.VERTEX_SHADER); | |
} | |
else { | |
return null; | |
} | |
gl.shaderSource(shader, source); | |
gl.compileShader(shader); | |
if(!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { | |
alert(gl.getShaderInfoLog(shader)); | |
return null; | |
} | |
return shader; | |
}; | |
/*************************/ | |
/* requestAnimationFrame */ | |
/*************************/ | |
// shim layer with setTimeout fallback | |
// http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/ | |
window.requestAnimFrame = (function(){ | |
return window.requestAnimationFrame || | |
window.webkitRequestAnimationFrame || | |
window.mozRequestAnimationFrame || | |
function( callback ){ | |
window.setTimeout(callback, 1000 / 60); | |
}; | |
})(); | |
/***************/ | |
/* Application */ | |
/***************/ | |
var Application = function(){ | |
this.canvas = document.querySelector('canvas'); | |
this.gl = this.canvas.getContext("webgl"); | |
this.shaderProgram = new ShaderProgram(this.gl, "vertex_shader", "fragment_shader"); | |
this.camera = new Camera(this.gl, this.canvas); | |
this.cubeMMatrix = mat4.identity(mat4.create()); | |
this.cube = new Cube(this.gl, this.shaderProgram); | |
this.viewportWidth = this.canvas.width; | |
this.viewportHeight = this.canvas.height; | |
this.gl.clearColor(0.0, 0.0, 0.4, 1.0); | |
this.gl.enable(this.gl.DEPTH_TEST); | |
this.shaderProgram.uniformValues.uAmbientColor = [0.3, 0.3, 0.3]; | |
this.shaderProgram.uniformValues.uDirectionalColor = [0.3, 0.3, 0.3]; | |
this.shaderProgram.uniformValues.uLightingDirection = [0.25, 0.75, 0.25]; | |
this.draw(); | |
}; | |
Application.prototype.draw = function() { | |
var _this = this; | |
window.requestAnimFrame(function() { | |
_this.draw(); | |
}); | |
this.gl.viewport(0, 0, this.viewportWidth, this.viewportHeight); | |
this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT); | |
this.camera.apply(this.shaderProgram, this.cubeMMatrix); | |
this.shaderProgram.apply(this.shaderProgram, this.cubeMMatrix); | |
this.cube.draw(); | |
}; | |
var app = new Application(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Simple Framework</title> | |
</head> | |
<body> | |
<script type="x-shader/x-fragment" id="fragment_shader"> | |
precision highp float; | |
uniform vec4 uColor; | |
varying vec3 vLightWeighting; | |
void main(void) { | |
gl_FragColor = vec4(uColor.rgb * vLightWeighting, uColor.a); | |
} | |
</script> | |
<script type="x-shader/x-vertex" id="vertex_shader"> | |
attribute vec3 aNormal; | |
attribute vec3 aVertexPosition; | |
uniform mat4 uPVMatrix; | |
uniform mat4 uMMatrix; | |
uniform mat4 uNMatrix; | |
uniform vec3 uAmbientColor; | |
uniform vec3 uLightingDirection; | |
uniform vec3 uDirectionalColor; | |
varying vec3 vLightWeighting; | |
void main(void) { | |
gl_Position = uPVMatrix * uMMatrix * vec4(aVertexPosition, 1.0); | |
vec4 transformedNormal = uNMatrix * vec4(aNormal, 1.0); | |
float directionalLightWeighting = max(dot(transformedNormal.xyz, uLightingDirection), 0.0); | |
vLightWeighting = uAmbientColor + (uDirectionalColor * directionalLightWeighting); | |
} | |
</script> | |
<canvas width="640" height="480"></canvas> | |
<script src="//glmatrix.googlecode.com/files/glMatrix-0.9.5.min.js"></script> | |
<script src="Application.js"></script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment