const canvas = document.getElementById("glCanvas");
const gl = canvas.getContext("webgl");
if (!gl) {
alert(
"Unable to initialize WebGL. Your browser or machine may not support it.");
}
const vsSource = `
attribute vec4 aVertexPosition;
attribute vec4 aVertexColor;
uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;
varying lowp vec4 vColor;
void main(void) {
gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
vColor = aVertexColor;
}
`;
const fsSource = `
varying lowp vec4 vColor;
void main(void) {
gl_FragColor = vColor;
}
`;
function loadShader(gl, type, source) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.error(
"An error occurred compiling the shaders: "
+ gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}
return shader;
}
const shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram,
loadShader(gl, gl.VERTEX_SHADER, vsSource));
gl.attachShader(
shaderProgram,
loadShader(gl, gl.FRAGMENT_SHADER, fsSource));
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram,
gl.LINK_STATUS)) {
console.error(
"Unable to initialize the shader program: "
+ gl.getProgramInfoLog(shaderProgram));
}
const programInfo = {
program: shaderProgram,
attribLocations: {
vertexPosition: gl.getAttribLocation(
shaderProgram, "aVertexPosition"),
vertexColor: gl.getAttribLocation(shaderProgram,
"aVertexColor"),
},
uniformLocations: {
projectionMatrix: gl.getUniformLocation(
shaderProgram, "uProjectionMatrix"),
modelViewMatrix: gl.getUniformLocation(
shaderProgram, "uModelViewMatrix"),
},
};
const buffers = initBuffers(gl);
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);
const faceColors = [
[1.0, 1.0, 1.0, 1.0], // Front face: white
[1.0, 0.0, 0.0, 1.0], // Back face: red
[0.0, 1.0, 0.0, 1.0], // Top face: green
[0.0, 0.0, 1.0, 1.0], // Bottom face: blue
[1.0, 1.0, 0.0, 1.0], // Right face: yellow
[1.0, 0.0, 1.0, 1.0], // Left face: purple
];
let colors = [];
for (let j = 0; j < faceColors.length; ++j) {
const c = faceColors[j];
colors = colors.concat(c, c, c, c);
}
const colorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors),
gl.STATIC_DRAW);
const indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
const indices = [
0, 1, 2, 0, 2,
3, // front
4, 5, 6, 4, 6,
7, // back
8, 9, 10, 8, 10,
11, // top
12, 13, 14, 12, 14,
15, // bottom
16, 17, 18, 16, 18,
19, // right
20, 21, 22, 20, 22,
23, // left
];
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,
new Uint16Array(indices), gl.STATIC_DRAW);
return {
position: positionBuffer,
color: colorBuffer,
indices: indexBuffer,
};
}
function drawScene(gl, programInfo, buffers, deltaTime) {
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clearDepth(1.0);
gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LEQUAL);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
const fieldOfView = (45 * Math.PI) / 180;
const aspect
= gl.canvas.clientWidth / gl.canvas.clientHeight;
const zNear = 0.1;
const zFar = 100.0;
const projectionMatrix = mat4.create();
mat4.perspective(projectionMatrix, fieldOfView, aspect,
zNear, zFar);
const modelViewMatrix = mat4.create();
mat4.translate(modelViewMatrix, modelViewMatrix,
[-0.0, 0.0, -6.0]);
mat4.rotate(modelViewMatrix, modelViewMatrix,
cubeRotation, [0, 0, 1]);
mat4.rotate(modelViewMatrix, modelViewMatrix,
cubeRotation * 0.7, [0, 1, 0]);
{
const numComponents = 3;
const type = gl.FLOAT;
const normalize = false;
const stride = 0;
const offset = 0;
gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
gl.vertexAttribPointer(
programInfo.attribLocations.vertexPosition,
numComponents, type, normalize, stride, offset);
gl.enableVertexAttribArray(
programInfo.attribLocations.vertexPosition);
}
{
const numComponents = 4;
const type = gl.FLOAT;
const normalize = false;
const stride = 0;
const offset = 0;
gl.bindBuffer(gl.ARRAY_BUFFER, buffers.color);
gl.vertexAttribPointer(
programInfo.attribLocations.vertexColor,
numComponents, type, normalize, stride, offset);
gl.enableVertexAttribArray(
programInfo.attribLocations.vertexColor);
}
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffers.indices);
gl.useProgram(programInfo.program);
gl.uniformMatrix4fv(
programInfo.uniformLocations.projectionMatrix,
false, projectionMatrix);
gl.uniformMatrix4fv(
programInfo.uniformLocations.modelViewMatrix, false,
modelViewMatrix);
{
const vertexCount = 36;
const type = gl.UNSIGNED_SHORT;
const offset = 0;
gl.drawElements(gl.TRIANGLES, vertexCount, type,
offset);
}
}
let cubeRotation = 0.0;
let then = 0;
function render(now) {
now *= 0.001;
const deltaTime = now - then;
then = now;
cubeRotation += deltaTime;
drawScene(gl, programInfo, buffers, deltaTime);
requestAnimationFrame(render);
}
requestAnimationFrame(render);