cg1-visualisations/public/script.js

709 lines
22 KiB
JavaScript

"use strict";
class Animation {
constructor() {
this.time = 0.0;
}
interpolation(i) {
if (i > this.time) {
return 0.0;
}
if (i+1 > this.time) {
return this.time - Math.floor(this.time);
}
return 1.0;
}
isZAxisInverted() {
return (this.time <= 5.0);
}
isCameraDrawn() {
return (this.time <= 2.0);
}
isOriginCubeDrawn() {
return (this.time != 0.0 && this.time < 5.0);
}
}
let cv, gl;
let program;
let floorProgram;
let hVertices;
let hVertexBuffer;
let cubeVertices;
let cubeVertexBuffer;
let lineCubeVertices;
let lineCubeVertexBuffer;
let originVertices;
let originVertexBuffer;
let floorVertices;
let floorVertexBuffer;
let cameraVertices;
let cameraVertexBuffer;
let lastFrame = Date.now();
let animation = new Animation();
let displayMatricesVirtually = true;
let virtualRealInterpolation = 1;
let cameraPitch = 0.565;
let cameraYaw = 0.375;
let cameraDistance = 4;
let smoothCameraDistance = 4;
let mouseDragging = false;
let frameTimes = [];
function resizeCanvas() {
const dpr = window.devicePixelRatio;
cv.width = cv.parentElement.clientWidth * dpr;
cv.height = cv.parentElement.clientHeight * dpr;
gl.viewport(0, 0, cv.width, cv.height);
}
async function init() {
cv = document.getElementById("cv");
gl = cv.getContext("webgl");
if (!gl) {
window.alert("WebGL not supported");
}
const resizeObserver = new ResizeObserver(resizeCanvas);
resizeObserver.observe(cv.parentElement);
resizeCanvas();
// input handling
document.getElementById("interpolate").addEventListener("input", (e) => {
animation.time = 6.0 - e.target.value;
for (let i = 0; i < 6; ++i) {
document.getElementById("matrices").children[5-i].style.setProperty("--fill-percentage", (animation.interpolation(i) * 100) + "%");
}
});
document.getElementById("displayMatricesVirtually").addEventListener("input", (e) => {
displayMatricesVirtually = e.target.checked;
});
document.getElementById("backfaceCulling").addEventListener("input", (e) => {
if (e.target.checked) {
gl.enable(gl.CULL_FACE);
} else {
gl.disable(gl.CULL_FACE);
}
});
cv.addEventListener("mousedown", (e) => {
if (e.button == 0) {
mouseDragging = true;
}
});
document.addEventListener("mouseup", (e) => {
if (e.button == 0) {
mouseDragging = false;
}
});
document.addEventListener("mouseleave", (e) => {
mouseDragging = false;
});
document.addEventListener("mousemove", (e) => {
if (mouseDragging && displayMatricesVirtually) {
cameraYaw += e.movementX / 100;
cameraPitch += e.movementY / 100;
if (cameraPitch < -Math.PI / 2) cameraPitch = -Math.PI / 2;
if (cameraPitch > Math.PI / 2) cameraPitch = Math.PI / 2;
}
});
cv.addEventListener("wheel", (e) => {
cameraDistance += e.deltaY / 100;
if (cameraDistance < 1) cameraDistance = 1;
if (cameraDistance > 15) cameraDistance = 15;
e.preventDefault();
});
// end input handling
console.log("compiling shaders...");
program = await buildShaderProgram(gl, "shaders/vertex.glsl", "shaders/fragment.glsl");
floorProgram = await buildShaderProgram(gl, "shaders/floor-vertex.glsl", "shaders/floor-fragment.glsl");
console.log("creating vertex buffer");
hVertices = [
// X // Y
// left vertical bar
-0.35, 0.6, 0.0, 1.0, 0.3, 0.3,
-0.35, -0.6, 0.0, 1.0, 0.3, 0.3,
-0.2, 0.6, 0.0, 1.0, 0.3, 0.3,
-0.2, 0.6, 0.0, 1.0, 0.3, 0.3,
-0.35, -0.6, 0.0, 1.0, 0.3, 0.3,
-0.2, -0.6, 0.0, 1.0, 0.3, 0.3,
// right vertical bar
0.35, -0.6, 0.0, 1.0, 0.3, 0.3,
0.35, 0.6, 0.0, 1.0, 0.3, 0.3,
0.2, 0.6, 0.0, 1.0, 0.3, 0.3,
0.35, -0.6, 0.0, 1.0, 0.3, 0.3,
0.2, 0.6, 0.0, 1.0, 0.3, 0.3,
0.2, -0.6, 0.0, 1.0, 0.3, 0.3,
// middle bar
-0.2, 0.1, 0.0, 1.0, 0.3, 0.3,
-0.2, -0.1, 0.0, 1.0, 0.3, 0.3,
0.2, 0.1, 0.0, 1.0, 0.3, 0.3,
0.2, 0.1, 0.0, 1.0, 0.3, 0.3,
-0.2, -0.1, 0.0, 1.0, 0.3, 0.3,
0.2, -0.1, 0.0, 1.0, 0.3, 0.3,
// bottom bar
-0.35, -0.7, 0.0, 1.0, 0.3, 0.3,
-0.35, -0.9, 0.0, 1.0, 0.3, 0.3,
0.35, -0.9, 0.0, 1.0, 0.3, 0.3,
-0.35, -0.7, 0.0, 1.0, 0.3, 0.3,
0.35, -0.9, 0.0, 1.0, 0.3, 0.3,
0.35, -0.7, 0.0, 1.0, 0.3, 0.3,
];
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,
];
cameraVertices = [
// Cube Body (dark gray)
// Front face
-1, -1, 1, 0.196, 0.196, 0.196,
1, -1, 1, 0.196, 0.196, 0.196,
1, 1, 1, 0.196, 0.196, 0.196,
-1, -1, 1, 0.196, 0.196, 0.196,
1, 1, 1, 0.196, 0.196, 0.196,
-1, 1, 1, 0.196, 0.196, 0.196,
// Back face
-1, -1, -1, 0.196, 0.196, 0.196,
1, 1, -1, 0.196, 0.196, 0.196,
1, -1, -1, 0.196, 0.196, 0.196,
-1, -1, -1, 0.196, 0.196, 0.196,
-1, 1, -1, 0.196, 0.196, 0.196,
1, 1, -1, 0.196, 0.196, 0.196,
// Left face
-1, -1, -1, 0.196, 0.196, 0.196,
-1, -1, 1, 0.196, 0.196, 0.196,
-1, 1, 1, 0.196, 0.196, 0.196,
-1, -1, -1, 0.196, 0.196, 0.196,
-1, 1, 1, 0.196, 0.196, 0.196,
-1, 1, -1, 0.196, 0.196, 0.196,
// Right face
1, -1, -1, 0.196, 0.196, 0.196,
1, 1, 1, 0.196, 0.196, 0.196,
1, -1, 1, 0.196, 0.196, 0.196,
1, -1, -1, 0.196, 0.196, 0.196,
1, 1, -1, 0.196, 0.196, 0.196,
1, 1, 1, 0.196, 0.196, 0.196,
// Top face
-1, 1, -1, 0.196, 0.196, 0.196,
-1, 1, 1, 0.196, 0.196, 0.196,
1, 1, 1, 0.196, 0.196, 0.196,
-1, 1, -1, 0.196, 0.196, 0.196,
1, 1, 1, 0.196, 0.196, 0.196,
1, 1, -1, 0.196, 0.196, 0.196,
// Bottom face
-1, -1, -1, 0.196, 0.196, 0.196,
1, -1, 1, 0.196, 0.196, 0.196,
-1, -1, 1, 0.196, 0.196, 0.196,
-1, -1, -1, 0.196, 0.196, 0.196,
1, -1, -1, 0.196, 0.196, 0.196,
1, -1, 1, 0.196, 0.196, 0.196,
// Lens (light gray)
// Front face
-0.5, -0.5, -1.6, 0.706, 0.706, 0.706,
0.5, 0.5, -1.6, 0.706, 0.706, 0.706,
0.5, -0.5, -1.6, 0.706, 0.706, 0.706,
-0.5, -0.5, -1.6, 0.706, 0.706, 0.706,
-0.5, 0.5, -1.6, 0.706, 0.706, 0.706,
0.5, 0.5, -1.6, 0.706, 0.706, 0.706,
// Back face
-0.5, -0.5, -1.0, 0.706, 0.706, 0.706,
0.5, -0.5, -1.0, 0.706, 0.706, 0.706,
0.5, 0.5, -1.0, 0.706, 0.706, 0.706,
-0.5, -0.5, -1.0, 0.706, 0.706, 0.706,
0.5, 0.5, -1.0, 0.706, 0.706, 0.706,
-0.5, 0.5, -1.0, 0.706, 0.706, 0.706,
// Left face
-0.5, 0.5, -1.6, 0.706, 0.706, 0.706,
-0.5, -0.5, -1.0, 0.706, 0.706, 0.706,
-0.5, 0.5, -1.0, 0.706, 0.706, 0.706,
-0.5, -0.5, -1.6, 0.706, 0.706, 0.706,
-0.5, -0.5, -1.0, 0.706, 0.706, 0.706,
-0.5, 0.5, -1.6, 0.706, 0.706, 0.706,
// Right face
0.5, 0.5, -1.0, 0.706, 0.706, 0.706,
0.5, -0.5, -1.0, 0.706, 0.706, 0.706,
0.5, 0.5, -1.6, 0.706, 0.706, 0.706,
0.5, 0.5, -1.6, 0.706, 0.706, 0.706,
0.5, -0.5, -1.0, 0.706, 0.706, 0.706,
0.5, -0.5, -1.6, 0.706, 0.706, 0.706,
// Top face
0.5, 0.5, -1.6, 0.706, 0.706, 0.706,
-0.5, 0.5, -1.0, 0.706, 0.706, 0.706,
0.5, 0.5, -1.0, 0.706, 0.706, 0.706,
-0.5, 0.5, -1.6, 0.706, 0.706, 0.706,
-0.5, 0.5, -1.0, 0.706, 0.706, 0.706,
0.5, 0.5, -1.6, 0.706, 0.706, 0.706,
// Bottom face
-0.5, -0.5, -1.0, 0.706, 0.706, 0.706,
0.5, -0.5, -1.0, 0.706, 0.706, 0.706,
0.5, -0.5, -1.6, 0.706, 0.706, 0.706,
-0.5, -0.5, -1.0, 0.706, 0.706, 0.706,
0.5, -0.5, -1.6, 0.706, 0.706, 0.706,
-0.5, -0.5, -1.6, 0.706, 0.706, 0.706
];
hVertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, hVertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(hVertices), gl.STATIC_DRAW);
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);
cameraVertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, cameraVertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(cameraVertices), gl.STATIC_DRAW);
// unbind buffer
gl.bindBuffer(gl.ARRAY_BUFFER, null);
// set clear colour
gl.clearColor(...hexToRgb("181825"), 1.0);
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
gl.enable( gl.LINE_SMOOTH );
gl.enable( gl.POLYGON_SMOOTH );
gl.hint( gl.LINE_SMOOTH_HINT, gl.NICEST );
gl.hint( gl.POLYGON_SMOOTH_HINT, gl.NICEST )
gl.lineWidth(3.0);
// 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");
if (frameTimes.length > 0) {
msDisplay.innerText = (Math.round(frameTimes.reduce((prev, curr) => prev + curr) / frameTimes.length * 100) / 100) + "ms";
}
frameTimes = [];
frameCount = 0;
}
async function draw() {
let now = Date.now();
let deltaTime = (now - lastFrame) / 1000;
let frameStart = performance.now();
if (displayMatricesVirtually) {
virtualRealInterpolation = Math.min(virtualRealInterpolation + deltaTime * 2, 1);
} else {
virtualRealInterpolation = Math.max(virtualRealInterpolation - deltaTime * 2, 0);
}
smoothCameraDistance += (cameraDistance - smoothCameraDistance) / 8;
updateStats(deltaTime);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
let identity = [];
mat4Identity(identity);
// Real Matrices
let realProjectionMatrix = [];
mat4BuildPerspective(realProjectionMatrix, 60.0 / 180.0 * Math.PI, cv.width / cv.height, 0.1, 30);
let realViewMatrix = [];
let realCameraPosition = [Math.cos(cameraYaw) * smoothCameraDistance * Math.cos(cameraPitch), Math.sin(cameraPitch) * smoothCameraDistance, Math.sin(cameraYaw) * smoothCameraDistance * Math.cos(cameraPitch)];
let realCameraLookAt = [0, 0, 0];
let realCameraUp = [0, 1, 0];
mat4BuildLookAt(realViewMatrix, realCameraPosition, realCameraLookAt, realCameraUp);
mat4Interpolate(realProjectionMatrix, identity, realProjectionMatrix, virtualRealInterpolation * virtualRealInterpolation);
mat4Interpolate(realViewMatrix, identity, realViewMatrix, virtualRealInterpolation);
gl.useProgram(program);
gl.uniformMatrix4fv(gl.getUniformLocation(program, "realProjectionMatrix"), gl.FALSE, new Float32Array(realProjectionMatrix));
gl.uniformMatrix4fv(gl.getUniformLocation(program, "realViewMatrix"), gl.FALSE, new Float32Array(realViewMatrix));
gl.useProgram(floorProgram);
gl.uniformMatrix4fv(gl.getUniformLocation(floorProgram, "realProjectionMatrix"), gl.FALSE, new Float32Array(realProjectionMatrix));
// Virtual Matrices
gl.useProgram(program);
let virtualModelViewLocation = gl.getUniformLocation(program, "virtualModelViewMatrix");
let virtualProjectionLocation = gl.getUniformLocation(program, "virtualProjectionMatrix");
let colorOverrideLocation = gl.getUniformLocation(program, "colorOverride");
let virtualProjectionMatrix = [];
mat4BuildPerspective(virtualProjectionMatrix, 60.0 / 180.0 * Math.PI, cv.width / cv.height, 0.9, 5);
if (animation.isZAxisInverted()) {
let zAxisFlipMatrix = [];
mat4Identity(zAxisFlipMatrix);
zAxisFlipMatrix[10] = -1;
mat4Interpolate(zAxisFlipMatrix, identity, zAxisFlipMatrix, virtualRealInterpolation);
mat4Multiply(virtualProjectionMatrix, zAxisFlipMatrix, virtualProjectionMatrix);
}
let inverseVirtualProjectionMatrix = [];
mat4Inverse(inverseVirtualProjectionMatrix, virtualProjectionMatrix);
let virtualViewMatrix = [];
let virtualCameraPosition = [1.2, 1.2, 2];
let virtualCameraLookAt = [0, 0, -1];
let virtualCameraUp = [0, 1, 0];
mat4BuildLookAt(virtualViewMatrix, virtualCameraPosition, virtualCameraLookAt, virtualCameraUp);
let inverseVirtualViewMatrix = [];
mat4Inverse(inverseVirtualViewMatrix, virtualViewMatrix);
// interpolated view matrix
let virtualViewMatrix1 = [];
mat4BuildLookAt1(virtualViewMatrix1, virtualCameraPosition, virtualCameraLookAt, virtualCameraUp);
mat4Interpolate(virtualViewMatrix1, identity, virtualViewMatrix1, animation.interpolation(0));
let virtualViewMatrix2 = [];
mat4BuildLookAt2(virtualViewMatrix2, virtualCameraPosition, virtualCameraLookAt, virtualCameraUp);
mat4Interpolate(virtualViewMatrix2, identity, virtualViewMatrix2, animation.interpolation(1));
mat4Multiply(virtualViewMatrix, virtualViewMatrix2, virtualViewMatrix1);
// interpolated projection matrix
mat4Identity(virtualProjectionMatrix);
let virtualProjectionMatrix1 = [];
mat4BuildPerspective1(virtualProjectionMatrix1, 60.0 / 180.0 * Math.PI, cv.width / cv.height, 0.9, 5);
mat4Interpolate(virtualProjectionMatrix1, identity, virtualProjectionMatrix1, animation.interpolation(2));
mat4Multiply(virtualProjectionMatrix, virtualProjectionMatrix1, virtualProjectionMatrix);
let virtualProjectionMatrix2 = [];
mat4BuildPerspective2(virtualProjectionMatrix2, 60.0 / 180.0 * Math.PI, cv.width / cv.height, 0.9, 5);
mat4Interpolate(virtualProjectionMatrix2, identity, virtualProjectionMatrix2, animation.interpolation(3));
mat4Multiply(virtualProjectionMatrix, virtualProjectionMatrix2, virtualProjectionMatrix);
let virtualProjectionMatrix3 = [];
mat4BuildPerspective3(virtualProjectionMatrix3, 60.0 / 180.0 * Math.PI, cv.width / cv.height, 0.9, 5);
mat4Interpolate(virtualProjectionMatrix3, identity, virtualProjectionMatrix3, animation.interpolation(4));
mat4Multiply(virtualProjectionMatrix, virtualProjectionMatrix3, virtualProjectionMatrix);
if (!displayMatricesVirtually) {
let virtualProjectionMatrix4 = [];
mat4BuildPerspective4(virtualProjectionMatrix4, 60.0 / 180.0 * Math.PI, cv.width / cv.height, 0.9, 5);
mat4Interpolate(virtualProjectionMatrix4, identity, virtualProjectionMatrix4, animation.interpolation(5));
mat4Multiply(virtualProjectionMatrix, virtualProjectionMatrix4, virtualProjectionMatrix);
}
gl.uniformMatrix4fv(virtualProjectionLocation, gl.FALSE, new Float32Array(virtualProjectionMatrix));
let modelMatrix = [];
mat4Identity(modelMatrix);
let modelViewMatrix = [];
mat4Multiply(modelViewMatrix, virtualViewMatrix, modelMatrix);
gl.uniformMatrix4fv(virtualModelViewLocation, gl.FALSE, new Float32Array(modelViewMatrix));
// draw scene
// draw H
gl.useProgram(program);
gl.bindBuffer(gl.ARRAY_BUFFER, hVertexBuffer);
setAttribPointers();
gl.drawArrays(gl.TRIANGLES, 0, hVertices.length / 6);
// draw line cube
gl.bindBuffer(gl.ARRAY_BUFFER, lineCubeVertexBuffer);
setAttribPointers();
gl.uniform3fv(colorOverrideLocation, [1, 1, 0.5]);
gl.drawArrays(gl.LINES, 0, lineCubeVertices.length / 6);
gl.uniform3fv(colorOverrideLocation, [0, 0, 0]);
// draw solid cube 1
let cube1ModelView = [];
mat4Identity(cube1ModelView);
mat4Scale(cube1ModelView, cube1ModelView, [0.3, 0.3, 0.3]);
mat4RotateY(cube1ModelView, cube1ModelView, 0.3);
mat4Translate(cube1ModelView, cube1ModelView, [-0.5, 0.3, -0.7]);
mat4Multiply(cube1ModelView, virtualViewMatrix, cube1ModelView);
gl.uniformMatrix4fv(virtualModelViewLocation, gl.FALSE, new Float32Array(cube1ModelView));
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexBuffer);
setAttribPointers();
gl.drawArrays(gl.TRIANGLES, 0, cubeVertices.length / 6);
// draw solid cube 2
let cube2ModelView = [];
mat4Identity(cube2ModelView);
mat4Scale(cube2ModelView, cube2ModelView, [0.4, 0.4, 0.4]);
mat4RotateY(cube2ModelView, cube2ModelView, 2.6);
mat4Translate(cube2ModelView, cube2ModelView, [1.6, 0.3, -1]);
mat4Multiply(cube2ModelView, virtualViewMatrix, cube2ModelView);
gl.uniformMatrix4fv(virtualModelViewLocation, gl.FALSE, new Float32Array(cube2ModelView));
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexBuffer);
setAttribPointers();
gl.drawArrays(gl.TRIANGLES, 0, cubeVertices.length / 6);
// draw virtual camera
if (displayMatricesVirtually && animation.isCameraDrawn()) {
let virtualCameraModelView = [];
mat4Identity(virtualCameraModelView);
mat4Scale(virtualCameraModelView, virtualCameraModelView, [0.1, 0.1, 0.1]);
mat4Translate(virtualCameraModelView, virtualCameraModelView, [0, 0, 0.16]);
mat4Multiply(virtualCameraModelView, inverseVirtualViewMatrix, virtualCameraModelView);
mat4Multiply(virtualCameraModelView, virtualViewMatrix, virtualCameraModelView);
gl.uniformMatrix4fv(virtualModelViewLocation, gl.FALSE, new Float32Array(virtualCameraModelView));
gl.bindBuffer(gl.ARRAY_BUFFER, cameraVertexBuffer);
setAttribPointers();
gl.drawArrays(gl.TRIANGLES, 0, cameraVertices.length / 6);
}
let frustomModelMatrix = [];
mat4Multiply(frustomModelMatrix, inverseVirtualViewMatrix, inverseVirtualProjectionMatrix);
mat4Multiply(frustomModelMatrix, virtualViewMatrix, frustomModelMatrix);
// mat4Copy(inverseVirtualProjectionMatrix, frustomModelMatrix);
gl.uniformMatrix4fv(virtualModelViewLocation, gl.FALSE, new Float32Array(frustomModelMatrix));
gl.bindBuffer(gl.ARRAY_BUFFER, lineCubeVertexBuffer);
setAttribPointers();
gl.uniform3fv(colorOverrideLocation, [1, 0, 1]);
gl.drawArrays(gl.LINES, 0, lineCubeVertices.length / 6);
gl.uniform3fv(colorOverrideLocation, [0, 0, 0]);
// draw origin
let originMatrix = [];
mat4BuildPerspective4(originMatrix, 60.0 / 180.0 * Math.PI, cv.width / cv.height, 0.9, 5);
mat4Interpolate(originMatrix, identity, originMatrix, animation.interpolation(5));
gl.uniformMatrix4fv(virtualModelViewLocation, gl.FALSE, new Float32Array(originMatrix));
gl.uniformMatrix4fv(virtualProjectionLocation, gl.FALSE, new Float32Array(identity));
gl.bindBuffer(gl.ARRAY_BUFFER, originVertexBuffer);
setAttribPointers();
gl.drawArrays(gl.LINES, 0, originVertices.length / 6);
// draw origin cube
if (animation.isOriginCubeDrawn()) {
gl.bindBuffer(gl.ARRAY_BUFFER, lineCubeVertexBuffer);
setAttribPointers();
gl.uniform3fv(colorOverrideLocation, [1, 0, 0]);
gl.drawArrays(gl.LINES, 0, lineCubeVertices.length / 6);
gl.uniform3fv(colorOverrideLocation, [0, 0, 0]);
}
// draw floor
gl.useProgram(floorProgram);
let floorModelView = [];
mat4Identity(floorModelView);
mat4Scale(floorModelView, floorModelView, [10, 0, 10]);
mat4Multiply(floorModelView, realViewMatrix, floorModelView);
gl.uniformMatrix4fv(gl.getUniformLocation(floorProgram, "realModelViewMatrix"), gl.FALSE, new Float32Array(floorModelView));
gl.bindBuffer(gl.ARRAY_BUFFER, floorVertexBuffer);
setAttribPointers();
gl.drawArrays(gl.TRIANGLES, 0, floorVertices.length / 6);
frameTimes.push(performance.now() - frameStart);
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];
}
window.addEventListener("DOMContentLoaded", init);