diff --git a/cg/webgl/index.html b/cg/webgl/index.html new file mode 100644 index 0000000..c98ce0e --- /dev/null +++ b/cg/webgl/index.html @@ -0,0 +1,43 @@ + + + + + + + + +
+ +
+ + + + diff --git a/cg/webgl/m4.js b/cg/webgl/m4.js new file mode 100644 index 0000000..5a628f6 --- /dev/null +++ b/cg/webgl/m4.js @@ -0,0 +1,1467 @@ +/* + * Copyright 2021 GFXFundamentals. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of GFXFundamentals. nor the names of his + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Various 3d math functions. + * + * @module webgl-3d-math + */ +(function(root, factory) { // eslint-disable-line + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define([], factory); + } else { + // Browser globals + root.m4 = factory(); + } +}(this, function() { + "use strict"; + + /** + * An array or typed array with 3 values. + * @typedef {number[]|TypedArray} Vector3 + * @memberOf module:webgl-3d-math + */ + + /** + * An array or typed array with 4 values. + * @typedef {number[]|TypedArray} Vector4 + * @memberOf module:webgl-3d-math + */ + + /** + * An array or typed array with 16 values. + * @typedef {number[]|TypedArray} Matrix4 + * @memberOf module:webgl-3d-math + */ + + + let MatType = Float32Array; + + /** + * Sets the type this library creates for a Mat4 + * @param {constructor} Ctor the constructor for the type. Either `Float32Array` or `Array` + * @return {constructor} previous constructor for Mat4 + */ + function setDefaultType(Ctor) { + const OldType = MatType; + MatType = Ctor; + return OldType; + } + + /** + * Takes two 4-by-4 matrices, a and b, and computes the product in the order + * that pre-composes b with a. In other words, the matrix returned will + * transform by b first and then a. Note this is subtly different from just + * multiplying the matrices together. For given a and b, this function returns + * the same object in both row-major and column-major mode. + * @param {Matrix4} a A matrix. + * @param {Matrix4} b A matrix. + * @param {Matrix4} [dst] optional matrix to store result + * @return {Matrix4} dst or a new matrix if none provided + */ + function multiply(a, b, dst) { + dst = dst || new MatType(16); + var b00 = b[0 * 4 + 0]; + var b01 = b[0 * 4 + 1]; + var b02 = b[0 * 4 + 2]; + var b03 = b[0 * 4 + 3]; + var b10 = b[1 * 4 + 0]; + var b11 = b[1 * 4 + 1]; + var b12 = b[1 * 4 + 2]; + var b13 = b[1 * 4 + 3]; + var b20 = b[2 * 4 + 0]; + var b21 = b[2 * 4 + 1]; + var b22 = b[2 * 4 + 2]; + var b23 = b[2 * 4 + 3]; + var b30 = b[3 * 4 + 0]; + var b31 = b[3 * 4 + 1]; + var b32 = b[3 * 4 + 2]; + var b33 = b[3 * 4 + 3]; + var a00 = a[0 * 4 + 0]; + var a01 = a[0 * 4 + 1]; + var a02 = a[0 * 4 + 2]; + var a03 = a[0 * 4 + 3]; + var a10 = a[1 * 4 + 0]; + var a11 = a[1 * 4 + 1]; + var a12 = a[1 * 4 + 2]; + var a13 = a[1 * 4 + 3]; + var a20 = a[2 * 4 + 0]; + var a21 = a[2 * 4 + 1]; + var a22 = a[2 * 4 + 2]; + var a23 = a[2 * 4 + 3]; + var a30 = a[3 * 4 + 0]; + var a31 = a[3 * 4 + 1]; + var a32 = a[3 * 4 + 2]; + var a33 = a[3 * 4 + 3]; + dst[ 0] = b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30; + dst[ 1] = b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31; + dst[ 2] = b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32; + dst[ 3] = b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33; + dst[ 4] = b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30; + dst[ 5] = b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31; + dst[ 6] = b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32; + dst[ 7] = b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33; + dst[ 8] = b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30; + dst[ 9] = b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31; + dst[10] = b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32; + dst[11] = b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33; + dst[12] = b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30; + dst[13] = b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31; + dst[14] = b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32; + dst[15] = b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33; + return dst; + } + + + /** + * adds 2 vectors3s + * @param {Vector3} a a + * @param {Vector3} b b + * @param {Vector3} dst optional vector3 to store result + * @return {Vector3} dst or new Vector3 if not provided + * @memberOf module:webgl-3d-math + */ + function addVectors(a, b, dst) { + dst = dst || new MatType(3); + dst[0] = a[0] + b[0]; + dst[1] = a[1] + b[1]; + dst[2] = a[2] + b[2]; + return dst; + } + + /** + * subtracts 2 vectors3s + * @param {Vector3} a a + * @param {Vector3} b b + * @param {Vector3} dst optional vector3 to store result + * @return {Vector3} dst or new Vector3 if not provided + * @memberOf module:webgl-3d-math + */ + function subtractVectors(a, b, dst) { + dst = dst || new MatType(3); + dst[0] = a[0] - b[0]; + dst[1] = a[1] - b[1]; + dst[2] = a[2] - b[2]; + return dst; + } + + /** + * scale vectors3 + * @param {Vector3} v vector + * @param {Number} s scale + * @param {Vector3} dst optional vector3 to store result + * @return {Vector3} dst or new Vector3 if not provided + * @memberOf module:webgl-3d-math + */ + function scaleVector(v, s, dst) { + dst = dst || new MatType(3); + dst[0] = v[0] * s; + dst[1] = v[1] * s; + dst[2] = v[2] * s; + return dst; + } + + /** + * normalizes a vector. + * @param {Vector3} v vector to normalize + * @param {Vector3} dst optional vector3 to store result + * @return {Vector3} dst or new Vector3 if not provided + * @memberOf module:webgl-3d-math + */ + function normalize(v, dst) { + dst = dst || new MatType(3); + var length = Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); + // make sure we don't divide by 0. + if (length > 0.00001) { + dst[0] = v[0] / length; + dst[1] = v[1] / length; + dst[2] = v[2] / length; + } + return dst; + } + + /** + * Computes the length of a vector + * @param {Vector3} v vector to take length of + * @return {number} length of vector + */ + function length(v) { + return Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); + } + + /** + * Computes the length squared of a vector + * @param {Vector3} v vector to take length of + * @return {number} length sqaured of vector + */ + function lengthSq(v) { + return v[0] * v[0] + v[1] * v[1] + v[2] * v[2]; + } + + /** + * Computes the cross product of 2 vectors3s + * @param {Vector3} a a + * @param {Vector3} b b + * @param {Vector3} dst optional vector3 to store result + * @return {Vector3} dst or new Vector3 if not provided + * @memberOf module:webgl-3d-math + */ + function cross(a, b, dst) { + dst = dst || new MatType(3); + dst[0] = a[1] * b[2] - a[2] * b[1]; + dst[1] = a[2] * b[0] - a[0] * b[2]; + dst[2] = a[0] * b[1] - a[1] * b[0]; + return dst; + } + + /** + * Computes the dot product of two vectors; assumes both vectors have + * three entries. + * @param {Vector3} a Operand vector. + * @param {Vector3} b Operand vector. + * @return {number} dot product + * @memberOf module:webgl-3d-math + */ + function dot(a, b) { + return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]); + } + + /** + * Computes the distance squared between 2 points + * @param {Vector3} a + * @param {Vector3} b + * @return {number} distance squared between a and b + */ + function distanceSq(a, b) { + const dx = a[0] - b[0]; + const dy = a[1] - b[1]; + const dz = a[2] - b[2]; + return dx * dx + dy * dy + dz * dz; + } + + /** + * Computes the distance between 2 points + * @param {Vector3} a + * @param {Vector3} b + * @return {number} distance between a and b + */ + function distance(a, b) { + return Math.sqrt(distanceSq(a, b)); + } + + /** + * Makes an identity matrix. + * @param {Matrix4} [dst] optional matrix to store result + * @return {Matrix4} dst or a new matrix if none provided + * @memberOf module:webgl-3d-math + */ + function identity(dst) { + dst = dst || new MatType(16); + + dst[ 0] = 1; + dst[ 1] = 0; + dst[ 2] = 0; + dst[ 3] = 0; + dst[ 4] = 0; + dst[ 5] = 1; + dst[ 6] = 0; + dst[ 7] = 0; + dst[ 8] = 0; + dst[ 9] = 0; + dst[10] = 1; + dst[11] = 0; + dst[12] = 0; + dst[13] = 0; + dst[14] = 0; + dst[15] = 1; + + return dst; + } + + /** + * Transposes a matrix. + * @param {Matrix4} m matrix to transpose. + * @param {Matrix4} [dst] optional matrix to store result + * @return {Matrix4} dst or a new matrix if none provided + * @memberOf module:webgl-3d-math + */ + function transpose(m, dst) { + dst = dst || new MatType(16); + + dst[ 0] = m[0]; + dst[ 1] = m[4]; + dst[ 2] = m[8]; + dst[ 3] = m[12]; + dst[ 4] = m[1]; + dst[ 5] = m[5]; + dst[ 6] = m[9]; + dst[ 7] = m[13]; + dst[ 8] = m[2]; + dst[ 9] = m[6]; + dst[10] = m[10]; + dst[11] = m[14]; + dst[12] = m[3]; + dst[13] = m[7]; + dst[14] = m[11]; + dst[15] = m[15]; + + return dst; + } + + /** + * Creates a lookAt matrix. + * This is a world matrix for a camera. In other words it will transform + * from the origin to a place and orientation in the world. For a view + * matrix take the inverse of this. + * @param {Vector3} cameraPosition position of the camera + * @param {Vector3} target position of the target + * @param {Vector3} up direction + * @param {Matrix4} [dst] optional matrix to store result + * @return {Matrix4} dst or a new matrix if none provided + * @memberOf module:webgl-3d-math + */ + function lookAt(cameraPosition, target, up, dst) { + dst = dst || new MatType(16); + var zAxis = normalize( + subtractVectors(cameraPosition, target)); + var xAxis = normalize(cross(up, zAxis)); + var yAxis = normalize(cross(zAxis, xAxis)); + + dst[ 0] = xAxis[0]; + dst[ 1] = xAxis[1]; + dst[ 2] = xAxis[2]; + dst[ 3] = 0; + dst[ 4] = yAxis[0]; + dst[ 5] = yAxis[1]; + dst[ 6] = yAxis[2]; + dst[ 7] = 0; + dst[ 8] = zAxis[0]; + dst[ 9] = zAxis[1]; + dst[10] = zAxis[2]; + dst[11] = 0; + dst[12] = cameraPosition[0]; + dst[13] = cameraPosition[1]; + dst[14] = cameraPosition[2]; + dst[15] = 1; + + return dst; + } + + /** + * Computes a 4-by-4 perspective transformation matrix given the angular height + * of the frustum, the aspect ratio, and the near and far clipping planes. The + * arguments define a frustum extending in the negative z direction. The given + * angle is the vertical angle of the frustum, and the horizontal angle is + * determined to produce the given aspect ratio. The arguments near and far are + * the distances to the near and far clipping planes. Note that near and far + * are not z coordinates, but rather they are distances along the negative + * z-axis. The matrix generated sends the viewing frustum to the unit box. + * We assume a unit box extending from -1 to 1 in the x and y dimensions and + * from -1 to 1 in the z dimension. + * @param {number} fieldOfViewInRadians field of view in y axis. + * @param {number} aspect aspect of viewport (width / height) + * @param {number} near near Z clipping plane + * @param {number} far far Z clipping plane + * @param {Matrix4} [dst] optional matrix to store result + * @return {Matrix4} dst or a new matrix if none provided + * @memberOf module:webgl-3d-math + */ + function perspective(fieldOfViewInRadians, aspect, near, far, dst) { + dst = dst || new MatType(16); + var f = Math.tan(Math.PI * 0.5 - 0.5 * fieldOfViewInRadians); + var rangeInv = 1.0 / (near - far); + + dst[ 0] = f / aspect; + dst[ 1] = 0; + dst[ 2] = 0; + dst[ 3] = 0; + dst[ 4] = 0; + dst[ 5] = f; + dst[ 6] = 0; + dst[ 7] = 0; + dst[ 8] = 0; + dst[ 9] = 0; + dst[10] = (near + far) * rangeInv; + dst[11] = -1; + dst[12] = 0; + dst[13] = 0; + dst[14] = near * far * rangeInv * 2; + dst[15] = 0; + + return dst; + } + + /** + * Computes a 4-by-4 orthographic projection matrix given the coordinates of the + * planes defining the axis-aligned, box-shaped viewing volume. The matrix + * generated sends that box to the unit box. Note that although left and right + * are x coordinates and bottom and top are y coordinates, near and far + * are not z coordinates, but rather they are distances along the negative + * z-axis. We assume a unit box extending from -1 to 1 in the x and y + * dimensions and from -1 to 1 in the z dimension. + * @param {number} left The x coordinate of the left plane of the box. + * @param {number} right The x coordinate of the right plane of the box. + * @param {number} bottom The y coordinate of the bottom plane of the box. + * @param {number} top The y coordinate of the right plane of the box. + * @param {number} near The negative z coordinate of the near plane of the box. + * @param {number} far The negative z coordinate of the far plane of the box. + * @param {Matrix4} [dst] optional matrix to store result + * @return {Matrix4} dst or a new matrix if none provided + * @memberOf module:webgl-3d-math + */ + function orthographic(left, right, bottom, top, near, far, dst) { + dst = dst || new MatType(16); + + dst[ 0] = 2 / (right - left); + dst[ 1] = 0; + dst[ 2] = 0; + dst[ 3] = 0; + dst[ 4] = 0; + dst[ 5] = 2 / (top - bottom); + dst[ 6] = 0; + dst[ 7] = 0; + dst[ 8] = 0; + dst[ 9] = 0; + dst[10] = 2 / (near - far); + dst[11] = 0; + dst[12] = (left + right) / (left - right); + dst[13] = (bottom + top) / (bottom - top); + dst[14] = (near + far) / (near - far); + dst[15] = 1; + + return dst; + } + + /** + * Computes a 4-by-4 perspective transformation matrix given the left, right, + * top, bottom, near and far clipping planes. The arguments define a frustum + * extending in the negative z direction. The arguments near and far are the + * distances to the near and far clipping planes. Note that near and far are not + * z coordinates, but rather they are distances along the negative z-axis. The + * matrix generated sends the viewing frustum to the unit box. We assume a unit + * box extending from -1 to 1 in the x and y dimensions and from -1 to 1 in the z + * dimension. + * @param {number} left The x coordinate of the left plane of the box. + * @param {number} right The x coordinate of the right plane of the box. + * @param {number} bottom The y coordinate of the bottom plane of the box. + * @param {number} top The y coordinate of the right plane of the box. + * @param {number} near The negative z coordinate of the near plane of the box. + * @param {number} far The negative z coordinate of the far plane of the box. + * @param {Matrix4} [dst] optional matrix to store result + * @return {Matrix4} dst or a new matrix if none provided + * @memberOf module:webgl-3d-math + */ + function frustum(left, right, bottom, top, near, far, dst) { + dst = dst || new MatType(16); + + var dx = right - left; + var dy = top - bottom; + var dz = far - near; + + dst[ 0] = 2 * near / dx; + dst[ 1] = 0; + dst[ 2] = 0; + dst[ 3] = 0; + dst[ 4] = 0; + dst[ 5] = 2 * near / dy; + dst[ 6] = 0; + dst[ 7] = 0; + dst[ 8] = (left + right) / dx; + dst[ 9] = (top + bottom) / dy; + dst[10] = -(far + near) / dz; + dst[11] = -1; + dst[12] = 0; + dst[13] = 0; + dst[14] = -2 * near * far / dz; + dst[15] = 0; + + return dst; + } + + /** + * Makes a translation matrix + * @param {number} tx x translation. + * @param {number} ty y translation. + * @param {number} tz z translation. + * @param {Matrix4} [dst] optional matrix to store result + * @return {Matrix4} dst or a new matrix if none provided + * @memberOf module:webgl-3d-math + */ + function translation(tx, ty, tz, dst) { + dst = dst || new MatType(16); + + dst[ 0] = 1; + dst[ 1] = 0; + dst[ 2] = 0; + dst[ 3] = 0; + dst[ 4] = 0; + dst[ 5] = 1; + dst[ 6] = 0; + dst[ 7] = 0; + dst[ 8] = 0; + dst[ 9] = 0; + dst[10] = 1; + dst[11] = 0; + dst[12] = tx; + dst[13] = ty; + dst[14] = tz; + dst[15] = 1; + + return dst; + } + + /** + * Multiply by translation matrix. + * @param {Matrix4} m matrix to multiply + * @param {number} tx x translation. + * @param {number} ty y translation. + * @param {number} tz z translation. + * @param {Matrix4} [dst] optional matrix to store result + * @return {Matrix4} dst or a new matrix if none provided + * @memberOf module:webgl-3d-math + */ + function translate(m, tx, ty, tz, dst) { + // This is the optimized version of + // return multiply(m, translation(tx, ty, tz), dst); + dst = dst || new MatType(16); + + var m00 = m[0]; + var m01 = m[1]; + var m02 = m[2]; + var m03 = m[3]; + var m10 = m[1 * 4 + 0]; + var m11 = m[1 * 4 + 1]; + var m12 = m[1 * 4 + 2]; + var m13 = m[1 * 4 + 3]; + var m20 = m[2 * 4 + 0]; + var m21 = m[2 * 4 + 1]; + var m22 = m[2 * 4 + 2]; + var m23 = m[2 * 4 + 3]; + var m30 = m[3 * 4 + 0]; + var m31 = m[3 * 4 + 1]; + var m32 = m[3 * 4 + 2]; + var m33 = m[3 * 4 + 3]; + + if (m !== dst) { + dst[ 0] = m00; + dst[ 1] = m01; + dst[ 2] = m02; + dst[ 3] = m03; + dst[ 4] = m10; + dst[ 5] = m11; + dst[ 6] = m12; + dst[ 7] = m13; + dst[ 8] = m20; + dst[ 9] = m21; + dst[10] = m22; + dst[11] = m23; + } + + dst[12] = m00 * tx + m10 * ty + m20 * tz + m30; + dst[13] = m01 * tx + m11 * ty + m21 * tz + m31; + dst[14] = m02 * tx + m12 * ty + m22 * tz + m32; + dst[15] = m03 * tx + m13 * ty + m23 * tz + m33; + + return dst; + } + + /** + * Makes an x rotation matrix + * @param {number} angleInRadians amount to rotate + * @param {Matrix4} [dst] optional matrix to store result + * @return {Matrix4} dst or a new matrix if none provided + * @memberOf module:webgl-3d-math + */ + function xRotation(angleInRadians, dst) { + dst = dst || new MatType(16); + var c = Math.cos(angleInRadians); + var s = Math.sin(angleInRadians); + + dst[ 0] = 1; + dst[ 1] = 0; + dst[ 2] = 0; + dst[ 3] = 0; + dst[ 4] = 0; + dst[ 5] = c; + dst[ 6] = s; + dst[ 7] = 0; + dst[ 8] = 0; + dst[ 9] = -s; + dst[10] = c; + dst[11] = 0; + dst[12] = 0; + dst[13] = 0; + dst[14] = 0; + dst[15] = 1; + + return dst; + } + + /** + * Multiply by an x rotation matrix + * @param {Matrix4} m matrix to multiply + * @param {number} angleInRadians amount to rotate + * @param {Matrix4} [dst] optional matrix to store result + * @return {Matrix4} dst or a new matrix if none provided + * @memberOf module:webgl-3d-math + */ + function xRotate(m, angleInRadians, dst) { + // this is the optimized version of + // return multiply(m, xRotation(angleInRadians), dst); + dst = dst || new MatType(16); + + var m10 = m[4]; + var m11 = m[5]; + var m12 = m[6]; + var m13 = m[7]; + var m20 = m[8]; + var m21 = m[9]; + var m22 = m[10]; + var m23 = m[11]; + var c = Math.cos(angleInRadians); + var s = Math.sin(angleInRadians); + + dst[4] = c * m10 + s * m20; + dst[5] = c * m11 + s * m21; + dst[6] = c * m12 + s * m22; + dst[7] = c * m13 + s * m23; + dst[8] = c * m20 - s * m10; + dst[9] = c * m21 - s * m11; + dst[10] = c * m22 - s * m12; + dst[11] = c * m23 - s * m13; + + if (m !== dst) { + dst[ 0] = m[ 0]; + dst[ 1] = m[ 1]; + dst[ 2] = m[ 2]; + dst[ 3] = m[ 3]; + dst[12] = m[12]; + dst[13] = m[13]; + dst[14] = m[14]; + dst[15] = m[15]; + } + + return dst; + } + + /** + * Makes an y rotation matrix + * @param {number} angleInRadians amount to rotate + * @param {Matrix4} [dst] optional matrix to store result + * @return {Matrix4} dst or a new matrix if none provided + * @memberOf module:webgl-3d-math + */ + function yRotation(angleInRadians, dst) { + dst = dst || new MatType(16); + var c = Math.cos(angleInRadians); + var s = Math.sin(angleInRadians); + + dst[ 0] = c; + dst[ 1] = 0; + dst[ 2] = -s; + dst[ 3] = 0; + dst[ 4] = 0; + dst[ 5] = 1; + dst[ 6] = 0; + dst[ 7] = 0; + dst[ 8] = s; + dst[ 9] = 0; + dst[10] = c; + dst[11] = 0; + dst[12] = 0; + dst[13] = 0; + dst[14] = 0; + dst[15] = 1; + + return dst; + } + + /** + * Multiply by an y rotation matrix + * @param {Matrix4} m matrix to multiply + * @param {number} angleInRadians amount to rotate + * @param {Matrix4} [dst] optional matrix to store result + * @return {Matrix4} dst or a new matrix if none provided + * @memberOf module:webgl-3d-math + */ + function yRotate(m, angleInRadians, dst) { + // this is the optimized version of + // return multiply(m, yRotation(angleInRadians), dst); + dst = dst || new MatType(16); + + var m00 = m[0 * 4 + 0]; + var m01 = m[0 * 4 + 1]; + var m02 = m[0 * 4 + 2]; + var m03 = m[0 * 4 + 3]; + var m20 = m[2 * 4 + 0]; + var m21 = m[2 * 4 + 1]; + var m22 = m[2 * 4 + 2]; + var m23 = m[2 * 4 + 3]; + var c = Math.cos(angleInRadians); + var s = Math.sin(angleInRadians); + + dst[ 0] = c * m00 - s * m20; + dst[ 1] = c * m01 - s * m21; + dst[ 2] = c * m02 - s * m22; + dst[ 3] = c * m03 - s * m23; + dst[ 8] = c * m20 + s * m00; + dst[ 9] = c * m21 + s * m01; + dst[10] = c * m22 + s * m02; + dst[11] = c * m23 + s * m03; + + if (m !== dst) { + dst[ 4] = m[ 4]; + dst[ 5] = m[ 5]; + dst[ 6] = m[ 6]; + dst[ 7] = m[ 7]; + dst[12] = m[12]; + dst[13] = m[13]; + dst[14] = m[14]; + dst[15] = m[15]; + } + + return dst; + } + + /** + * Makes an z rotation matrix + * @param {number} angleInRadians amount to rotate + * @param {Matrix4} [dst] optional matrix to store result + * @return {Matrix4} dst or a new matrix if none provided + * @memberOf module:webgl-3d-math + */ + function zRotation(angleInRadians, dst) { + dst = dst || new MatType(16); + var c = Math.cos(angleInRadians); + var s = Math.sin(angleInRadians); + + dst[ 0] = c; + dst[ 1] = s; + dst[ 2] = 0; + dst[ 3] = 0; + dst[ 4] = -s; + dst[ 5] = c; + dst[ 6] = 0; + dst[ 7] = 0; + dst[ 8] = 0; + dst[ 9] = 0; + dst[10] = 1; + dst[11] = 0; + dst[12] = 0; + dst[13] = 0; + dst[14] = 0; + dst[15] = 1; + + return dst; + } + + /** + * Multiply by an z rotation matrix + * @param {Matrix4} m matrix to multiply + * @param {number} angleInRadians amount to rotate + * @param {Matrix4} [dst] optional matrix to store result + * @return {Matrix4} dst or a new matrix if none provided + * @memberOf module:webgl-3d-math + */ + function zRotate(m, angleInRadians, dst) { + // This is the optimized version of + // return multiply(m, zRotation(angleInRadians), dst); + dst = dst || new MatType(16); + + var m00 = m[0 * 4 + 0]; + var m01 = m[0 * 4 + 1]; + var m02 = m[0 * 4 + 2]; + var m03 = m[0 * 4 + 3]; + var m10 = m[1 * 4 + 0]; + var m11 = m[1 * 4 + 1]; + var m12 = m[1 * 4 + 2]; + var m13 = m[1 * 4 + 3]; + var c = Math.cos(angleInRadians); + var s = Math.sin(angleInRadians); + + dst[ 0] = c * m00 + s * m10; + dst[ 1] = c * m01 + s * m11; + dst[ 2] = c * m02 + s * m12; + dst[ 3] = c * m03 + s * m13; + dst[ 4] = c * m10 - s * m00; + dst[ 5] = c * m11 - s * m01; + dst[ 6] = c * m12 - s * m02; + dst[ 7] = c * m13 - s * m03; + + if (m !== dst) { + dst[ 8] = m[ 8]; + dst[ 9] = m[ 9]; + dst[10] = m[10]; + dst[11] = m[11]; + dst[12] = m[12]; + dst[13] = m[13]; + dst[14] = m[14]; + dst[15] = m[15]; + } + + return dst; + } + + /** + * Makes an rotation matrix around an arbitrary axis + * @param {Vector3} axis axis to rotate around + * @param {number} angleInRadians amount to rotate + * @param {Matrix4} [dst] optional matrix to store result + * @return {Matrix4} dst or a new matrix if none provided + * @memberOf module:webgl-3d-math + */ + function axisRotation(axis, angleInRadians, dst) { + dst = dst || new MatType(16); + + var x = axis[0]; + var y = axis[1]; + var z = axis[2]; + var n = Math.sqrt(x * x + y * y + z * z); + x /= n; + y /= n; + z /= n; + var xx = x * x; + var yy = y * y; + var zz = z * z; + var c = Math.cos(angleInRadians); + var s = Math.sin(angleInRadians); + var oneMinusCosine = 1 - c; + + dst[ 0] = xx + (1 - xx) * c; + dst[ 1] = x * y * oneMinusCosine + z * s; + dst[ 2] = x * z * oneMinusCosine - y * s; + dst[ 3] = 0; + dst[ 4] = x * y * oneMinusCosine - z * s; + dst[ 5] = yy + (1 - yy) * c; + dst[ 6] = y * z * oneMinusCosine + x * s; + dst[ 7] = 0; + dst[ 8] = x * z * oneMinusCosine + y * s; + dst[ 9] = y * z * oneMinusCosine - x * s; + dst[10] = zz + (1 - zz) * c; + dst[11] = 0; + dst[12] = 0; + dst[13] = 0; + dst[14] = 0; + dst[15] = 1; + + return dst; + } + + /** + * Multiply by an axis rotation matrix + * @param {Matrix4} m matrix to multiply + * @param {Vector3} axis axis to rotate around + * @param {number} angleInRadians amount to rotate + * @param {Matrix4} [dst] optional matrix to store result + * @return {Matrix4} dst or a new matrix if none provided + * @memberOf module:webgl-3d-math + */ + function axisRotate(m, axis, angleInRadians, dst) { + // This is the optimized version of + // return multiply(m, axisRotation(axis, angleInRadians), dst); + dst = dst || new MatType(16); + + var x = axis[0]; + var y = axis[1]; + var z = axis[2]; + var n = Math.sqrt(x * x + y * y + z * z); + x /= n; + y /= n; + z /= n; + var xx = x * x; + var yy = y * y; + var zz = z * z; + var c = Math.cos(angleInRadians); + var s = Math.sin(angleInRadians); + var oneMinusCosine = 1 - c; + + var r00 = xx + (1 - xx) * c; + var r01 = x * y * oneMinusCosine + z * s; + var r02 = x * z * oneMinusCosine - y * s; + var r10 = x * y * oneMinusCosine - z * s; + var r11 = yy + (1 - yy) * c; + var r12 = y * z * oneMinusCosine + x * s; + var r20 = x * z * oneMinusCosine + y * s; + var r21 = y * z * oneMinusCosine - x * s; + var r22 = zz + (1 - zz) * c; + + var m00 = m[0]; + var m01 = m[1]; + var m02 = m[2]; + var m03 = m[3]; + var m10 = m[4]; + var m11 = m[5]; + var m12 = m[6]; + var m13 = m[7]; + var m20 = m[8]; + var m21 = m[9]; + var m22 = m[10]; + var m23 = m[11]; + + dst[ 0] = r00 * m00 + r01 * m10 + r02 * m20; + dst[ 1] = r00 * m01 + r01 * m11 + r02 * m21; + dst[ 2] = r00 * m02 + r01 * m12 + r02 * m22; + dst[ 3] = r00 * m03 + r01 * m13 + r02 * m23; + dst[ 4] = r10 * m00 + r11 * m10 + r12 * m20; + dst[ 5] = r10 * m01 + r11 * m11 + r12 * m21; + dst[ 6] = r10 * m02 + r11 * m12 + r12 * m22; + dst[ 7] = r10 * m03 + r11 * m13 + r12 * m23; + dst[ 8] = r20 * m00 + r21 * m10 + r22 * m20; + dst[ 9] = r20 * m01 + r21 * m11 + r22 * m21; + dst[10] = r20 * m02 + r21 * m12 + r22 * m22; + dst[11] = r20 * m03 + r21 * m13 + r22 * m23; + + if (m !== dst) { + dst[12] = m[12]; + dst[13] = m[13]; + dst[14] = m[14]; + dst[15] = m[15]; + } + + return dst; + } + + /** + * Makes a scale matrix + * @param {number} sx x scale. + * @param {number} sy y scale. + * @param {number} sz z scale. + * @param {Matrix4} [dst] optional matrix to store result + * @return {Matrix4} dst or a new matrix if none provided + * @memberOf module:webgl-3d-math + */ + function scaling(sx, sy, sz, dst) { + dst = dst || new MatType(16); + + dst[ 0] = sx; + dst[ 1] = 0; + dst[ 2] = 0; + dst[ 3] = 0; + dst[ 4] = 0; + dst[ 5] = sy; + dst[ 6] = 0; + dst[ 7] = 0; + dst[ 8] = 0; + dst[ 9] = 0; + dst[10] = sz; + dst[11] = 0; + dst[12] = 0; + dst[13] = 0; + dst[14] = 0; + dst[15] = 1; + + return dst; + } + + /** + * Multiply by a scaling matrix + * @param {Matrix4} m matrix to multiply + * @param {number} sx x scale. + * @param {number} sy y scale. + * @param {number} sz z scale. + * @param {Matrix4} [dst] optional matrix to store result + * @return {Matrix4} dst or a new matrix if none provided + * @memberOf module:webgl-3d-math + */ + function scale(m, sx, sy, sz, dst) { + // This is the optimized version of + // return multiply(m, scaling(sx, sy, sz), dst); + dst = dst || new MatType(16); + + dst[ 0] = sx * m[0 * 4 + 0]; + dst[ 1] = sx * m[0 * 4 + 1]; + dst[ 2] = sx * m[0 * 4 + 2]; + dst[ 3] = sx * m[0 * 4 + 3]; + dst[ 4] = sy * m[1 * 4 + 0]; + dst[ 5] = sy * m[1 * 4 + 1]; + dst[ 6] = sy * m[1 * 4 + 2]; + dst[ 7] = sy * m[1 * 4 + 3]; + dst[ 8] = sz * m[2 * 4 + 0]; + dst[ 9] = sz * m[2 * 4 + 1]; + dst[10] = sz * m[2 * 4 + 2]; + dst[11] = sz * m[2 * 4 + 3]; + + if (m !== dst) { + dst[12] = m[12]; + dst[13] = m[13]; + dst[14] = m[14]; + dst[15] = m[15]; + } + + return dst; + } + + /** + * creates a matrix from translation, quaternion, scale + * @param {Number[]} translation [x, y, z] translation + * @param {Number[]} quaternion [x, y, z, z] quaternion rotation + * @param {Number[]} scale [x, y, z] scale + * @param {Matrix4} [dst] optional matrix to store result + * @return {Matrix4} dst or a new matrix if none provided + */ + function compose(translation, quaternion, scale, dst) { + dst = dst || new MatType(16); + + const x = quaternion[0]; + const y = quaternion[1]; + const z = quaternion[2]; + const w = quaternion[3]; + + const x2 = x + x; + const y2 = y + y; + const z2 = z + z; + + const xx = x * x2; + const xy = x * y2; + const xz = x * z2; + + const yy = y * y2; + const yz = y * z2; + const zz = z * z2; + + const wx = w * x2; + const wy = w * y2; + const wz = w * z2; + + const sx = scale[0]; + const sy = scale[1]; + const sz = scale[2]; + + dst[0] = (1 - (yy + zz)) * sx; + dst[1] = (xy + wz) * sx; + dst[2] = (xz - wy) * sx; + dst[3] = 0; + + dst[4] = (xy - wz) * sy; + dst[5] = (1 - (xx + zz)) * sy; + dst[6] = (yz + wx) * sy; + dst[7] = 0; + + dst[ 8] = (xz + wy) * sz; + dst[ 9] = (yz - wx) * sz; + dst[10] = (1 - (xx + yy)) * sz; + dst[11] = 0; + + dst[12] = translation[0]; + dst[13] = translation[1]; + dst[14] = translation[2]; + dst[15] = 1; + + return dst; + } + + function quatFromRotationMatrix(m, dst) { + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm + + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + const m11 = m[0]; + const m12 = m[4]; + const m13 = m[8]; + const m21 = m[1]; + const m22 = m[5]; + const m23 = m[9]; + const m31 = m[2]; + const m32 = m[6]; + const m33 = m[10]; + + const trace = m11 + m22 + m33; + + if (trace > 0) { + const s = 0.5 / Math.sqrt(trace + 1); + dst[3] = 0.25 / s; + dst[0] = (m32 - m23) * s; + dst[1] = (m13 - m31) * s; + dst[2] = (m21 - m12) * s; + } else if (m11 > m22 && m11 > m33) { + const s = 2 * Math.sqrt(1 + m11 - m22 - m33); + dst[3] = (m32 - m23) / s; + dst[0] = 0.25 * s; + dst[1] = (m12 + m21) / s; + dst[2] = (m13 + m31) / s; + } else if (m22 > m33) { + const s = 2 * Math.sqrt(1 + m22 - m11 - m33); + dst[3] = (m13 - m31) / s; + dst[0] = (m12 + m21) / s; + dst[1] = 0.25 * s; + dst[2] = (m23 + m32) / s; + } else { + const s = 2 * Math.sqrt(1 + m33 - m11 - m22); + dst[3] = (m21 - m12) / s; + dst[0] = (m13 + m31) / s; + dst[1] = (m23 + m32) / s; + dst[2] = 0.25 * s; + } + } + + function decompose(mat, translation, quaternion, scale) { + let sx = m4.length(mat.slice(0, 3)); + const sy = m4.length(mat.slice(4, 7)); + const sz = m4.length(mat.slice(8, 11)); + + // if determinate is negative, we need to invert one scale + const det = determinate(mat); + if (det < 0) { + sx = -sx; + } + + translation[0] = mat[12]; + translation[1] = mat[13]; + translation[2] = mat[14]; + + // scale the rotation part + const matrix = m4.copy(mat); + + const invSX = 1 / sx; + const invSY = 1 / sy; + const invSZ = 1 / sz; + + matrix[0] *= invSX; + matrix[1] *= invSX; + matrix[2] *= invSX; + + matrix[4] *= invSY; + matrix[5] *= invSY; + matrix[6] *= invSY; + + matrix[8] *= invSZ; + matrix[9] *= invSZ; + matrix[10] *= invSZ; + + quatFromRotationMatrix(matrix, quaternion); + + scale[0] = sx; + scale[1] = sy; + scale[2] = sz; + } + + function determinate(m) { + var m00 = m[0 * 4 + 0]; + var m01 = m[0 * 4 + 1]; + var m02 = m[0 * 4 + 2]; + var m03 = m[0 * 4 + 3]; + var m10 = m[1 * 4 + 0]; + var m11 = m[1 * 4 + 1]; + var m12 = m[1 * 4 + 2]; + var m13 = m[1 * 4 + 3]; + var m20 = m[2 * 4 + 0]; + var m21 = m[2 * 4 + 1]; + var m22 = m[2 * 4 + 2]; + var m23 = m[2 * 4 + 3]; + var m30 = m[3 * 4 + 0]; + var m31 = m[3 * 4 + 1]; + var m32 = m[3 * 4 + 2]; + var m33 = m[3 * 4 + 3]; + var tmp_0 = m22 * m33; + var tmp_1 = m32 * m23; + var tmp_2 = m12 * m33; + var tmp_3 = m32 * m13; + var tmp_4 = m12 * m23; + var tmp_5 = m22 * m13; + var tmp_6 = m02 * m33; + var tmp_7 = m32 * m03; + var tmp_8 = m02 * m23; + var tmp_9 = m22 * m03; + var tmp_10 = m02 * m13; + var tmp_11 = m12 * m03; + + var t0 = (tmp_0 * m11 + tmp_3 * m21 + tmp_4 * m31) - + (tmp_1 * m11 + tmp_2 * m21 + tmp_5 * m31); + var t1 = (tmp_1 * m01 + tmp_6 * m21 + tmp_9 * m31) - + (tmp_0 * m01 + tmp_7 * m21 + tmp_8 * m31); + var t2 = (tmp_2 * m01 + tmp_7 * m11 + tmp_10 * m31) - + (tmp_3 * m01 + tmp_6 * m11 + tmp_11 * m31); + var t3 = (tmp_5 * m01 + tmp_8 * m11 + tmp_11 * m21) - + (tmp_4 * m01 + tmp_9 * m11 + tmp_10 * m21); + + return 1.0 / (m00 * t0 + m10 * t1 + m20 * t2 + m30 * t3); + } + + /** + * Computes the inverse of a matrix. + * @param {Matrix4} m matrix to compute inverse of + * @param {Matrix4} [dst] optional matrix to store result + * @return {Matrix4} dst or a new matrix if none provided + * @memberOf module:webgl-3d-math + */ + function inverse(m, dst) { + dst = dst || new MatType(16); + var m00 = m[0 * 4 + 0]; + var m01 = m[0 * 4 + 1]; + var m02 = m[0 * 4 + 2]; + var m03 = m[0 * 4 + 3]; + var m10 = m[1 * 4 + 0]; + var m11 = m[1 * 4 + 1]; + var m12 = m[1 * 4 + 2]; + var m13 = m[1 * 4 + 3]; + var m20 = m[2 * 4 + 0]; + var m21 = m[2 * 4 + 1]; + var m22 = m[2 * 4 + 2]; + var m23 = m[2 * 4 + 3]; + var m30 = m[3 * 4 + 0]; + var m31 = m[3 * 4 + 1]; + var m32 = m[3 * 4 + 2]; + var m33 = m[3 * 4 + 3]; + var tmp_0 = m22 * m33; + var tmp_1 = m32 * m23; + var tmp_2 = m12 * m33; + var tmp_3 = m32 * m13; + var tmp_4 = m12 * m23; + var tmp_5 = m22 * m13; + var tmp_6 = m02 * m33; + var tmp_7 = m32 * m03; + var tmp_8 = m02 * m23; + var tmp_9 = m22 * m03; + var tmp_10 = m02 * m13; + var tmp_11 = m12 * m03; + var tmp_12 = m20 * m31; + var tmp_13 = m30 * m21; + var tmp_14 = m10 * m31; + var tmp_15 = m30 * m11; + var tmp_16 = m10 * m21; + var tmp_17 = m20 * m11; + var tmp_18 = m00 * m31; + var tmp_19 = m30 * m01; + var tmp_20 = m00 * m21; + var tmp_21 = m20 * m01; + var tmp_22 = m00 * m11; + var tmp_23 = m10 * m01; + + var t0 = (tmp_0 * m11 + tmp_3 * m21 + tmp_4 * m31) - + (tmp_1 * m11 + tmp_2 * m21 + tmp_5 * m31); + var t1 = (tmp_1 * m01 + tmp_6 * m21 + tmp_9 * m31) - + (tmp_0 * m01 + tmp_7 * m21 + tmp_8 * m31); + var t2 = (tmp_2 * m01 + tmp_7 * m11 + tmp_10 * m31) - + (tmp_3 * m01 + tmp_6 * m11 + tmp_11 * m31); + var t3 = (tmp_5 * m01 + tmp_8 * m11 + tmp_11 * m21) - + (tmp_4 * m01 + tmp_9 * m11 + tmp_10 * m21); + + var d = 1.0 / (m00 * t0 + m10 * t1 + m20 * t2 + m30 * t3); + + dst[0] = d * t0; + dst[1] = d * t1; + dst[2] = d * t2; + dst[3] = d * t3; + dst[4] = d * ((tmp_1 * m10 + tmp_2 * m20 + tmp_5 * m30) - + (tmp_0 * m10 + tmp_3 * m20 + tmp_4 * m30)); + dst[5] = d * ((tmp_0 * m00 + tmp_7 * m20 + tmp_8 * m30) - + (tmp_1 * m00 + tmp_6 * m20 + tmp_9 * m30)); + dst[6] = d * ((tmp_3 * m00 + tmp_6 * m10 + tmp_11 * m30) - + (tmp_2 * m00 + tmp_7 * m10 + tmp_10 * m30)); + dst[7] = d * ((tmp_4 * m00 + tmp_9 * m10 + tmp_10 * m20) - + (tmp_5 * m00 + tmp_8 * m10 + tmp_11 * m20)); + dst[8] = d * ((tmp_12 * m13 + tmp_15 * m23 + tmp_16 * m33) - + (tmp_13 * m13 + tmp_14 * m23 + tmp_17 * m33)); + dst[9] = d * ((tmp_13 * m03 + tmp_18 * m23 + tmp_21 * m33) - + (tmp_12 * m03 + tmp_19 * m23 + tmp_20 * m33)); + dst[10] = d * ((tmp_14 * m03 + tmp_19 * m13 + tmp_22 * m33) - + (tmp_15 * m03 + tmp_18 * m13 + tmp_23 * m33)); + dst[11] = d * ((tmp_17 * m03 + tmp_20 * m13 + tmp_23 * m23) - + (tmp_16 * m03 + tmp_21 * m13 + tmp_22 * m23)); + dst[12] = d * ((tmp_14 * m22 + tmp_17 * m32 + tmp_13 * m12) - + (tmp_16 * m32 + tmp_12 * m12 + tmp_15 * m22)); + dst[13] = d * ((tmp_20 * m32 + tmp_12 * m02 + tmp_19 * m22) - + (tmp_18 * m22 + tmp_21 * m32 + tmp_13 * m02)); + dst[14] = d * ((tmp_18 * m12 + tmp_23 * m32 + tmp_15 * m02) - + (tmp_22 * m32 + tmp_14 * m02 + tmp_19 * m12)); + dst[15] = d * ((tmp_22 * m22 + tmp_16 * m02 + tmp_21 * m12) - + (tmp_20 * m12 + tmp_23 * m22 + tmp_17 * m02)); + + return dst; + } + + /** + * Takes a matrix and a vector with 4 entries, transforms that vector by + * the matrix, and returns the result as a vector with 4 entries. + * @param {Matrix4} m The matrix. + * @param {Vector4} v The point in homogenous coordinates. + * @param {Vector4} dst optional vector4 to store result + * @return {Vector4} dst or new Vector4 if not provided + * @memberOf module:webgl-3d-math + */ + function transformVector(m, v, dst) { + dst = dst || new MatType(4); + for (var i = 0; i < 4; ++i) { + dst[i] = 0.0; + for (var j = 0; j < 4; ++j) { + dst[i] += v[j] * m[j * 4 + i]; + } + } + return dst; + } + + /** + * Takes a 4-by-4 matrix and a vector with 3 entries, + * interprets the vector as a point, transforms that point by the matrix, and + * returns the result as a vector with 3 entries. + * @param {Matrix4} m The matrix. + * @param {Vector3} v The point. + * @param {Vector4} dst optional vector4 to store result + * @return {Vector4} dst or new Vector4 if not provided + * @memberOf module:webgl-3d-math + */ + function transformPoint(m, v, dst) { + dst = dst || new MatType(3); + var v0 = v[0]; + var v1 = v[1]; + var v2 = v[2]; + var d = v0 * m[0 * 4 + 3] + v1 * m[1 * 4 + 3] + v2 * m[2 * 4 + 3] + m[3 * 4 + 3]; + + dst[0] = (v0 * m[0 * 4 + 0] + v1 * m[1 * 4 + 0] + v2 * m[2 * 4 + 0] + m[3 * 4 + 0]) / d; + dst[1] = (v0 * m[0 * 4 + 1] + v1 * m[1 * 4 + 1] + v2 * m[2 * 4 + 1] + m[3 * 4 + 1]) / d; + dst[2] = (v0 * m[0 * 4 + 2] + v1 * m[1 * 4 + 2] + v2 * m[2 * 4 + 2] + m[3 * 4 + 2]) / d; + + return dst; + } + + /** + * Takes a 4-by-4 matrix and a vector with 3 entries, interprets the vector as a + * direction, transforms that direction by the matrix, and returns the result; + * assumes the transformation of 3-dimensional space represented by the matrix + * is parallel-preserving, i.e. any combination of rotation, scaling and + * translation, but not a perspective distortion. Returns a vector with 3 + * entries. + * @param {Matrix4} m The matrix. + * @param {Vector3} v The direction. + * @param {Vector4} dst optional vector4 to store result + * @return {Vector4} dst or new Vector4 if not provided + * @memberOf module:webgl-3d-math + */ + function transformDirection(m, v, dst) { + dst = dst || new MatType(3); + + var v0 = v[0]; + var v1 = v[1]; + var v2 = v[2]; + + dst[0] = v0 * m[0 * 4 + 0] + v1 * m[1 * 4 + 0] + v2 * m[2 * 4 + 0]; + dst[1] = v0 * m[0 * 4 + 1] + v1 * m[1 * 4 + 1] + v2 * m[2 * 4 + 1]; + dst[2] = v0 * m[0 * 4 + 2] + v1 * m[1 * 4 + 2] + v2 * m[2 * 4 + 2]; + + return dst; + } + + /** + * Takes a 4-by-4 matrix m and a vector v with 3 entries, interprets the vector + * as a normal to a surface, and computes a vector which is normal upon + * transforming that surface by the matrix. The effect of this function is the + * same as transforming v (as a direction) by the inverse-transpose of m. This + * function assumes the transformation of 3-dimensional space represented by the + * matrix is parallel-preserving, i.e. any combination of rotation, scaling and + * translation, but not a perspective distortion. Returns a vector with 3 + * entries. + * @param {Matrix4} m The matrix. + * @param {Vector3} v The normal. + * @param {Vector3} [dst] The direction. + * @return {Vector3} The transformed direction. + * @memberOf module:webgl-3d-math + */ + function transformNormal(m, v, dst) { + dst = dst || new MatType(3); + var mi = inverse(m); + var v0 = v[0]; + var v1 = v[1]; + var v2 = v[2]; + + dst[0] = v0 * mi[0 * 4 + 0] + v1 * mi[0 * 4 + 1] + v2 * mi[0 * 4 + 2]; + dst[1] = v0 * mi[1 * 4 + 0] + v1 * mi[1 * 4 + 1] + v2 * mi[1 * 4 + 2]; + dst[2] = v0 * mi[2 * 4 + 0] + v1 * mi[2 * 4 + 1] + v2 * mi[2 * 4 + 2]; + + return dst; + } + + function copy(src, dst) { + dst = dst || new MatType(16); + + dst[ 0] = src[ 0]; + dst[ 1] = src[ 1]; + dst[ 2] = src[ 2]; + dst[ 3] = src[ 3]; + dst[ 4] = src[ 4]; + dst[ 5] = src[ 5]; + dst[ 6] = src[ 6]; + dst[ 7] = src[ 7]; + dst[ 8] = src[ 8]; + dst[ 9] = src[ 9]; + dst[10] = src[10]; + dst[11] = src[11]; + dst[12] = src[12]; + dst[13] = src[13]; + dst[14] = src[14]; + dst[15] = src[15]; + + return dst; + } + + return { + copy: copy, + lookAt: lookAt, + addVectors: addVectors, + subtractVectors: subtractVectors, + scaleVector: scaleVector, + distance: distance, + distanceSq: distanceSq, + normalize: normalize, + compose: compose, + cross: cross, + decompose: decompose, + dot: dot, + identity: identity, + transpose: transpose, + length: length, + lengthSq: lengthSq, + orthographic: orthographic, + frustum: frustum, + perspective: perspective, + translation: translation, + translate: translate, + xRotation: xRotation, + yRotation: yRotation, + zRotation: zRotation, + xRotate: xRotate, + yRotate: yRotate, + zRotate: zRotate, + axisRotation: axisRotation, + axisRotate: axisRotate, + scaling: scaling, + scale: scale, + multiply: multiply, + inverse: inverse, + transformVector: transformVector, + transformPoint: transformPoint, + transformDirection: transformDirection, + transformNormal: transformNormal, + setDefaultType: setDefaultType, + }; + +})); + + diff --git a/cg/webgl/webgl.js b/cg/webgl/webgl.js new file mode 100644 index 0000000..be5a222 --- /dev/null +++ b/cg/webgl/webgl.js @@ -0,0 +1,323 @@ +"use strict"; + +const v3 = { + add: function (v1, v2) { + return [v1[0] + v2[0], v1[1] + v2[1], v1[2] + v2[2]]; + }, + normalize: function (v) { + return v3.scale(v, 1 / v3.norm(v)); + }, + norm: function (v) { + return Math.sqrt(Math.pow(v[0], 2) + Math.pow(v[1], 2) + Math.pow(v[2], 2)); + }, + scale: function (v, f) { + return [v[0] * f, v[1] * f, v[2] * f]; + }, +}; + +function getGyroPermission(){ + if(!DeviceOrientationEvent.requestPermission){ + return Promise.resolve("granted") + } + else{ + return DeviceOrientationEvent.requestPermission() + } +} + +function createShader(gl, type, source) { + const shader = gl.createShader(type); + gl.shaderSource(shader, source); + gl.compileShader(shader); + + if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { + throw new Error(gl.getShaderInfoLog(shader)); + } + + return shader; +} + +function createProgram(gl, shaders) { + const program = gl.createProgram(); + for (const shader of shaders) { + gl.attachShader(program, shader); + } + gl.linkProgram(program); + + if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { + throw new Error(gl.getProgramInfoLog(program)); + } + + return program; +} + +function initIsocahedron(vertices, elements) { + const t = 1 + Math.sqrt(5) / 2; + + vertices.push( + v3.normalize([-1, t, 0]), + v3.normalize([1, t, 0]), + v3.normalize([-1, -t, 0]), + v3.normalize([1, -t, 0]), + v3.normalize([0, -1, t]), + v3.normalize([0, 1, t]), + v3.normalize([0, -1, -t]), + v3.normalize([0, 1, -t]), + v3.normalize([t, 0, -1]), + v3.normalize([t, 0, 1]), + v3.normalize([-t, 0, -1]), + v3.normalize([-t, 0, 1]), + ); + + elements.push( + 0, 11, 5, + 0, 5, 1, + 0, 1, 7, + 0, 7, 10, + 0, 10, 11, + 1, 5, 9, + 5, 11, 4, + 11, 10, 2, + 10, 7, 6, + 7, 1, 8, + 3, 9, 4, + 3, 4, 2, + 3, 2, 6, + 3, 6, 8, + 3, 8, 9, + 4, 9, 5, + 2, 4, 11, + 6, 2, 10, + 8, 6, 7, + 9, 8, 1, + ); +} + +function getMidpoint(vertices, midpoints, i0, i1) { + const k = `${i0}_${i1}`; + if (midpoints.has(k)) { + return vertices[midpoints[k]]; + } + + const p0 = vertices[i0]; + const p1 = vertices[i1]; + + const midpoint = v3.normalize(v3.scale(v3.add(p0, p1), 0.5)); + const midpointIndex = vertices.length; + midpoints.set(k, midpointIndex); + vertices.push(midpoint); + return midpointIndex; +} + +function subdivideIsocahedron(vertices, elements, midpoints) { + const newElements = []; + for (let i = 0; i < elements.length; i += 3) { + const p0 = elements[i]; + const p1 = elements[i + 1]; + const p2 = elements[i + 2]; + const m0 = getMidpoint(vertices, midpoints, p0, p1); + const m1 = getMidpoint(vertices, midpoints, p1, p2); + const m2 = getMidpoint(vertices, midpoints, p2, p0); + + newElements.push( + m0, m1, m2, + p0, m0, m2, + p1, m1, m0, + p2, m2, m1 + ); + } + return newElements; +} + +function generateIsocahedron() { + const r = 1; + const n = 3; + const tau = 2 * Math.PI; + + const vertices = []; + const normals = []; + let elements = []; + + initIsocahedron(vertices, elements); + const midpoints = new Map(); + for (let i = 0; i < 1; i++) { + elements = subdivideIsocahedron(vertices, elements, midpoints); + } + + return { + vertices: [].concat(...vertices), + // as we want to approximate a unit sphere, all the vertices are unit vectors + normals: [].concat(...vertices), + elements + }; +} + +const canvas = document.querySelector("#canvas"); +const gl = canvas.getContext("webgl"); + +const vertexShader = createShader(gl, gl.VERTEX_SHADER, ` + attribute vec4 a_position; + attribute vec3 a_normal; + + uniform mat4 u_matrix; + uniform mat4 u_world; + uniform mat4 u_worldIT; + uniform vec3 u_light; + uniform vec3 u_camera; + + varying vec3 v_normal; + varying vec3 v_surfaceToLight; + varying vec3 v_surfaceToView; + varying vec3 v_pos; + + void main() { + gl_Position = u_matrix * a_position; + v_pos = a_position.rgb; + v_pos.r = abs(v_pos.r); + v_pos.g = abs(v_pos.g); + v_pos.b = abs(v_pos.b); + + v_normal = mat3(u_worldIT) * a_normal; + + vec3 surfaceWorldPos = (u_world * a_position).xyz; + v_surfaceToLight = u_light - surfaceWorldPos; + + v_surfaceToView = u_camera - surfaceWorldPos; + } +`); + +const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, ` + precision highp float; + + varying vec3 v_normal; + varying vec3 v_surfaceToLight; + varying vec3 v_surfaceToView; + varying vec3 v_pos; + + void main() { + vec3 halfVector = normalize(normalize(v_surfaceToLight) + normalize(v_surfaceToView)); + + float ka = 0.3; + float kd = 0.8; + float ks = 0.6; + float gamma = 100.0; + + gl_FragColor = vec4(v_pos, 1.0); + gl_FragColor.rgb *= ka + (kd * dot(normalize(v_normal), normalize(v_surfaceToLight))); + gl_FragColor.rgb += ks * pow(max(0.0, dot(normalize(v_normal), halfVector)), gamma); + } +`); + +const program = createProgram(gl, [vertexShader, fragmentShader]); + +const {vertices, normals, elements} = generateIsocahedron(); + +const positionBuffer = gl.createBuffer(); +gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer) +gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); + +const normalBuffer = gl.createBuffer(); +gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer); +gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(normals), gl.STATIC_DRAW); + +const elementBuffer = gl.createBuffer(); +gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elementBuffer); +gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(elements), gl.STATIC_DRAW); + +gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); + +gl.enable(gl.DEPTH_TEST); +gl.enable(gl.CULL_FACE); + +const positionAttribLocation = gl.getAttribLocation(program, "a_position"); +const normalAttribLocation = gl.getAttribLocation(program, "a_normal"); + +const matrixLocation = gl.getUniformLocation(program, "u_matrix"); +const worldMatrixLocation = gl.getUniformLocation(program, "u_world"); +const worldITMatrixLocation = gl.getUniformLocation(program, "u_worldIT"); +const lightVecLocation = gl.getUniformLocation(program, "u_light"); +const cameraVecLocation = gl.getUniformLocation(program, "u_camera"); + +const aspectRatio = gl.canvas.width / gl.canvas.height; +const zNear = 1; +const zFar = 2000; + +const rotation = [0, 0, 0]; + +gl.useProgram(program); + +gl.enableVertexAttribArray(positionAttribLocation); +gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); +gl.vertexAttribPointer( + positionAttribLocation, + 3, // element size + gl.FLOAT, + false, // normalize + 0, // stride + 0 // offset +); + +gl.enableVertexAttribArray(normalAttribLocation); +gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer); +gl.vertexAttribPointer(normalAttribLocation, 3, gl.FLOAT, false, 0, 0); + +gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elementBuffer); + +function drawScene () { + window.requestAnimationFrame(drawScene); + + const t = performance.now() / 1000; + + const lightPos = [10, 10, 30]; + const projectionMatrix = m4.perspective(Math.PI / 180 * 60, aspectRatio, zNear, zFar); + const cameraPos = [0, 0, 30]; + const target = [0, 0, 0]; + const up = [0, 1, 0]; + const cameraMatrix = m4.lookAt(cameraPos, target, up); + const viewMatrix = m4.inverse(cameraMatrix); + let worldMatrix = m4.identity(); + worldMatrix = m4.xRotate(worldMatrix, rotation[0]); + worldMatrix = m4.yRotate(worldMatrix, rotation[1]); + worldMatrix = m4.zRotate(worldMatrix, rotation[2]); + worldMatrix = m4.scale(worldMatrix, 12, 12, 12); + + const worldITMatrix = m4.transpose(m4.inverse(worldMatrix)); + const viewProjectionMatrix = m4.multiply(projectionMatrix, viewMatrix); + const worldViewProjectionMatrix = m4.multiply(viewProjectionMatrix, worldMatrix); + + /* + let matrix = projectionMatrix; + matrix = m4.translate(matrix, 0, 0, -30); + matrix = m4.xRotate(matrix, rotation[0]); + matrix = m4.yRotate(matrix, rotation[1]); + matrix = m4.zRotate(matrix, rotation[2]); + matrix = m4.scale(matrix, 10, 10, 10); + */ + gl.uniformMatrix4fv(matrixLocation, false, worldViewProjectionMatrix); + gl.uniformMatrix4fv(worldMatrixLocation, false, worldMatrix); + gl.uniformMatrix4fv(worldITMatrixLocation, false, worldITMatrix); + gl.uniform3fv(lightVecLocation, lightPos); + gl.uniform3fv(cameraVecLocation, cameraPos); + + gl.clearColor(0, 0, 0, 1); + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + + gl.drawElements( + gl.TRIANGLES, + elements.length, // count + gl.UNSIGNED_SHORT, + 0, // offset + ); +} + +drawScene(); + +canvas.addEventListener("click", e => { + getGyroPermission() + .then(response => { + window.addEventListener("deviceorientation", e => { + rotation[0] = 2 * (-e.beta / 180 * Math.PI); + rotation[1] = 2 * (-e.gamma / 180 * Math.PI); + rotation[2] = 2 * (-e.alpha / 180 * Math.PI + Math.PI / 2); + }); + }); +}); diff --git a/gyro/AufnahmeLIna.mp3 b/gyro/AufnahmeLIna.mp3 new file mode 100644 index 0000000..67893cb Binary files /dev/null and b/gyro/AufnahmeLIna.mp3 differ diff --git a/gyro/Untitled-1.html b/gyro/Untitled-1.html new file mode 100644 index 0000000..08ba0df --- /dev/null +++ b/gyro/Untitled-1.html @@ -0,0 +1,130 @@ + + + + + + + +

colles gyro dingens

+ +ich bin der Davidmann2 + +
+ + status + + + loading + +
+ +
+ + gyro + + + loading + +
+ +
+ + gyro + + + loading + +
+ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gyro/blatters.mp3 b/gyro/blatters.mp3 new file mode 100644 index 0000000..a3e6542 Binary files /dev/null and b/gyro/blatters.mp3 differ diff --git a/gyro/index.html b/gyro/index.html new file mode 100644 index 0000000..c3982ca --- /dev/null +++ b/gyro/index.html @@ -0,0 +1,26 @@ + + + +

Is it working?

+ +
lalala
+ + +