WebGL Test

2011-12-25

WebGL Test 1

window.addEventListener('load', () => {
'use strict'

function main() {
const canvas = document.getElementById('world')
const gl = initGL(canvas)
const shaderProgram = initShader(gl)
const vertexBuffers = initBuffers(gl)

gl.clearColor(0, 0, 0, 1)
gl.enable(gl.DEPTH_TEST)
gl.enable(gl.CULL_FACE)
gl.cullFace(gl.BACK)

// Animation.
let rx = 0, ry = 0, rz = 0
const modelMatrix = mat4.create()
const tick = () => {
requestAnimationFrame(tick) // Request next frame.

rx += 0.02
ry += 0.03
rz += 0.05
mat4.identity(modelMatrix)
mat4.rotateX(modelMatrix, modelMatrix, rx)
mat4.rotateY(modelMatrix, modelMatrix, ry)
mat4.rotateZ(modelMatrix, modelMatrix, rz)

drawScene(gl, shaderProgram, vertexBuffers, modelMatrix)
}
requestAnimationFrame(tick) // Request next frame.
}

function drawScene(gl, shaderProgram, vertexBuffers, modelMatrix) {
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight)
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)

gl.useProgram(shaderProgram)

// Projection matrix.
const pMatrix = mat4.create()
mat4.perspective(pMatrix, 45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0)
gl.uniformMatrix4fv(shaderProgram.uPMatrix, false, pMatrix)

// Model view matrix.
const mvMatrix = mat4.create()
mat4.identity(mvMatrix)
mat4.translate(mvMatrix, mvMatrix, [0.0, 0.0, -5.0])

// Model matrix.
mat4.multiply(mvMatrix, mvMatrix, modelMatrix)
gl.uniformMatrix4fv(shaderProgram.uMVMatrix, false, mvMatrix)

gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffers.aVertexPosition)
gl.vertexAttribPointer(shaderProgram.aVertexPosition,
vertexBuffers.aVertexPosition.itemSize, gl.FLOAT, false, 0, 0)
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffers.aVertexColor)
gl.vertexAttribPointer(shaderProgram.aVertexColor,
vertexBuffers.aVertexColor.itemSize, gl.FLOAT, false, 0, 0)

gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vertexBuffers.indexBuffer)
gl.drawElements(gl.TRIANGLES, vertexBuffers.indexBuffer.numItems, gl.UNSIGNED_SHORT, 0)
}

function initShader(gl) {
const shader_vs_src = `
attribute vec3 aVertexPosition;
attribute vec4 aVertexColor;

uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;

varying vec4 vColor;

void main() {
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
vColor = aVertexColor;
}`
const shader_fs_src = `
precision mediump float;

varying vec4 vColor;

void main() {
gl_FragColor = vColor;
}`

const shaderProgram = createShaderProgram(
gl,
compileShader(gl, gl.VERTEX_SHADER, shader_vs_src),
compileShader(gl, gl.FRAGMENT_SHADER, shader_fs_src))
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert('Could not initialise shaders')
}

shaderProgram.aVertexPosition = gl.getAttribLocation(shaderProgram, 'aVertexPosition')
gl.enableVertexAttribArray(shaderProgram.aVertexPosition)

shaderProgram.aVertexColor = gl.getAttribLocation(shaderProgram, 'aVertexColor')
gl.enableVertexAttribArray(shaderProgram.aVertexColor)

shaderProgram.uPMatrix = gl.getUniformLocation(shaderProgram, 'uPMatrix')
shaderProgram.uMVMatrix = gl.getUniformLocation(shaderProgram, 'uMVMatrix')

return shaderProgram
}

function initBuffers(gl) {
const positionBuffer = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer)
const positions = [
// Front face
-1.0,-1.0, 1.0, 1.0,-1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0,
// Back face
-1.0,-1.0,-1.0, -1.0, 1.0,-1.0, 1.0, 1.0,-1.0, 1.0,-1.0,-1.0,
// Top face
-1.0, 1.0,-1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,-1.0,
// Bottom face
-1.0,-1.0,-1.0, 1.0,-1.0,-1.0, 1.0,-1.0, 1.0, -1.0,-1.0, 1.0,
// Right face
1.0,-1.0,-1.0, 1.0, 1.0,-1.0, 1.0, 1.0, 1.0, 1.0,-1.0, 1.0,
// Left face
-1.0,-1.0,-1.0, -1.0,-1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0,-1.0,
]
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW)
positionBuffer.itemSize = 3
positionBuffer.numItems = positions.length / positionBuffer.itemSize

const colorBuffer = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer)
const colors = [
1,0,0,1, 1,0,0,1, 1,0,0,1, 1,0,0,1,
0,1,0,1, 0,1,0,1, 0,1,0,1, 0,1,0,1,
0,0,1,1, 0,0,1,1, 0,0,1,1, 0,0,1,1,
1,1,0,1, 1,1,0,1, 1,1,0,1, 1,1,0,1,
0,1,1,1, 0,1,1,1, 0,1,1,1, 0,1,1,1,
1,0,1,1, 1,0,1,1, 1,0,1,1, 1,0,1,1,
]
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW)
colorBuffer.itemSize = 4
colorBuffer.numItems = colors.length / colorBuffer.itemSize

const indexBuffer = gl.createBuffer()
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer)
const indices = [
0, 1, 2, 0, 2, 3, // Front face
4, 5, 6, 4, 6, 7, // Back face
8, 9, 10, 8, 10, 11, // Top face
12, 13, 14, 12, 14, 15, // Bottom face
16, 17, 18, 16, 18, 19, // Right face
20, 21, 22, 20, 22, 23, // Left face
]
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW)
indexBuffer.itemSize = 1
indexBuffer.numItems = indices.length / indexBuffer.itemSize

return {
aVertexPosition: positionBuffer,
aVertexColor: colorBuffer,
indexBuffer: indexBuffer,
}
}

////////////////////////////////////////////////////////////////
// Matrix stack.
const mvMatrixStack = []

function pushMatrix(mtx) {
const copy = mat4.create()
mat4.set(mtx, copy)
mvMatrixStack.push(copy)
}

function popMatrix() {
if (mvMatrixStack.length == 0) {
throw "Invalid popMatrix!"
}
return mvMatrixStack.pop()
}

////////////////////////////////////////////////////////////////
function initGL(canvas) {
let gl
try {
gl = canvas.getContext('experimental-webgl')
gl.viewportWidth = canvas.width
gl.viewportHeight = canvas.height
} catch (e) {
}
if (!gl) {
alert('Could not initialise WebGL, sorry :-(')
}
return gl
}

function createShaderProgram(gl, vertexShader, fragmentShader) {
const shaderProgram = gl.createProgram()
gl.attachShader(shaderProgram, vertexShader)
gl.attachShader(shaderProgram, fragmentShader)
gl.linkProgram(shaderProgram)
return shaderProgram
}

// type: gl.VERTEX_SHADER or gl.FRAGMENT_SHADER
function compileShader(gl, type, src) {
const shader = gl.createShader(type)
gl.shaderSource(shader, src)
gl.compileShader(shader)
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert(gl.getShaderInfoLog(shader))
return null
}
return shader
}

// ========

main()
})