Skip to content

Instantly share code, notes, and snippets.

@mathdoodle
Last active February 11, 2018 13:50
Show Gist options
  • Save mathdoodle/69a4edb74810531611d1 to your computer and use it in GitHub Desktop.
Save mathdoodle/69a4edb74810531611d1 to your computer and use it in GitHub Desktop.
WebGL Fundamentals

WebGL Fundamentals

Overview

Demonstrates the fundamentals of using the WebGL API.

/**
* Converts a null argument into an exception.
* reason is the error message reported if the arg is null.
*/
export function denullify<T>(reason: string, arg: T | null): T {
if (arg !== null) {
return arg
}
else {
throw new Error(reason)
}
}
/**
* Interprets a null argument as an out of memory condition.
*/
export function memcheck<T>(arg: T | null): T {
return denullify("Out of memory", arg)
}
<!DOCTYPE html>
<html>
<head>
<base href='/'>
<script src='https://jspm.io/[email protected]'></script>
<link rel='stylesheet' href='style.css'>
</head>
<body>
<canvas id='my-canvas' width='500' height='500'>
Your browser does not support the HTML5 canvas element.
</canvas>
<script>
System.defaultJSExtensions = true
System.import('./script')
</script>
</body>
</html>
/**
*
*/
export function initWebGL(canvas: HTMLCanvasElement): WebGLRenderingContext {
// Try to grab the standard context. If it fails, fallback to experimental.
const context = canvas.getContext('webgl') || canvas.getContext('experimental-webgl')
if (context) {
return context
}
else {
throw new Error("Unable to initialize WebGL. Your browser may not support it.")
}
}
import { memcheck } from './denullify'
/**
* Creates a WebGLProgram with compiled and linked shaders.
*/
export function makeProgram(gl: WebGLRenderingContext, vertexShader: string, fragmentShader: string): WebGLProgram {
const vs = memcheck(gl.createShader(gl.VERTEX_SHADER))
gl.shaderSource(vs, vertexShader)
gl.compileShader(vs)
if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS)) {
throw new Error(memcheck(gl.getShaderInfoLog(vs)))
}
const fs = memcheck(gl.createShader(gl.FRAGMENT_SHADER))
gl.shaderSource(fs, fragmentShader)
gl.compileShader(fs)
if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS)) {
throw new Error(memcheck(gl.getShaderInfoLog(fs)))
}
const program = memcheck(gl.createProgram())
gl.attachShader(program, vs)
gl.attachShader(program, fs)
gl.linkProgram(program)
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
throw new Error(memcheck(gl.getProgramInfoLog(program)))
}
return program
}
{
"name": "webgl",
"version": "1.0.0",
"description": "WebGL Fundamentals",
"dependencies": {
"DomReady": "1.0.0",
"gl-matrix": "2.3.2"
},
"author": "David Geo Holmes",
"keywords": [
"WebGL",
"shaders",
"low level",
"GLSL",
"Graphics",
"mathdoodle"
],
"linting": true,
"hideConfigFiles": true
}
import { denullify, memcheck } from './denullify'
import { initWebGL } from './initWebGL'
import { makeProgram } from './makeProgram'
DomReady.ready(main)
function main() {
const canvas = <HTMLCanvasElement> document.getElementById('my-canvas')
const gl: WebGLRenderingContext = initWebGL(canvas)
// Compile and link the shaders into a program.
const vs_source = denullify('shader-vs does not exist in DOM', document.getElementById('shader-vs')).innerText
const fs_source = denullify('shader-fs does not exist in DOM', document.getElementById('shader-fs')).innerText
const program = makeProgram(gl, vs_source, fs_source)
gl.useProgram(program)
const colors: number[] = [
// front face
1.0, 0.0, 0.0, // 0
1.0, 0.0, 0.0, // 1
1.0, 0.0, 0.0, // 2
0.0, 0.0, 1.0, // 3
0.0, 0.0, 1.0, // 4
0.0, 0.0, 1.0, // 5
// rear face
1.0, 0.0, 0.0, // 6
1.0, 0.0, 0.0, // 7
1.0, 0.0, 0.0, // 8
0.0, 0.0, 1.0, // 9
0.0, 0.0, 1.0, // 10
0.0, 0.0, 1.0 // 11
]
const cbo = memcheck(gl.createBuffer())
gl.bindBuffer(gl.ARRAY_BUFFER, cbo)
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW)
const vertices: number[] = [
0.0, 0.0, 0.0, // 0
1.0, 0.0, 0.0, // 1
2.0, 0.0, 0.0, // 2
0.5, 1.0, 0.0, // 3
1.5, 1.0, 0.0, // 4
1.0, 2.0, 0.0, // 5
0.0, 0.0, -2.0, // 6
1.0, 0.0, -2.0, // 7
2.0, 0.0, -2.0, // 8
0.5, 1.0, -2.0, // 9
1.5, 1.0, -2.0, // 10
1.0, 2.0, -2.0 // 11
]
const vbo = memcheck(gl.createBuffer())
gl.bindBuffer(gl.ARRAY_BUFFER, vbo)
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW)
const indices: number[] = [
// front face
0, 1, 3, // 0
1, 3, 4, // 1
1, 2, 4, // 2
3, 4, 5, // 3
// rear face
6, 7, 9, // 4
7, 9, 10, // 5
7, 8, 10, // 6
9, 10, 11, // 7
// left side
0, 3, 6, // 8
3, 6, 9, // 9
3, 5, 9, // 10
5, 9, 11, // 11
// right side
2, 4, 8, // 12
4, 8, 10, // 13
4, 5, 10, // 14
5, 10, 11, // 15
// bottom
0, 6, 8, // 16
8, 2, 0 // 17
]
const ibo = memcheck(gl.createBuffer())
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo)
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW)
const mvMatrix = <Float32Array> mat4.create()
const pMatrix = <Float32Array> mat4.create()
const uMVMatrix = denullify('uMVMatrix does not exist in program', gl.getUniformLocation(program, 'uMVMatrix'))
const uPMatrix = denullify('uPMatrix does not exist in program', gl.getUniformLocation(program, 'uPMatrix'))
let angle = 0
function animLoop() {
// Clear the viewport.
gl.clearColor(0.5, 0.5, 0.6, 1.0)
gl.enable(gl.DEPTH_TEST)
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
gl.viewport(0, 0, canvas.width, canvas.height)
mat4.perspective(pMatrix, 45, canvas.width / canvas.height, 0.1, 100.0)
mat4.identity(mvMatrix)
mat4.translate(mvMatrix, mvMatrix, [-1.0, -1.0, -7.0])
mat4.rotate(mvMatrix, mvMatrix, angle, [0.0, 1.0, 0.0])
const aVertexPosition = gl.getAttribLocation(program, 'aVertexPosition')
gl.enableVertexAttribArray(aVertexPosition)
gl.bindBuffer(gl.ARRAY_BUFFER, vbo)
gl.vertexAttribPointer(aVertexPosition, 3, gl.FLOAT, false, 0, 0)
const aVertexColor = gl.getAttribLocation(program, 'aVertexColor')
gl.enableVertexAttribArray(aVertexColor)
gl.bindBuffer(gl.ARRAY_BUFFER, cbo)
gl.vertexAttribPointer(aVertexColor, 3, gl.FLOAT, false, 0, 0)
gl.uniformMatrix4fv(uMVMatrix, false, mvMatrix)
gl.uniformMatrix4fv(uPMatrix, false, pMatrix)
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo)
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0)
angle += 0.01
requestAnimationFrame(animLoop)
}
animLoop()
}
varying highp vec4 vColor;
void main(void) {
gl_FragColor = vColor;
}
attribute vec3 aVertexPosition;
attribute vec3 aVertexColor;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
varying highp vec4 vColor;
void main(void) {
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
vColor = vec4(aVertexColor, 1.0);
gl_PointSize = 10.0;
}
body {
background-color: blue;
}
canvas {
background-color: black;
position: absolute;
left: 10px;
top: 10px;
}
{
"allowJs": false,
"declaration": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"jsx": "react",
"module": "system",
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"preserveConstEnums": true,
"removeComments": false,
"sourceMap": true,
"strictNullChecks": true,
"suppressImplicitAnyIndexErrors": true,
"target": "es5",
"traceResolution": true
}
{
"rules": {
"array-type": [
true,
"array"
],
"curly": false,
"comment-format": [
true,
"check-space"
],
"eofline": true,
"forin": true,
"jsdoc-format": true,
"no-conditional-assignment": false,
"no-consecutive-blank-lines": true,
"no-construct": true,
"no-for-in-array": true,
"no-magic-numbers": false,
"no-shadowed-variable": true,
"no-string-throw": true,
"no-trailing-whitespace": [
true,
"ignore-jsdoc"
],
"no-var-keyword": true,
"one-variable-per-declaration": [
true,
"ignore-for-loop"
],
"prefer-const": true,
"prefer-for-of": true,
"prefer-function-over-method": false,
"radix": true,
"semicolon": [
true,
"never"
],
"trailing-comma": [
true,
{
"multiline": "never",
"singleline": "never"
}
],
"triple-equals": true,
"use-isnan": true
}
}
@mathdoodle
Copy link
Author

mathdoodle commented May 22, 2016

hjvrsbwevhwabe

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment