UNPKG

s2maps-gpu

Version:

S2 Maps GPU - An open source, high-performance, and GPU-accelerated map engine for rendering large-scale, interactive maps.

477 lines (476 loc) 12 kB
/** @returns a 4x4 identity matrix */ export function create() { const m = new Float32Array(16); m[0] = 1; m[5] = 1; m[10] = 1; m[15] = 1; return m; } /** * Clone a matrix * @param m - input matrix to clone * @returns cloned matrix */ export function clone(m) { const out = new Float32Array(m.length); m.forEach((v, i) => (out[i] = v)); return out; } /** * Prepare an Blend matrix * @param m - input matrix * @param width - viewport width * @param height - viewport height * @param near - near plane * @param far - far plane * @returns the blended matrix */ export function blend(m, width, height, near, far) { m[0] = 1 / width; m[1] = 0; m[2] = 0; m[3] = 0; m[4] = 0; m[5] = 1 / height; m[6] = 0; m[7] = 0; m[8] = 0; m[9] = 0; m[11] = -1; m[12] = 0; m[13] = 0; m[15] = 0; if (far !== null && far !== Infinity) { const nf = 1 / (near - far); m[10] = (far + near) * nf; m[14] = 2 * far * near * nf; } else { m[10] = -1; m[14] = -2 * near; } return m; } /** * Prepare an Orthographic projection matrix * @param m - input matrix * @param width - viewport width * @param height - viewport height * @param far - far plane * @returns the orthographic matrix */ export function ortho(m, width, height, far) { m[0] = 1 / width; m[1] = 0; m[2] = 0; m[3] = 0; m[4] = 0; m[5] = 1 / height; m[6] = 0; m[7] = 0; m[8] = 0; m[9] = 0; m[10] = -1 / far; m[11] = 0; m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1; return m; } /** * Prepare a perspective projection matrix * @param m - input matrix * @param fovy - field of view * @param aspect - viewport aspect * @param near - near plane * @param far - far plane * @returns the perspective matrix */ export function perspective(m, fovy, aspect, near, far) { const f = 1.0 / Math.tan(fovy / 2); m[0] = f / aspect; m[1] = 0; m[2] = 0; m[3] = 0; m[4] = 0; m[5] = f; m[6] = 0; m[7] = 0; m[8] = 0; m[9] = 0; m[11] = -1; m[12] = 0; m[13] = 0; m[15] = 0; if (far !== Infinity) { const nf = 1 / (near - far); m[10] = (far + near) * nf; m[14] = 2 * far * near * nf; } else { m[10] = -1; m[14] = -2 * near; } return m; } /** * Prepare a lookAt matrix * @param eye - camera position * @param up - camera up vector * @returns the lookAt matrix */ export function lookAt(eye, up) { const m = new Float32Array(16); let x0, x1, x2, y0, y1; let y2, z0, z1, z2, len; const eyex = eye.x; const eyey = eye.y; const eyez = eye.z; const upx = up.x; const upy = up.y; const upz = up.z; z0 = eyex; z1 = eyey; z2 = eyez; len = 1 / Math.hypot(z0, z1, z2); z0 *= len; z1 *= len; z2 *= len; x0 = upy * z2 - upz * z1; x1 = upz * z0 - upx * z2; x2 = upx * z1 - upy * z0; len = Math.hypot(x0, x1, x2); if (len === 0) { x0 = 0; x1 = 0; x2 = 0; } else { len = 1 / len; x0 *= len; x1 *= len; x2 *= len; } y0 = z1 * x2 - z2 * x1; y1 = z2 * x0 - z0 * x2; y2 = z0 * x1 - z1 * x0; len = Math.hypot(y0, y1, y2); if (len === 0) { y0 = 0; y1 = 0; y2 = 0; } else { len = 1 / len; y0 *= len; y1 *= len; y2 *= len; } m[0] = x0; m[1] = y0; m[2] = z0; m[3] = 0; m[4] = x1; m[5] = y1; m[6] = z1; m[7] = 0; m[8] = x2; m[9] = y2; m[10] = z2; m[11] = 0; m[12] = -(x0 * eyex + x1 * eyey + x2 * eyez); m[13] = -(y0 * eyex + y1 * eyey + y2 * eyez); m[14] = -(z0 * eyex + z1 * eyey + z2 * eyez); m[15] = 1; return m; } /** * Add a center to the matrix * @param m - input matrix * @param v - center vector * @returns the matrix */ export function addCenter(m, v) { m[12] = v[0]; m[13] = v[1]; m[14] = v[2]; m[15] = v[3]; return m; } /** * Translate the matrix given a vector * @param m - input matrix * @param v - vector * @returns the matrix */ export function translate(m, v) { const x = v[0]; const y = v[1]; const z = v[2]; m[12] = m[0] * x + m[4] * y + m[8] * z + m[12]; m[13] = m[1] * x + m[5] * y + m[9] * z + m[13]; m[14] = m[2] * x + m[6] * y + m[10] * z + m[14]; m[15] = m[3] * x + m[7] * y + m[11] * z + m[15]; return m; } /** * Scale the matrix via a vector * @param m - input matrix * @param v - vector * @returns the matrix */ export function scale(m, v) { const x = v[0]; const y = v[1]; const z = v[2]; m[0] = m[0] * x; m[1] = m[1] * x; m[2] = m[2] * x; m[3] = m[3] * x; m[4] = m[4] * y; m[5] = m[5] * y; m[6] = m[6] * y; m[7] = m[7] * y; m[8] = m[8] * z; m[9] = m[9] * z; m[10] = m[10] * z; m[11] = m[11] * z; return m; } /** * Rotate the matrix * @param m - input matrix * @param rad - rotation in radians * @returns the matrix */ export function rotate(m, rad) { rotateX(m, rad[0]); rotateY(m, rad[1]); rotateZ(m, rad[2]); return m; } /** * Rotate the matrix around the X axis * @param m - input matrix * @param rad - rotation in radians * @returns the matrix */ export function rotateX(m, rad) { const s = Math.sin(rad); const c = Math.cos(rad); const m10 = m[4]; const m11 = m[5]; const m12 = m[6]; const m13 = m[7]; const m20 = m[8]; const m21 = m[9]; const m22 = m[10]; const m23 = m[11]; // Perform axis-specific matrix multiplication m[4] = m10 * c + m20 * s; m[5] = m11 * c + m21 * s; m[6] = m12 * c + m22 * s; m[7] = m13 * c + m23 * s; m[8] = m20 * c - m10 * s; m[9] = m21 * c - m11 * s; m[10] = m22 * c - m12 * s; m[11] = m23 * c - m13 * s; return m; } /** * Rotate the matrix around the Y axis * @param m - input matrix * @param rad - rotation in radians * @returns the matrix */ export function rotateY(m, rad) { const s = Math.sin(rad); const c = Math.cos(rad); const m00 = m[0]; const m01 = m[1]; const m02 = m[2]; const m03 = m[3]; const m20 = m[8]; const m21 = m[9]; const m22 = m[10]; const m23 = m[11]; // Perform axis-specific matrix multiplication m[0] = m00 * c - m20 * s; m[1] = m01 * c - m21 * s; m[2] = m02 * c - m22 * s; m[3] = m03 * c - m23 * s; m[8] = m00 * s + m20 * c; m[9] = m01 * s + m21 * c; m[10] = m02 * s + m22 * c; m[11] = m03 * s + m23 * c; return m; } /** * Rotate the matrix around the Z axis * @param m - input matrix * @param rad - rotation in radians * @returns the matrix */ export function rotateZ(m, rad) { const s = Math.sin(rad); const c = Math.cos(rad); const m00 = m[0]; const m01 = m[1]; const m02 = m[2]; const m03 = m[3]; const m10 = m[4]; const m11 = m[5]; const m12 = m[6]; const m13 = m[7]; // Perform axis-specific matrix multiplication m[0] = m00 * c + m10 * s; m[1] = m01 * c + m11 * s; m[2] = m02 * c + m12 * s; m[3] = m03 * c + m13 * s; m[4] = m10 * c - m00 * s; m[5] = m11 * c - m01 * s; m[6] = m12 * c - m02 * s; m[7] = m13 * c - m03 * s; return m; } /** * Multiply a matrix by a vector * @param m - input matrix * @param v - vector * @returns the vector */ export function multiplyVector(m, v) { return [ m[0] * v.x + m[4] * v.y + m[8] * (v.z ?? 0) + m[12], m[1] * v.x + m[5] * v.y + m[9] * (v.z ?? 0) + m[13], m[2] * v.x + m[6] * v.y + m[10] * (v.z ?? 0) + m[14], m[3] * v.x + m[7] * v.y + m[11] * (v.z ?? 0) + m[15], ]; } /** * Multiply two matrices * @param a - input matrix * @param b - input matrix * @returns the matrix */ export function multiply(a, b) { const a00 = a[0]; const a01 = a[1]; const a02 = a[2]; const a03 = a[3]; const a10 = a[4]; const a11 = a[5]; const a12 = a[6]; const a13 = a[7]; const a20 = a[8]; const a21 = a[9]; const a22 = a[10]; const a23 = a[11]; const a30 = a[12]; const a31 = a[13]; const a32 = a[14]; const a33 = a[15]; // Cache only the current line of the second matrix let b0 = b[0]; let b1 = b[1]; let b2 = b[2]; let b3 = b[3]; a[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; a[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; a[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; a[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7]; a[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; a[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; a[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; a[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11]; a[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; a[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; a[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; a[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15]; a[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; a[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; a[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; a[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; return a; } /** * Invert a matrix * @param matrix - input matrix * @returns the inverted matrix */ export function invert(matrix) { const a00 = matrix[0]; const a01 = matrix[1]; const a02 = matrix[2]; const a03 = matrix[3]; const a10 = matrix[4]; const a11 = matrix[5]; const a12 = matrix[6]; const a13 = matrix[7]; const a20 = matrix[8]; const a21 = matrix[9]; const a22 = matrix[10]; const a23 = matrix[11]; const a30 = matrix[12]; const a31 = matrix[13]; const a32 = matrix[14]; const a33 = matrix[15]; const b00 = a00 * a11 - a01 * a10; const b01 = a00 * a12 - a02 * a10; const b02 = a00 * a13 - a03 * a10; const b03 = a01 * a12 - a02 * a11; const b04 = a01 * a13 - a03 * a11; const b05 = a02 * a13 - a03 * a12; const b06 = a20 * a31 - a21 * a30; const b07 = a20 * a32 - a22 * a30; const b08 = a20 * a33 - a23 * a30; const b09 = a21 * a32 - a22 * a31; const b10 = a21 * a33 - a23 * a31; const b11 = a22 * a33 - a23 * a32; // Calculate the determinant let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; if (det === 0) return null; det = 1 / det; matrix[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; matrix[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det; matrix[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det; matrix[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det; matrix[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det; matrix[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det; matrix[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det; matrix[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det; matrix[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det; matrix[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det; matrix[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det; matrix[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det; matrix[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det; matrix[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det; matrix[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det; matrix[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det; return matrix; } /** * Project a 3D vector given an input matrix * @param matrix - input matrix * @param vector - vector to project * @returns the projected vector */ export function project(matrix, vector) { const [mulX, mulY, mulZ, mulT] = multiplyVector(matrix, vector); return { x: mulX / mulT, y: mulY / mulT, z: mulZ / mulT }; }