From 115ab9c3c29449bd54960b6b212381d615c8231a Mon Sep 17 00:00:00 2001 From: Luca Conte Date: Thu, 8 May 2025 16:34:29 +0200 Subject: [PATCH 1/6] add license --- LICENSE.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 LICENSE.md diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..be02dfa --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,25 @@ +The MIT License (MIT) +===================== + +Copyright © 2025 Luca Conte, Dennis Allerkamp + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the “Software”), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. From 9a05f717fc70d93807ba1901899608e370d0b5ed Mon Sep 17 00:00:00 2001 From: Dennis Allerkamp Date: Thu, 8 May 2025 19:54:30 +0200 Subject: [PATCH 2/6] Decomposition into several matrices --- src/index.html | 77 +++++++++++++++++++++++++++++++++--------- src/matrix-math.js | 63 ++++++++++++++++++++++++++++++++++ src/script.js | 84 ++++++++++++++++++++++++++++++++-------------- 3 files changed, 184 insertions(+), 40 deletions(-) diff --git a/src/index.html b/src/index.html index 7e7b32d..4ced571 100644 --- a/src/index.html +++ b/src/index.html @@ -4,6 +4,7 @@ CG1 MDI + @@ -61,28 +62,18 @@ #controls { left: 20px; } + + #interpolate { + width: 100%; + }
- FPS: - -
- -
- Click & Drag to move camera -
-
- Scroll to zoom -
-
- LookAt Matrix: -
-
- Projection Matrix: -
Invert Z-Axis:
+ FPS: -
Use virtual camera: @@ -91,6 +82,62 @@ Backface Culling:
+ +
+
+ $$ + \color{red} + \begin{pmatrix} + 1 & 0 & 0 & 0 \\ + 0 & 1 & 0 & 0 \\ + 0 & 0 & -1 & 0 \\ + 0 & 0 & 0 & 1 + \end{pmatrix} + \begin{pmatrix} + \frac{2}{r-l} & 0 & 0 & 0 \\ + 0 & \frac{2}{t-b} & 0 & 0 \\ + 0 & 0 & \frac{2}{f-n} & 0 \\ + 0 & 0 & 0 & 1 + \end{pmatrix} + \begin{pmatrix} + 1 & 0 & 0 & - \frac{r+l}{2} \\ + 0 & 1 & 0 & - \frac{t+b}{2} \\ + 0 & 0 & 1 & \frac{n+f}{2} \\ + 0 & 0 & 0 & 1 + \end{pmatrix} + \begin{pmatrix} + 1 & 0 & 0 & 0 \\ + 0 & 1 & 0 & 0 \\ + 0 & 0 & 1 + \frac{f}{n} & f \\ + 0 & 0 & - \frac{1}{n} & 0 + \end{pmatrix} + \color{green} + \begin{pmatrix} + u_x & u_y & u_z & 0 \\ + v_x & v_y & v_z & 0 \\ + n_x & n_y & n_z & 0 \\ + 0 & 0 & 0 & 1 + \end{pmatrix} + \begin{pmatrix} + 1 & 0 & 0 & -e_x \\ + 0 & 1 & 0 & -e_y \\ + 0 & 0 & 1 & -e_z \\ + 0 & 0 & 0 & 1 + \end{pmatrix} + $$ + + + + + + + + +
+
+ +
+
\ No newline at end of file diff --git a/src/matrix-math.js b/src/matrix-math.js index 4281632..d0a9e98 100644 --- a/src/matrix-math.js +++ b/src/matrix-math.js @@ -173,6 +173,32 @@ function mat4BuildLookAt(out, eye, look, up) { out[2] = n[0]; out[6] = n[1]; out[10] = n[2]; out[14] = t[2]; out[3] = 0; out[7] = 0; out[11] = 0; out[15] = 1; } +function mat4BuildLookAt1(out, eye, look, up) { + out[0] = 1; out[4] = 0; out[8] = 0; out[12] = -eye[0]; + out[1] = 0; out[5] = 1; out[9] = 0; out[13] = -eye[1]; + out[2] = 0; out[6] = 0; out[10] = 1; out[14] = -eye[2]; + out[3] = 0; out[7] = 0; out[11] = 0; out[15] = 1; +} +function mat4BuildLookAt2(out, eye, look, up) { + let n = []; + let u = []; + let v = []; + + vec3Subtract(n, eye, look); + + vec3CrossProduct(u, up, n); + + vec3CrossProduct(v, n, u); + + vec3Normalise(n, n); + vec3Normalise(u, u); + vec3Normalise(v, v); + + out[0] = u[0]; out[4] = u[1]; out[8] = u[2]; out[12] = 0; + out[1] = v[0]; out[5] = v[1]; out[9] = v[2]; out[13] = 0; + out[2] = n[0]; out[6] = n[1]; out[10] = n[2]; out[14] = 0; + out[3] = 0; out[7] = 0; out[11] = 0; out[15] = 1; +} /** * builds a projection matrix, overwriting out @@ -209,6 +235,43 @@ function mat4BuildPerspective(out, fovy, aspect, n, f) { mat4BuildProjection(out, r, l, t, b, n, f); } +function mat4BuildPerspective1(out, fovy, aspect, n, f) { + mat4Identity(out); + out[10] = 1.0 + f / n; + out[11] = -1.0 / n; + out[14] = f; + out[15] = 0.0; +} +function mat4BuildPerspective2(out, fovy, aspect, n, f) { + let t = n * Math.tan(0.5 * fovy); + let b = -t; + + let r = aspect * t; + let l = -r; + + mat4Identity(out); + out[12] = -(r + l) / 2.0; + out[13] = -(t + b) / 2.0; + out[14] = (f + n) / 2.0; +} +function mat4BuildPerspective3(out, fovy, aspect, n, f) { + let t = n * Math.tan(0.5 * fovy); + let b = -t; + + let r = aspect * t; + let l = -r; + + mat4Identity(out); + + out[0] = 2.0 / (r - l); + out[5] = 2.0 / (t - b); + out[10] = 2.0 / (f - n); +} +function mat4BuildPerspective4(out, fovy, aspect, n, f) { + mat4Identity(out); + out[10] = -1.0; +} + /** * linearly interpolates between a and b, storing the result in out diff --git a/src/script.js b/src/script.js index d09f747..03e24a7 100644 --- a/src/script.js +++ b/src/script.js @@ -28,6 +28,8 @@ let lastFrame = Date.now(); let interpolateProjection = 0; let interpolateLookAt = 0; +let interpolate = [0, 0, 0, 0, 0, 0]; + let displayMatricesVirtually = true; let virtualRealInterpolation = 1; @@ -64,34 +66,37 @@ async function init() { // input handling - document.getElementById("interpolateProjection").addEventListener("input", (e) => { - interpolateProjection = e.target.value; - if (interpolateProjection <= 0) { - document.getElementById("interpolateLookAt").disabled = ""; - } else { - document.getElementById("interpolateLookAt").disabled = "yes"; + document.getElementById("interpolate").addEventListener("input", (e) => { + let t = 6.0 - e.target.value; + if (t <= 2.0) { + interpolateLookAt = t / 2.0; + interpolateProjection = 0.0; + invertZAxis = false; } - }); - document.getElementById("invertZAxis").addEventListener("input", (e) => { - invertZAxis = e.target.checked; - }); - document.getElementById("interpolateLookAt").addEventListener("input", (e) => { - interpolateLookAt = e.target.value; - if (interpolateLookAt >= 1) { - document.getElementById("interpolateProjection").disabled = ""; - } else { - document.getElementById("interpolateProjection").disabled = "yes"; + else if (t <= 5.0) { + interpolateLookAt = 1.0; + interpolateProjection = (t - 2.0) / 3.0; + invertZAxis = false; + } + else { + interpolateLookAt = 1.0; + interpolateProjection = 1.0; + invertZAxis = true; + } + for (let i = 0; i < 6; ++i) { + if (i > t) { + interpolate[i] = 0.0; + } + else if (i+1 > t) { + interpolate[i] = t - Math.floor(t); + } + else { + interpolate[i] = 1.0; + } } }); document.getElementById("displayMatricesVirtually").addEventListener("input", (e) => { displayMatricesVirtually = e.target.checked; - if (!displayMatricesVirtually) { - document.getElementById("invertZAxis").checked = true; - document.getElementById("invertZAxis").disabled = true; - } else { - document.getElementById("invertZAxis").checked = invertZAxis; - document.getElementById("invertZAxis").disabled = false; - } }); document.getElementById("backfaceCulling").addEventListener("input", (e) => { if (e.target.checked) { @@ -531,8 +536,37 @@ async function draw() { let inverseVirtualViewMatrix = []; mat4Inverse(inverseVirtualViewMatrix, virtualViewMatrix); - mat4Interpolate(virtualProjectionMatrix, identity, virtualProjectionMatrix, interpolateProjection); - mat4Interpolate(virtualViewMatrix, identity, virtualViewMatrix, interpolateLookAt); + // interpolated view matrix + let virtualViewMatrix1 = []; + mat4BuildLookAt1(virtualViewMatrix1, virtualCameraPosition, virtualCameraLookAt, virtualCameraUp); + mat4Interpolate(virtualViewMatrix1, identity, virtualViewMatrix1, interpolate[0]); + + let virtualViewMatrix2 = []; + mat4BuildLookAt2(virtualViewMatrix2, virtualCameraPosition, virtualCameraLookAt, virtualCameraUp); + mat4Interpolate(virtualViewMatrix2, identity, virtualViewMatrix2, interpolate[1]); + + mat4Multiply(virtualViewMatrix, virtualViewMatrix2, virtualViewMatrix1); + + // interpolated projection matrix + let virtualProjectionMatrix1 = []; + mat4BuildPerspective1(virtualProjectionMatrix1, 90.0 / 180.0 * Math.PI, cv.width / cv.height, 0.9, 5); + mat4Interpolate(virtualProjectionMatrix1, identity, virtualProjectionMatrix1, interpolate[2]); + + let virtualProjectionMatrix2 = []; + mat4BuildPerspective2(virtualProjectionMatrix2, 90.0 / 180.0 * Math.PI, cv.width / cv.height, 0.9, 5); + mat4Interpolate(virtualProjectionMatrix2, identity, virtualProjectionMatrix2, interpolate[3]); + + let virtualProjectionMatrix3 = []; + mat4BuildPerspective3(virtualProjectionMatrix3, 90.0 / 180.0 * Math.PI, cv.width / cv.height, 0.9, 5); + mat4Interpolate(virtualProjectionMatrix3, identity, virtualProjectionMatrix3, interpolate[4]); + + let virtualProjectionMatrix4 = []; + mat4BuildPerspective4(virtualProjectionMatrix4, 90.0 / 180.0 * Math.PI, cv.width / cv.height, 0.9, 5); + mat4Interpolate(virtualProjectionMatrix4, identity, virtualProjectionMatrix4, interpolate[5]); + + mat4Multiply(virtualProjectionMatrix, virtualProjectionMatrix4, virtualProjectionMatrix3); + mat4Multiply(virtualProjectionMatrix, virtualProjectionMatrix, virtualProjectionMatrix2); + mat4Multiply(virtualProjectionMatrix, virtualProjectionMatrix, virtualProjectionMatrix1); gl.uniformMatrix4fv(virtualProjectionLocation, gl.FALSE, new Float32Array(virtualProjectionMatrix)); From 1d05e0053aa039df5a3f3b55eff17106d4a061c3 Mon Sep 17 00:00:00 2001 From: Dennis Allerkamp Date: Fri, 9 May 2025 12:48:26 +0200 Subject: [PATCH 3/6] Transparent backgroound --- src/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/index.html b/src/index.html index 4ced571..0d50e63 100644 --- a/src/index.html +++ b/src/index.html @@ -51,7 +51,7 @@ padding: 20px; display: block; border: solid 2px #11111b; - background-color: #313244; + background-color: #31324480; border-radius: 20px; } @@ -125,7 +125,7 @@ 0 & 0 & 0 & 1 \end{pmatrix} $$ - + From ecf7e2074b78f1d62cf36e790e18717d8004c51c Mon Sep 17 00:00:00 2001 From: Dennis Allerkamp Date: Fri, 9 May 2025 12:51:53 +0200 Subject: [PATCH 4/6] Removed interpolation variables --- src/script.js | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/script.js b/src/script.js index 03e24a7..9903a55 100644 --- a/src/script.js +++ b/src/script.js @@ -25,9 +25,7 @@ let cameraVertexBuffer; let lastFrame = Date.now(); -let interpolateProjection = 0; -let interpolateLookAt = 0; - +let t = 0.0; let interpolate = [0, 0, 0, 0, 0, 0]; let displayMatricesVirtually = true; @@ -67,20 +65,14 @@ async function init() { // input handling document.getElementById("interpolate").addEventListener("input", (e) => { - let t = 6.0 - e.target.value; + t = 6.0 - e.target.value; if (t <= 2.0) { - interpolateLookAt = t / 2.0; - interpolateProjection = 0.0; invertZAxis = false; } else if (t <= 5.0) { - interpolateLookAt = 1.0; - interpolateProjection = (t - 2.0) / 3.0; invertZAxis = false; } else { - interpolateLookAt = 1.0; - interpolateProjection = 1.0; invertZAxis = true; } for (let i = 0; i < 6; ++i) { @@ -634,7 +626,7 @@ async function draw() { gl.bindBuffer(gl.ARRAY_BUFFER, cameraVertexBuffer); setAttribPointers(); - if (displayMatricesVirtually && interpolateProjection <= 0) { + if (displayMatricesVirtually && t <= 2.0) { gl.drawArrays(gl.TRIANGLES, 0, cameraVertices.length / 6); } @@ -663,7 +655,7 @@ async function draw() { // draw origin cube - if (interpolateProjection < 1 && interpolateLookAt > 0) { + if (t != 0.0 && t < 5.0) { gl.bindBuffer(gl.ARRAY_BUFFER, lineCubeVertexBuffer); setAttribPointers(); gl.uniform3fv(colorOverrideLocation, [1, 0, 0]); From 0307759a8d62dc15d6af04e954375c7e4b57c498 Mon Sep 17 00:00:00 2001 From: Dennis Allerkamp Date: Fri, 9 May 2025 12:54:07 +0200 Subject: [PATCH 5/6] Invert z-Axis instead of objects --- src/script.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/script.js b/src/script.js index 9903a55..0bcf16f 100644 --- a/src/script.js +++ b/src/script.js @@ -552,11 +552,8 @@ async function draw() { mat4BuildPerspective3(virtualProjectionMatrix3, 90.0 / 180.0 * Math.PI, cv.width / cv.height, 0.9, 5); mat4Interpolate(virtualProjectionMatrix3, identity, virtualProjectionMatrix3, interpolate[4]); - let virtualProjectionMatrix4 = []; - mat4BuildPerspective4(virtualProjectionMatrix4, 90.0 / 180.0 * Math.PI, cv.width / cv.height, 0.9, 5); - mat4Interpolate(virtualProjectionMatrix4, identity, virtualProjectionMatrix4, interpolate[5]); - - mat4Multiply(virtualProjectionMatrix, virtualProjectionMatrix4, virtualProjectionMatrix3); + mat4Identity(virtualProjectionMatrix); + mat4Multiply(virtualProjectionMatrix, virtualProjectionMatrix, virtualProjectionMatrix3); mat4Multiply(virtualProjectionMatrix, virtualProjectionMatrix, virtualProjectionMatrix2); mat4Multiply(virtualProjectionMatrix, virtualProjectionMatrix, virtualProjectionMatrix1); @@ -645,8 +642,11 @@ async function draw() { // draw origin + let originMatrix = []; + mat4BuildPerspective4(originMatrix, 60.0 / 180.0 * Math.PI, cv.width / cv.height, 0.9, 5); + mat4Interpolate(originMatrix, identity, originMatrix, interpolate[5]); - gl.uniformMatrix4fv(virtualModelViewLocation, gl.FALSE, new Float32Array(identity)); + gl.uniformMatrix4fv(virtualModelViewLocation, gl.FALSE, new Float32Array(originMatrix)); gl.uniformMatrix4fv(virtualProjectionLocation, gl.FALSE, new Float32Array(identity)); gl.bindBuffer(gl.ARRAY_BUFFER, originVertexBuffer); From 475214663027913f79d87b1b57a229d8e934e5cf Mon Sep 17 00:00:00 2001 From: Dennis Allerkamp Date: Fri, 9 May 2025 12:54:28 +0200 Subject: [PATCH 6/6] Minor visual improvements --- src/script.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/script.js b/src/script.js index 0bcf16f..8055b8d 100644 --- a/src/script.js +++ b/src/script.js @@ -410,6 +410,7 @@ async function init() { 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); @@ -480,7 +481,7 @@ async function draw() { // Real Matrices let realProjectionMatrix = []; - mat4BuildPerspective(realProjectionMatrix, 90.0 / 180.0 * Math.PI, cv.width / cv.height, 0.1, 30); + 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)]; @@ -506,7 +507,7 @@ async function draw() { let virtualProjectionMatrix = []; - mat4BuildPerspective(virtualProjectionMatrix, 90.0 / 180.0 * Math.PI, cv.width / cv.height, 0.9, 5); + mat4BuildPerspective(virtualProjectionMatrix, 60.0 / 180.0 * Math.PI, cv.width / cv.height, 0.9, 5); if (!invertZAxis) { let zAxisFlipMatrix = []; @@ -541,15 +542,15 @@ async function draw() { // interpolated projection matrix let virtualProjectionMatrix1 = []; - mat4BuildPerspective1(virtualProjectionMatrix1, 90.0 / 180.0 * Math.PI, cv.width / cv.height, 0.9, 5); + mat4BuildPerspective1(virtualProjectionMatrix1, 60.0 / 180.0 * Math.PI, cv.width / cv.height, 0.9, 5); mat4Interpolate(virtualProjectionMatrix1, identity, virtualProjectionMatrix1, interpolate[2]); let virtualProjectionMatrix2 = []; - mat4BuildPerspective2(virtualProjectionMatrix2, 90.0 / 180.0 * Math.PI, cv.width / cv.height, 0.9, 5); + mat4BuildPerspective2(virtualProjectionMatrix2, 60.0 / 180.0 * Math.PI, cv.width / cv.height, 0.9, 5); mat4Interpolate(virtualProjectionMatrix2, identity, virtualProjectionMatrix2, interpolate[3]); let virtualProjectionMatrix3 = []; - mat4BuildPerspective3(virtualProjectionMatrix3, 90.0 / 180.0 * Math.PI, cv.width / cv.height, 0.9, 5); + mat4BuildPerspective3(virtualProjectionMatrix3, 60.0 / 180.0 * Math.PI, cv.width / cv.height, 0.9, 5); mat4Interpolate(virtualProjectionMatrix3, identity, virtualProjectionMatrix3, interpolate[4]); mat4Identity(virtualProjectionMatrix);