Drawing a cube in WebGL

Above you see a spinning cube, with faces of different colors. This is drawn with WebGL. The vertex shader accepts one uniform parameter, a transformation matrix:

uniform mat4 transformation;
attribute vec4 coord;
void main(void) {
  gl_Position = transformation * coord;
}

To draw the six faces of the cube, I only define the vertices for the “front” face:

const vertBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
 -0.5, -0.5, 0.5, 1,
  0.5, -0.5, 0.5, 1,
  0.5,  0.5, 0.5, 1,
 -0.5,  0.5, 0.5, 1,
]), gl.STATIC_DRAW);

const indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array([0,1,2,3]), gl.STATIC_DRAW);

To draw the other five faces of the cube, I rotate the “front” face into the desired position. I do this in JavaScript using a library called glMatrix, which provides functions mat4.rotateX(out, in, angle).

function rotateX(ang) { const mat = mat4.create(); return mat4.rotateX(mat, mat, ang); }
function rotateY(ang) { const mat = mat4.create(); return mat4.rotateY(mat, mat, ang); }
const faces = [
  { color: new Float32Array([0,0,0,1]), transformation: mat4.create() },
  { color: new Float32Array([0,0,1,1]), transformation: rotateX(Math.PI * 1/2) },
  { color: new Float32Array([0,1,0,1]), transformation: rotateX(Math.PI) },
  { color: new Float32Array([0,1,1,1]), transformation: rotateX(Math.PI * 3/2) },
  { color: new Float32Array([1,0,0,1]), transformation: rotateY(Math.PI * 1/2) },
  { color: new Float32Array([1,0,1,1]), transformation: rotateY(Math.PI * 3/2) },
];

const startTime = new Date().getTime();
function redraw() {
  const t = (new Date().getTime() - startTime) / 1000;
  const timeTrans = mat4.create();
  mat4.rotateX(timeTrans, timeTrans, t);
  mat4.rotateY(timeTrans, timeTrans, t/2);
  mat4.rotateZ(timeTrans, timeTrans, t*2);
  gl.clear(gl.COLOR_BUFFER_BIT);
  for (let face of faces) {
    const trans = mat4.create();
    mat4.multiply(trans, timeTrans, face.transformation);
    gl.uniformMatrix4fv(transformationLoc, false, trans);
    gl.uniform4fv(faceColorLoc, face.color);
    gl.drawElements(gl.TRIANGLE_FAN, 4, gl.UNSIGNED_BYTE, 0);
  }
  window.requestAnimationFrame(redraw);
}
👋 I'm Jim, a full-stack product engineer. Want to build an amazing product and a profitable business? Read more about me or Get in touch!

More by Jim

Tagged #programming, #graphics, #webgl. All content copyright James Fisher 2017. This post is not associated with my employer. Found an error? Edit this page.