287 lines
6.9 KiB
JavaScript
287 lines
6.9 KiB
JavaScript
"use strict";
|
|
|
|
let cv, gl;
|
|
|
|
let program;
|
|
|
|
let cubeVertices;
|
|
let cubeVertexBuffer;
|
|
|
|
let lineCubeVertices;
|
|
let lineCubeVertexBuffer;
|
|
|
|
let originVertices;
|
|
let originVertexBuffer;
|
|
|
|
let floorVertices;
|
|
let floorVertexBuffer;
|
|
|
|
let lastFrame = Date.now();
|
|
|
|
async function init() {
|
|
cv = document.getElementById("cv");
|
|
gl = cv.getContext("webgl");
|
|
|
|
if (!gl) {
|
|
window.alert("WebGL not supported");
|
|
}
|
|
|
|
console.log("compiling shaders...");
|
|
program = await buildShaderProgram(gl, "shaders/vertex.glsl", "shaders/fragment.glsl");
|
|
|
|
console.log("creating vertex buffer");
|
|
|
|
cubeVertices = [
|
|
// Back face (red)
|
|
-1, -1, -1, 1, 0.5, 0.5,
|
|
-1, 1, -1, 1, 0.5, 0.5,
|
|
1, 1, -1, 1, 0.5, 0.5,
|
|
-1, -1, -1, 1, 0.5, 0.5,
|
|
1, 1, -1, 1, 0.5, 0.5,
|
|
1, -1, -1, 1, 0.5, 0.5,
|
|
|
|
// Front face (green)
|
|
-1, -1, 1, 0.5, 1, 0.5,
|
|
1, -1, 1, 0.5, 1, 0.5,
|
|
1, 1, 1, 0.5, 1, 0.5,
|
|
-1, -1, 1, 0.5, 1, 0.5,
|
|
1, 1, 1, 0.5, 1, 0.5,
|
|
-1, 1, 1, 0.5, 1, 0.5,
|
|
|
|
// Left face (blue)
|
|
-1, 1, -1, 0.5, 0.5, 1,
|
|
-1, -1, -1, 0.5, 0.5, 1,
|
|
-1, 1, 1, 0.5, 0.5, 1,
|
|
-1, 1, 1, 0.5, 0.5, 1,
|
|
-1, -1, -1, 0.5, 0.5, 1,
|
|
-1, -1, 1, 0.5, 0.5, 1,
|
|
|
|
// Right face (yellow)
|
|
1, -1, -1, 1, 1, 0.5,
|
|
1, 1, -1, 1, 1, 0.5,
|
|
1, 1, 1, 1, 1, 0.5,
|
|
1, -1, -1, 1, 1, 0.5,
|
|
1, 1, 1, 1, 1, 0.5,
|
|
1, -1, 1, 1, 1, 0.5,
|
|
|
|
// Top face (magenta)
|
|
-1, 1, -1, 1, 0.5, 1,
|
|
-1, 1, 1, 1, 0.5, 1,
|
|
1, 1, 1, 1, 0.5, 1,
|
|
-1, 1, -1, 1, 0.5, 1,
|
|
1, 1, 1, 1, 0.5, 1,
|
|
1, 1, -1, 1, 0.5, 1,
|
|
|
|
// Bottom face (cyan)
|
|
-1, -1, 1, 0.5, 1, 1,
|
|
-1, -1, -1, 0.5, 1, 1,
|
|
1, -1, 1, 0.5, 1, 1,
|
|
1, -1, 1, 0.5, 1, 1,
|
|
-1, -1, -1, 0.5, 1, 1,
|
|
1, -1, -1, 0.5, 1, 1
|
|
];
|
|
|
|
lineCubeVertices = [
|
|
1, 1, 1, 1, 0, 0,
|
|
1, 1, -1, 1, 0, 0,
|
|
1, 1, 1, 1, 0, 0,
|
|
1, -1, 1, 1, 0, 0,
|
|
1, 1, 1, 1, 0, 0,
|
|
-1, 1, 1, 1, 0, 0,
|
|
1, 1, -1, 1, 0, 0,
|
|
1, -1, -1, 1, 0, 0,
|
|
1, 1, -1, 1, 0, 0,
|
|
-1, 1, -1, 1, 0, 0,
|
|
1, -1, 1, 1, 0, 0,
|
|
1, -1, -1, 1, 0, 0,
|
|
1, -1, 1, 1, 0, 0,
|
|
-1, -1, 1, 1, 0, 0,
|
|
-1, 1, 1, 1, 0, 0,
|
|
-1, 1, -1, 1, 0, 0,
|
|
-1, 1, 1, 1, 0, 0,
|
|
-1, -1, 1, 1, 0, 0,
|
|
1, -1, -1, 1, 0, 0,
|
|
-1, -1, -1, 1, 0, 0,
|
|
-1, -1, 1, 1, 0, 0,
|
|
-1, -1, -1, 1, 0, 0,
|
|
-1, 1, -1, 1, 0, 0,
|
|
-1, -1, -1, 1, 0, 0,
|
|
];
|
|
|
|
originVertices = [
|
|
0, 0, 0, 1, 0, 0,
|
|
1, 0, 0, 1, 0, 0,
|
|
0, 0, 0, 0, 1, 0,
|
|
0, 1, 0, 0, 1, 0,
|
|
0, 0, 0, 0, 0, 1,
|
|
0, 0, 1, 0, 0, 1,
|
|
];
|
|
|
|
floorVertices = [
|
|
1, 0, 1, 0, 0, 0,
|
|
-1, 0, -1, 0, 0, 0,
|
|
-1, 0, 1, 0, 0, 0,
|
|
-1, 0, -1, 0, 0, 0,
|
|
1, 0, 1, 0, 0, 0,
|
|
1, 0, -1, 0, 0, 0,
|
|
];
|
|
|
|
cubeVertexBuffer = gl.createBuffer();
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexBuffer);
|
|
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(cubeVertices), gl.STATIC_DRAW);
|
|
|
|
lineCubeVertexBuffer = gl.createBuffer();
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, lineCubeVertexBuffer);
|
|
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(lineCubeVertices), gl.STATIC_DRAW);
|
|
|
|
originVertexBuffer = gl.createBuffer();
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, originVertexBuffer);
|
|
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(originVertices), gl.STATIC_DRAW);
|
|
|
|
floorVertexBuffer = gl.createBuffer();
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, floorVertexBuffer);
|
|
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(floorVertices), gl.STATIC_DRAW);
|
|
|
|
// unbind buffer
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
|
|
|
// set clear colour
|
|
gl.clearColor(...hexToRgb("181825"), 1.0);
|
|
|
|
gl.enable(gl.CULL_FACE);
|
|
|
|
// start drawing
|
|
requestAnimationFrame(draw);
|
|
}
|
|
|
|
function setAttribPointers() {
|
|
let positionAttribLocation = gl.getAttribLocation(program, "vertPosition");
|
|
let colorAttribLocation = gl.getAttribLocation(program, "vertColor");
|
|
|
|
gl.vertexAttribPointer(positionAttribLocation, 3, gl.FLOAT, gl.FALSE, 6 * Float32Array.BYTES_PER_ELEMENT, 0);
|
|
gl.vertexAttribPointer(colorAttribLocation, 3, gl.FLOAT, gl.FALSE, 6 * Float32Array.BYTES_PER_ELEMENT, 3 * Float32Array.BYTES_PER_ELEMENT);
|
|
|
|
gl.enableVertexAttribArray(positionAttribLocation);
|
|
gl.enableVertexAttribArray(colorAttribLocation);
|
|
}
|
|
|
|
let frameCount = 0;
|
|
let lastStatUpdate = Date.now();
|
|
|
|
function updateStats(deltaTime) {
|
|
frameCount++;
|
|
|
|
let now = Date.now();
|
|
let timeSinceLastUpdate = (now - lastStatUpdate) / 1000;
|
|
|
|
if (timeSinceLastUpdate < 0.5) return;
|
|
|
|
lastStatUpdate = now;
|
|
|
|
let fpsDisplay = document.getElementById("fps");
|
|
fpsDisplay.innerText = Math.round(frameCount / timeSinceLastUpdate)
|
|
|
|
let msDisplay = document.getElementById("ms");
|
|
msDisplay.innerText = deltaTime * 1000 + "ms";
|
|
|
|
frameCount = 0;
|
|
}
|
|
|
|
let hue = 0;
|
|
|
|
async function draw() {
|
|
let now = Date.now();
|
|
let deltaTime = (now - lastFrame) / 1000;
|
|
|
|
hue += deltaTime / 5;
|
|
if (hue > 1) hue = 0;
|
|
|
|
updateStats(deltaTime);
|
|
|
|
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
|
|
gl.useProgram(program);
|
|
|
|
let modelViewLocation = gl.getUniformLocation(program, "modelViewMatrix");
|
|
let projectionLocation = gl.getUniformLocation(program, "projectionMatrix");
|
|
|
|
|
|
let projectionMatrix = [];
|
|
mat4BuildPerspective(projectionMatrix, 90.0 / 180.0 * Math.PI, cv.width / cv.height, 0.1, 20);
|
|
gl.uniformMatrix4fv(projectionLocation, gl.FALSE, new Float32Array(projectionMatrix));
|
|
|
|
|
|
let viewMatrix = [];
|
|
let cameraPosition = [2, 2, 2];
|
|
let cameraLookAt = [0, 0, -1];
|
|
let cameraUp = [0, 1, 0];
|
|
mat4BuildLookAt(viewMatrix, cameraPosition, cameraLookAt, cameraUp);
|
|
|
|
|
|
let modelMatrix = [];
|
|
mat4Identity(modelMatrix);
|
|
|
|
mat4RotateX(modelMatrix, modelMatrix, hue * 2 * Math.PI);
|
|
mat4RotateY(modelMatrix, modelMatrix, hue * 2 * Math.PI);
|
|
|
|
|
|
let modelViewMatrix = [];
|
|
mat4Multiply(modelViewMatrix, viewMatrix, modelMatrix);
|
|
|
|
gl.uniformMatrix4fv(modelViewLocation, gl.FALSE, new Float32Array(modelViewMatrix));
|
|
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexBuffer);
|
|
setAttribPointers();
|
|
gl.drawArrays(gl.TRIANGLES, 0, cubeVertices.length / 6);
|
|
|
|
gl.lineWidth(3);
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, lineCubeVertexBuffer);
|
|
setAttribPointers();
|
|
gl.drawArrays(gl.LINES, 0, lineCubeVertices.length / 6);
|
|
|
|
|
|
gl.uniformMatrix4fv(modelViewLocation, gl.FALSE, new Float32Array(viewMatrix));
|
|
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, originVertexBuffer);
|
|
setAttribPointers();
|
|
gl.drawArrays(gl.LINES, 0, originVertices.length / 6);
|
|
|
|
lastFrame = now;
|
|
requestAnimationFrame(draw);
|
|
}
|
|
|
|
function hexToRgb(hex) {
|
|
let r = parseInt(hex.substring(0, 2), 16) / 255;
|
|
let g = parseInt(hex.substring(2, 4), 16) / 255;
|
|
let b = parseInt(hex.substring(4, 6), 16) / 255;
|
|
|
|
return [r, g, b];
|
|
}
|
|
|
|
function hslToRgb(h, s, l) {
|
|
let r, g, b;
|
|
|
|
if (s == 0) {
|
|
r = g = b = l;
|
|
} else {
|
|
let hue2rgb = function hue2rgb(p, q, t) {
|
|
if (t < 0) t += 1;
|
|
if (t > 1) t -= 1;
|
|
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
|
if (t < 1 / 2) return q;
|
|
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
|
return p;
|
|
}
|
|
|
|
let q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
let p = 2 * l - q;
|
|
|
|
r = hue2rgb(p, q, h + 1 / 3);
|
|
g = hue2rgb(p, q, h);
|
|
b = hue2rgb(p, q, h - 1 / 3);
|
|
}
|
|
|
|
return [r, g, b];
|
|
}
|
|
|
|
window.addEventListener("DOMContentLoaded", init); |