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));