├── .editorconfig ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── __tests__ ├── browser │ └── test.html ├── float32vector.test.ts ├── lib │ └── close_to.ts ├── matrix.test.ts └── quaternion.test.ts ├── build └── matrixgl.min.js ├── docs ├── .nojekyll ├── assets │ ├── highlight.css │ ├── icons.css │ ├── icons.png │ ├── icons@2x.png │ ├── main.js │ ├── search.js │ ├── style.css │ ├── widgets.png │ └── widgets@2x.png ├── classes │ ├── Float32Vector2.html │ ├── Float32Vector3.html │ ├── Float32Vector4.html │ ├── Matrix2x2.html │ ├── Matrix3x3.html │ ├── Matrix4x4.html │ └── Quaternion.html ├── index.html ├── interfaces │ └── Matrix.html └── modules.html ├── lib ├── cjs │ ├── float32vector.d.ts │ ├── float32vector.js │ ├── index.d.ts │ ├── index.js │ ├── matrix.d.ts │ ├── matrix.js │ ├── quaternion.d.ts │ ├── quaternion.js │ ├── vector_base.d.ts │ └── vector_base.js └── esm │ ├── float32vector.d.ts │ ├── float32vector.js │ ├── index.d.ts │ ├── index.js │ ├── matrix.d.ts │ ├── matrix.js │ ├── quaternion.d.ts │ ├── quaternion.js │ ├── vector_base.d.ts │ └── vector_base.js ├── package-lock.json ├── package.json ├── src ├── float32vector.ts ├── index.ts ├── matrix.ts ├── quaternion.ts └── vector_base.ts └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | 6 | charset = utf-8 7 | 8 | indent_style = space 9 | indent_size = 2 10 | 11 | trim_trailing_whitespace = true -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: 5 | types: [opened, synchronize, reopened] 6 | 7 | jobs: 8 | test: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - uses: actions/setup-node@v2 13 | with: 14 | node-version: '16' 15 | - run: npm ci 16 | - run: npm run test -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | *~ 3 | .fuse_hidden* 4 | .directory 5 | .Trash-* 6 | .nfs* 7 | .idea 8 | *.iml 9 | out 10 | gen 11 | logs 12 | *.log 13 | npm-debug.log* 14 | yarn-debug.log* 15 | yarn-error.log* 16 | pids 17 | *.pid 18 | *.seed 19 | *.pid.lock 20 | lib-cov 21 | coverage 22 | .nyc_output 23 | .grunt 24 | bower_components 25 | .lock-wscript 26 | build/Release 27 | node_modules/ 28 | jspm_packages/ 29 | typings/ 30 | .npm 31 | .eslintcache 32 | .node_repl_history 33 | *.tgz 34 | .yarn-integrity 35 | .env 36 | .idea 37 | *.iml 38 | out 39 | gen 40 | Thumbs.db 41 | ehthumbs.db 42 | ehthumbs_vista.db 43 | *.stackdump 44 | [Dd]esktop.ini 45 | $RECYCLE.BIN/ 46 | *.cab 47 | *.msi 48 | *.msm 49 | *.msp 50 | *.lnk 51 | .DS_Store 52 | .AppleDouble 53 | .LSOverride 54 | Icon 55 | ._* 56 | .DocumentRevisions-V100 57 | .fseventsd 58 | .Spotlight-V100 59 | .TemporaryItems 60 | .Trashes 61 | .VolumeIcon.icns 62 | .com.apple.timemachine.donotpresent 63 | .AppleDB 64 | .AppleDesktop 65 | Network Trash Folder 66 | Temporary Items 67 | .apdisk 68 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 2.0.0 4 | 5 | * **\[Breaking Change\]** Add ESM support for Node.js. CommonJS is supported too, but this change may break some build system. 6 | * **\[Breaking Change\]** Change compatibility to ES2020 and drop ES5 support for Node.js. 7 | * **\[Breaking Change\]** Change compatibility to ES2020 and drop ES5 support for browsers. 8 | * Change license to Zlib License which is looser than MIT license. Zlib license doesn't require license terms in your code. 9 | 10 | ## 1.0.1 11 | 12 | * Fix v1.0.0 did not apply changes to `matrixgl.min.js` and documents. 13 | 14 | ## 1.0.0 15 | 16 | * **\[Breaking Change\]** Rename `perspective` to `frustum`. 17 | * Add new `Matrix4.perspective()`. 18 | 19 | ## 0.2.0 20 | 21 | * Add `xy` to `Vector3` and `xyz` to `Vector4`, that return the part of the vector. 22 | * Add `rotateAround(axis, radian)` to `Matrix4` and static `Matrix4.rotationAround(axis, radian)`. 23 | * Improve `toString()` of vectors. 24 | 25 | ## 0.1.0 26 | 27 | * Add a Quaternion class. 28 | 29 | ## 0.0.3 30 | 31 | * Fix Vector3.normalize() returns NaN if its magnitude is zero. 32 | 33 | ## 0.0.2 34 | 35 | * orthogonal -> orthographic 36 | 37 | ## 0.0.1 38 | 39 | * Initial release with minimal implementation. -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021 Koto Furumiya 2 | 3 | This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. 4 | 5 | Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 6 | 7 | 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 8 | 9 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 10 | 11 | 3. This notice may not be removed or altered from any source distribution. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MatrixGL 2 | 3 | MatrixGL is yet another matrix library for WebGL. 4 | 5 | ## Install without Node.js 6 | 7 | Download the zip file from [Releases page on GitHub](https://github.com/kotofurumiya/matrixgl/releases), and unzip the file. 8 | 9 | You will see **matrixgl.min.js** file in the **build** directory. Copy the file(matrixgl.min.js) into your directory. You can ignore all other files(These files are for Node.js). 10 | 11 | Then add below code to your HTML file. 12 | 13 | ```html 14 | 15 | 18 | ``` 19 | 20 | ## Install with Node.js 21 | 22 | Run the install command. 23 | 24 | ``` 25 | $ npm install matrixgl 26 | ``` 27 | 28 | Then, import MatrixGL in your script. 29 | 30 | ```typescript 31 | // JavaScript(CommonJS) 32 | const { Vector3, Vector4, Matrix4, Quaternion } = require('matrixgl'); 33 | 34 | // TypeScript or Modern JavaScript(ES Modules) 35 | import { Vector3, Vector4, Matrix4, Quaternion } from 'matrixgl'; 36 | ``` 37 | 38 | ## Basic Usage 39 | 40 | MatrixGL has Vector, Matrix and Quaternion class. 41 | 42 | You can use it simply. For example: 43 | 44 | ```javascript 45 | // create 4-dimensional vector. 46 | const vec = new Vector4(1, 2, 3, 4); 47 | 48 | // display elements. 49 | console.log(vec.x); // 1 50 | console.log(vec.y); // 2 51 | console.log(vec.z); // 3 52 | console.log(vec.w); // 4 53 | 54 | // all values 55 | console.log(vec.values); 56 | ``` 57 | 58 | Vector classes also have some operation. 59 | 60 | ```javascript 61 | const vec1 = new Vector4(1, 2, 3, 4); 62 | const vec2 = new Vector4(5, 6, 7, 8); 63 | const scalar = 5; 64 | 65 | // calculate 66 | const vecSum = vec1.add(vec2); 67 | const vecDiff = vec1.sub(vec2); 68 | const vecProd = vec1.mulByScalar(scalar); 69 | const vecMag = vec1.magnitude; 70 | ``` 71 | 72 | **Note: MatrixGL's API does not modify the original vector/matrix unlike ordinary OpenGL matrix libraries. So you should assign the result to variables** 73 | 74 | There are also Matrix classes. 75 | 76 | ```javascript 77 | const mat = new Matrix2(1, 2, 3, 4); 78 | console.log(mat.values); 79 | ``` 80 | 81 | Matrices' values are stored in "column major order" which is the default order of WebGL. This means `new Matrix(1, 2, 3, 4);` represents the first row is `[1, 3]` and second row is `[2, 4]`. 82 | 83 | If you are bored with enumerating numbers 16 times to create a Matrix4, please use a spread operator. 84 | 85 | ```javascript 86 | const values = new Array(16); 87 | values.fill(0); 88 | 89 | const matrix = new Matrix4(...values); 90 | ``` 91 | 92 | In addition to basic methods, `Matrix4` class has special methods. You can generate a model matrix easily with these methods. 93 | 94 | ```javascript 95 | const model = Matrix4.identity() 96 | .translate(1, 2, 3) 97 | .rotateX(Math.PI) 98 | .scale(5, 5, 5); 99 | ``` 100 | 101 | Or you can build a model matrix manually. 102 | 103 | ```javascript 104 | const identity = Matrix4.identity(); 105 | const scaling = Matrix4.scaling(5, 5, 5); 106 | const rotation = Matrix4.rotationX(Math.PI); 107 | const translation = Matrix4.translation(1, 2, 3); 108 | 109 | const model = identity.mulByMatrix4(translation) 110 | .mulByMatrix4(rotation) 111 | .mulByMatrix4(scaling); 112 | ``` 113 | 114 | If you want a rotation matrix about an arbitrary axis, use `rotateAround(axis, radian)` . 115 | ```javascript 116 | // An axis vector must be normalized. 117 | const axis = new Vector3(1, 2, 3).normalize(); 118 | const rotation = Matrix4.identity() 119 | .rotateAround(axis, Math.PI); 120 | ``` 121 | 122 | or use `Matrix4.rotationAround(axis, radian)`. 123 | 124 | ```javascript 125 | const rotation = Matrix4.rotationAround(axis, Math.PI); 126 | ``` 127 | 128 | To build a "look at" matrix, use `lookAt` method. 129 | 130 | ```javascript 131 | const camera = new Vector3(1, 2, 3); 132 | const lookAt = new Vector3(4, 5, 6); 133 | const cameraUpDirection = new Vector3(7, 8, 9); 134 | 135 | const view = Matrix4.lookAt(camera, lookAt, cameraUpDirection); 136 | ``` 137 | 138 | If you need a projection matrix, use `Matrix4.orthographic` or `Matrix4.perspective` method. 139 | 140 | ```javascript 141 | const orthographic = Matrix4.orthographic({ 142 | top: 1, 143 | bottom: -1, 144 | left: -1, 145 | right: 1, 146 | near: 1, 147 | far: 2 148 | }); 149 | 150 | const perspective = Matrix4.perspective({ 151 | fovYRadian: 60 * Math.PI / 180, 152 | aspectRatio: 1, 153 | near: 1, 154 | far: 2 155 | }); 156 | ``` 157 | 158 | And combine all above matrices to build a ModelViewProjection matrix. 159 | 160 | ```javascript 161 | const mvp = perspective.mulByMatrix4(view) 162 | .mulByMatrix4(model); 163 | ``` 164 | 165 | ## Quaternion 166 | 167 | MatrixGL supports quaternions for rotation. 168 | 169 | ```javascript 170 | // Create a quaternion. 171 | const q = new Quaternion(1, 2, 3, 4); 172 | ``` 173 | 174 | To create a rotation matrix from a quaternion, use `Quaternion.rotationAround(axis, rad)` and `toRotationMatrix4()`. 175 | 176 | ```javascript 177 | // An axis must be normalized. 178 | const axis = new Vector3(1, 2, 3).normalize(); 179 | const radian = 45 * Math.PI / 180; 180 | 181 | // Create a quaternion from the axis and radian. 182 | const q = Quaternion.rotationAround(axis, radian); 183 | 184 | // Convert the rotation quaternion to a rotation matrix. 185 | const rotation = q.toRotationMatrix4(); 186 | ``` 187 | 188 | To interpolate between two quaternions, use `slerp(other, t)`. 189 | 190 | ```javascript 191 | // To interpolate quaternions, they must be normalized. 192 | const q1 = new Quaternion(1, 2, 3, 4).normalize(); 193 | const q2 = new Quaternion(5, 6, 7, 8).normalize(); 194 | 195 | // interpolate with t = 0.5. 196 | // t is from 0.0 to 1.0. 197 | const interpolated = q1.slerp(q2, 0.5); 198 | ``` 199 | 200 | ## Usage with WebGL 201 | 202 | You can get `Float32Array` from `values` property of vectors, matrices or quaternions. 203 | 204 | So if you use MatrixGL with WebGL, just pass the vector's(or matrix's) `values`. 205 | 206 | ```javascript 207 | // Buffer 208 | gl.bufferData(gl.ARRAY_BUFFER, vec1.values, gl.STATIC_DRAW); 209 | 210 | // Uniform Variable 211 | gl.uniformMatrix4fv(mvpLocation, false, mvp.values); 212 | ``` 213 | 214 | ## API Document 215 | 216 | For more information, see also [API Document](https://kotofurumiya.github.io/matrixgl). 217 | 218 | ## How to Build from Source 219 | 220 | Install dependencies. 221 | 222 | ``` 223 | $ npm install 224 | ``` 225 | 226 | Build. 227 | 228 | ``` 229 | $ npm run build 230 | ``` 231 | 232 | ## License 233 | 234 | Zlib License. See [LICENSE.md](https://github.com/kotofurumiya/matrixgl/blob/master/LICENSE.md). -------------------------------------------------------------------------------- /__tests__/browser/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | matrixgl Test 6 | 7 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /__tests__/float32vector.test.ts: -------------------------------------------------------------------------------- 1 | import { suite } from 'uvu'; 2 | import { Vector2, Vector3, Vector4 } from '../'; 3 | import { toBeCloseTo, arrayToBeCloseTo } from './lib/close_to'; 4 | 5 | const Vector2Suite = suite('Vector2'); 6 | const Vector3Suite = suite('Vector3'); 7 | const Vector4Suite = suite('Vector4'); 8 | const delta = 0.001; 9 | 10 | // 11 | // Vector2 12 | // 13 | Vector2Suite('Add Vector2', () => { 14 | const vec1 = new Vector2(1, 2); 15 | const vec2 = new Vector2(3, 4); 16 | 17 | arrayToBeCloseTo(vec1.add(vec2).values, [4, 6], delta); 18 | }); 19 | 20 | Vector2Suite('Sub Vector2', () => { 21 | const vec1 = new Vector2(1, 2); 22 | const vec2 = new Vector2(3, 4); 23 | 24 | arrayToBeCloseTo(vec1.sub(vec2).values, [-2, -2], delta); 25 | }); 26 | 27 | Vector2Suite('Mul Vector2', () => { 28 | const vec1 = new Vector2(1, 2); 29 | 30 | arrayToBeCloseTo(vec1.mulByScalar(5).values, [5, 10], delta); 31 | }); 32 | 33 | // 34 | // Vector3 35 | // 36 | Vector3Suite('Add Vector3', () => { 37 | const vec1 = new Vector3(1, 2, 3); 38 | const vec2 = new Vector3(4, 5, 6); 39 | 40 | arrayToBeCloseTo(vec1.add(vec2).values, [5, 7, 9], delta); 41 | }); 42 | 43 | Vector3Suite('Sub Vector3', () => { 44 | const vec1 = new Vector3(1, 2, 3); 45 | const vec2 = new Vector3(4, 5, 6); 46 | 47 | arrayToBeCloseTo(vec1.sub(vec2).values, [-3, -3, -3], delta); 48 | }); 49 | 50 | Vector3Suite('Mul Vector3', () => { 51 | const vec1 = new Vector3(1, 2, 3); 52 | 53 | arrayToBeCloseTo(vec1.mulByScalar(5).values, [5, 10, 15], delta); 54 | }); 55 | 56 | Vector3Suite('Dot Vector3', () => { 57 | const vec1 = new Vector3(1, 2, 3); 58 | const vec2 = new Vector3(4, 5, 6); 59 | 60 | toBeCloseTo(vec1.dot(vec2), 32, delta); 61 | }); 62 | 63 | Vector3Suite('Cross Vector3', () => { 64 | const vec1 = new Vector3(1, 2, 3); 65 | const vec2 = new Vector3(4, 5, 6); 66 | 67 | arrayToBeCloseTo(vec1.cross(vec2).values, [-3, 6, -3], delta); 68 | }); 69 | 70 | Vector3Suite('Magnitude of Vector3', () => { 71 | const vec = new Vector3(1.23 , 4.56, 7.89); 72 | 73 | toBeCloseTo(vec.magnitude, 9.19558, delta); 74 | }); 75 | 76 | Vector3Suite('Normal Vector3', () => { 77 | const vec = new Vector3(1.05, 3.47, 7.43); 78 | arrayToBeCloseTo(vec.normalize().values, [0.127006, 0.419726, 0.898721], delta); 79 | }); 80 | 81 | Vector3Suite('Normal Zero Vector3', () => { 82 | const vec = new Vector3(0.0, 0.0, 0.0); 83 | arrayToBeCloseTo(vec.normalize().values, [0.0, 0.0, 0.0], delta); 84 | }); 85 | 86 | Vector3Suite('Get xy', () => { 87 | const vec = new Vector3(1, 2, 3); 88 | arrayToBeCloseTo(vec.xy.values, [1, 2], delta); 89 | }); 90 | 91 | // 92 | // Vector4 93 | // 94 | Vector4Suite('Add Vector4', () => { 95 | const vec1 = new Vector4(1, 2, 3, 4); 96 | const vec2 = new Vector4(5, 6, 7, 8); 97 | 98 | arrayToBeCloseTo(vec1.add(vec2).values, [6, 8, 10, 12], delta); 99 | }); 100 | 101 | Vector4Suite('Sub Vector4', () => { 102 | const vec1 = new Vector4(1, 2, 3, 4); 103 | const vec2 = new Vector4(5, 6, 7, 8); 104 | 105 | arrayToBeCloseTo(vec1.sub(vec2).values, [-4, -4, -4, -4], delta); 106 | }); 107 | 108 | Vector4Suite('Mul Vector4', () => { 109 | const vec1 = new Vector4(1, 2, 3, 4); 110 | 111 | arrayToBeCloseTo(vec1.mulByScalar(5).values, [5, 10, 15, 20], delta); 112 | }); 113 | 114 | Vector4Suite('Get xyz', () => { 115 | const vec = new Vector4(1, 2, 3, 4); 116 | arrayToBeCloseTo(vec.xyz.values, [1, 2, 3], delta); 117 | }); 118 | 119 | Vector2Suite.run(); 120 | Vector3Suite.run(); 121 | Vector4Suite.run(); -------------------------------------------------------------------------------- /__tests__/lib/close_to.ts: -------------------------------------------------------------------------------- 1 | import { Assertion } from "uvu/assert"; 2 | import { compare } from 'uvu/diff'; 3 | 4 | export const toBeCloseTo = (actual: number, expected: number, delta: number) => { 5 | const diff = Math.abs(actual - expected); 6 | if(diff > delta) { 7 | throw new Assertion({ 8 | message: `unacceptable diff with delta=${delta}`, 9 | operator: 'toBeCloseTo', 10 | details: compare(actual, expected), 11 | expects: expected, 12 | actual 13 | }); 14 | } 15 | } 16 | 17 | export const arrayToBeCloseTo = (actual: ArrayLike, expected: ArrayLike, delta: number) => { 18 | if(actual.length !== expected.length) { 19 | throw new Assertion({ 20 | message: 'incompatible length', 21 | operator: 'arrayToBeCloseTo', 22 | details: compare(actual.length, expected.length), 23 | expects: expected, 24 | actual 25 | }); 26 | } 27 | 28 | type Difference = { 29 | index: number, 30 | diff: number 31 | }; 32 | const differenceList: Difference[] = []; 33 | for(let i=0; i delta) { 36 | differenceList.push({ 37 | index: i, 38 | diff 39 | }); 40 | } 41 | } 42 | 43 | if(differenceList.length > 0) { 44 | throw new Assertion({ 45 | message: `unacceptable diffs with delta=${delta}`, 46 | operator: 'arrayCloseTo', 47 | details: compare(differenceList, []), 48 | expects: expected, 49 | actual 50 | }); 51 | } 52 | }; 53 | -------------------------------------------------------------------------------- /__tests__/matrix.test.ts: -------------------------------------------------------------------------------- 1 | import { suite } from 'uvu'; 2 | import { Matrix4, Vector3 } from '../'; 3 | import { arrayToBeCloseTo } from './lib/close_to'; 4 | 5 | const Matrix4Suite = suite('Matrix4'); 6 | const delta = 0.001; 7 | 8 | // 9 | // Matrix4 10 | // 11 | Matrix4Suite('Model Matrix', () => { 12 | const model = Matrix4.identity() 13 | .translate(40, 0, -20) 14 | .rotateZ(Math.PI / 8) 15 | .scale(1, 2,3) 16 | 17 | arrayToBeCloseTo(model.values, [ 18 | 0.9238795042037964,0.3826834261417389,0,0, 19 | -0.7653668522834778,1.8477590084075928,0,0, 20 | 0,0,3,0, 21 | 40,0,-20,1 22 | ], delta); 23 | }); 24 | 25 | Matrix4Suite('View Matrix', () => { 26 | const cameraPosition = new Vector3(0, 60, 90); 27 | const lookAtPosition = new Vector3(0, 0, 0); 28 | const upDirection = new Vector3(0, 1, 0); 29 | const view = Matrix4.lookAt(cameraPosition, lookAtPosition, upDirection); 30 | 31 | arrayToBeCloseTo(view.values, [ 32 | 1,0,0,0, 33 | 0,0.8320503234863281,0.5547001957893372,0, 34 | 0,-0.5547001957893372,0.8320503234863281,0, 35 | 0,0,-108.16654205322266,1 36 | ], delta); 37 | }); 38 | 39 | Matrix4Suite('Projection Matrix Orthographic', () => { 40 | const left = -40; 41 | const right = 40; 42 | const top = 40; 43 | const bottom = -40; 44 | const near = 30; 45 | const far = 150; 46 | const projection = Matrix4.orthographic({ top, right, left, bottom, near, far }); 47 | 48 | arrayToBeCloseTo(projection.values, [ 49 | 0.02500000037252903,0,0,0, 50 | 0,0.02500000037252903,0, 51 | 0,0,0,-0.01666666753590107, 52 | 0,0,0,-1.5,1 53 | ], delta); 54 | }); 55 | 56 | Matrix4Suite('Projection Matrix Frustum', () => { 57 | const left = -40; 58 | const right = 40; 59 | const top = 40; 60 | const bottom = -40; 61 | const near = 30; 62 | const far = 150; 63 | const frustum = Matrix4.frustum({ top, right, left, bottom, near, far }); 64 | 65 | arrayToBeCloseTo(frustum.values, [ 66 | 0.75,0,0,0, 67 | 0,0.75,0,0, 68 | 0,0,-1.5,-1, 69 | 0,0,-75,0 70 | ], delta); 71 | }); 72 | 73 | Matrix4Suite('Projection Matrix Perspective', () => { 74 | const fovY = 60 * Math.PI / 180; 75 | const aspectRatio = 500 / 500; 76 | const near = 30; 77 | const far = 300; 78 | const projection = Matrix4.perspective({ fovYRadian: fovY, aspectRatio, near, far }); 79 | 80 | arrayToBeCloseTo(projection.values, [ 81 | 1.7320507764816284,0,0,0, 82 | 0,1.7320507764816284,0,0, 83 | 0,0,-1.2222222089767456,-1, 84 | 0,0,-66.66666412353516,0 85 | ], delta); 86 | }); 87 | 88 | Matrix4Suite.run(); -------------------------------------------------------------------------------- /__tests__/quaternion.test.ts: -------------------------------------------------------------------------------- 1 | import { suite } from 'uvu'; 2 | import { Quaternion, Vector3 } from '../'; 3 | import { arrayToBeCloseTo } from './lib/close_to'; 4 | 5 | const QuaternionSuite = suite('Matrix4'); 6 | const delta = 0.001; 7 | 8 | QuaternionSuite('toRotationMatrix4', () => { 9 | const axis = new Vector3(1, 2, 3).normalize(); 10 | const rad = 45.6 * Math.PI / 180; 11 | const quaternion = Quaternion.rotationAround(axis, rad); 12 | const rotationMatrix = quaternion.toRotationMatrix4(); 13 | const expected = [ 14 | 0.7211159467697144, 0.6157578229904175, -0.3175438642501831, 0, 15 | -0.5299473404884338, 0.7854738235473633, 0.3196665644645691, 0, 16 | 0.4462595582008362, -0.062235139310359955, 0.8927369117736816, 0, 17 | 0, 0, 0, 1 18 | ]; 19 | 20 | arrayToBeCloseTo(rotationMatrix.values, expected, delta); 21 | }); 22 | 23 | QuaternionSuite('normalize', () => { 24 | const normalized = new Quaternion(1, 2, 3, 4).normalize(); 25 | const expected = [0.18257418583505536, 0.3651483716701107, 0.5477225575051661, 0.7302967433402214]; 26 | 27 | arrayToBeCloseTo(normalized.values, expected, delta); 28 | }); 29 | 30 | QuaternionSuite('normalize with zero norm', () => { 31 | const normalized = new Quaternion(0, 0, 0, 0).normalize(); 32 | arrayToBeCloseTo(normalized.values, [0, 0, 0, 0], delta); 33 | }); 34 | 35 | QuaternionSuite('slerp', () => { 36 | const q1 = new Quaternion(1, 2, 3, 4).normalize(); 37 | const q2 = new Quaternion(5, 6, 7, 8).normalize(); 38 | const s = q1.slerp(q2, 0.123); 39 | const expected = [0.20761071976221868, 0.37753696937382647, 0.5474632189854343, 0.717389468597042]; 40 | 41 | arrayToBeCloseTo(s.values, expected, delta); 42 | }); 43 | 44 | QuaternionSuite.run(); -------------------------------------------------------------------------------- /build/matrixgl.min.js: -------------------------------------------------------------------------------- 1 | (()=>{var U=class{get values(){return this._values}get magnitude(){let t=0;for(let r of this._values)t+=r**2;return Math.sqrt(t)}toString(){return`Vector${this._values.length}(${this._values.join(", ")})`}},C=class extends U{get x(){return this._values[0]}get y(){return this._values[1]}set x(t){this._values[0]=t}set y(t){this._values[1]=t}},D=class extends U{get x(){return this._values[0]}get y(){return this._values[1]}get z(){return this._values[2]}set x(t){this._values[0]=t}set y(t){this._values[1]=t}set z(t){this._values[2]=t}},E=class extends U{get x(){return this._values[0]}get y(){return this._values[1]}get z(){return this._values[2]}get w(){return this._values[3]}set x(t){this._values[0]=t}set y(t){this._values[1]=t}set z(t){this._values[2]=t}set w(t){this._values[3]=t}};var d=class extends C{constructor(t,r){super();this._values=new Float32Array([t,r])}add(t){return new d(this.x+t.x,this.y+t.y)}sub(t){return new d(this.x-t.x,this.y-t.y)}mulByScalar(t){return new d(this.x*t,this.y*t)}},c=class extends D{constructor(t,r,e){super();this._values=new Float32Array([t,r,e])}add(t){return new c(this.x+t.x,this.y+t.y,this.z+t.z)}sub(t){return new c(this.x-t.x,this.y-t.y,this.z-t.z)}mulByScalar(t){return new c(this.x*t,this.y*t,this.z*t)}dot(t){return this.x*t.x+this.y*t.y+this.z*t.z}cross(t){let r=this.y*t.z-this.z*t.y,e=this.z*t.x-this.x*t.z,n=this.x*t.y-this.y*t.x;return new c(r,e,n)}normalize(){let t=this.magnitude;return t===0?this:new c(this.x/t,this.y/t,this.z/t)}get xy(){return new d(this.x,this.y)}},F=class extends E{constructor(t,r,e,n){super();this._values=new Float32Array([t,r,e,n])}add(t){return new F(this.x+t.x,this.y+t.y,this.z+t.z,this.w+t.w)}sub(t){return new F(this.x-t.x,this.y-t.y,this.z-t.z,this.w-t.w)}mulByScalar(t){return new F(this.x*t,this.y*t,this.z*t,this.w*t)}get xyz(){return new c(this.x,this.y,this.z)}},mt=d,ct=c,lt=F;var w=class{constructor(t,r,e,n){this._values=new Float32Array([t,r,e,n])}static rotationAround(t,r){let e=Math.sin(r/2),n=Math.cos(r/2);return new w(t.x*e,t.y*e,t.z*e,n)}normalize(){let t=this.magnitude;if(t===0)return this;let r=1/t;return new w(this.x*r,this.y*r,this.z*r,this.w*r)}add(t){return new w(this.x+t.x,this.y+t.y,this.z+t.z,this.w+t.w)}mulByScalar(t){return new w(this.x*t,this.y*t,this.z*t,this.w*t)}dot(t){return this.x*t.x+this.y*t.y+this.z*t.z+this.w*t.w}slerp(t,r,e={chooseShorterAngle:!0}){let n=this.dot(t),u=t;n<0&&(n=-n,u=t.mulByScalar(-1));let s=Math.acos(n),o=Math.sin(s),i=this.mulByScalar(Math.sin((1-r)*s)/o),m=u.mulByScalar(Math.sin(r*s)/o);return i.add(m)}get magnitude(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w)}get norm(){return this.magnitude}get x(){return this._values[0]}get y(){return this._values[1]}get z(){return this._values[2]}get w(){return this._values[3]}set x(t){this._values[0]=t}set y(t){this._values[1]=t}set z(t){this._values[2]=t}set w(t){this._values[3]=t}get values(){return this._values}toRotationMatrix4(){let t=this.x,r=this.y,e=this.z,n=this.w,u=1-2*r*r-2*e*e,s=2*t*r-2*n*e,o=2*t*e+2*n*r,i=0,m=2*t*r+2*n*e,l=1-2*t*t-2*e*e,b=2*r*e-2*n*t,h=0,x=2*t*e-2*n*r,y=2*r*e+2*n*t,v=1-2*t*t-2*r*r,p=0,g=0,z=0,M=0,A=1;return new a(u,m,x,g,s,l,y,z,o,b,v,M,i,h,p,A)}toString(){return`Quaternion(${this.x}, ${this.y}, ${this.z}, ${this.w})`}};var I=class{constructor(t,r,e,n){this._values=new Float32Array([t,r,e,n])}static identity(){return new I(1,0,0,1)}get values(){return this._values}toString(){return this._values.toString()}},X=class{constructor(t,r,e,n,u,s,o,i,m){this._values=new Float32Array([t,r,e,n,u,s,o,i,m])}static identity(){return new X(1,0,0,0,1,0,0,0,1)}get values(){return this._values}toString(){return this._values.toString()}},a=class{constructor(t,r,e,n,u,s,o,i,m,l,b,h,x,y,v,p){this._values=new Float32Array([t,r,e,n,u,s,o,i,m,l,b,h,x,y,v,p])}static identity(){return new a(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1)}static translation(t,r,e){return new a(1,0,0,0,0,1,0,0,0,0,1,0,t,r,e,1)}static scaling(t,r,e){return new a(t,0,0,0,0,r,0,0,0,0,e,0,0,0,0,1)}static rotationX(t){let r=Math.sin(t),e=Math.cos(t);return new a(1,0,0,0,0,e,r,0,0,-r,e,0,0,0,0,1)}static rotationY(t){let r=Math.sin(t),e=Math.cos(t);return new a(e,0,-r,0,0,1,0,0,r,0,e,0,0,0,0,1)}static rotationZ(t){let r=Math.sin(t),e=Math.cos(t);return new a(e,r,0,0,-r,e,0,0,0,0,1,0,0,0,0,1)}static rotationAround(t,r){return w.rotationAround(t,r).toRotationMatrix4()}static lookAt(t,r,e){let n=t.sub(r).normalize(),u=e.cross(n).normalize(),s=n.cross(u).normalize();return new a(u.x,s.x,n.x,0,u.y,s.y,n.y,0,u.z,s.z,n.z,0,-t.dot(u),-t.dot(s),-t.dot(n),1)}static orthographic(t){let r=t.top,e=t.bottom,n=t.left,u=t.right,s=t.near,o=t.far;return new a(2/(u-n),0,0,0,0,2/(r-e),0,0,0,0,-2/(o-s),0,-(u+n)/(u-n),-(r+e)/(r-e),-(o+s)/(o-s),1)}static frustum(t){let r=t.top,e=t.bottom,n=t.left,u=t.right,s=t.near,o=t.far;return new a(2*s/(u-n),0,0,0,0,2*s/(r-e),0,0,(u+n)/(u-n),(r+e)/(r-e),-(o+s)/(o-s),-1,0,0,-2*o*s/(o-s),0)}static perspective(t){let r=t.near*Math.tan(t.fovYRadian*.5),e=r*2,n=t.aspectRatio*e,u=-.5*n,s=u+n,o=r-e;return a.frustum({top:r,bottom:o,left:u,right:s,near:t.near,far:t.far})}mulByMatrix4x4(t){let r=this._values[0],e=this._values[4],n=this._values[8],u=this._values[12],s=this._values[1],o=this._values[5],i=this._values[9],m=this._values[13],l=this._values[2],b=this._values[6],h=this._values[10],x=this._values[14],y=this._values[3],v=this._values[7],p=this._values[11],g=this._values[15],z=t.values[0],M=t.values[4],A=t.values[8],f=t.values[12],_=t.values[1],V=t.values[5],S=t.values[9],B=t.values[13],T=t.values[2],Q=t.values[6],q=t.values[10],k=t.values[14],L=t.values[3],R=t.values[7],$=t.values[11],Y=t.values[15],G=r*z+e*_+n*T+u*L,H=r*M+e*V+n*Q+u*R,J=r*A+e*S+n*q+u*$,K=r*f+e*B+n*k+u*Y,N=s*z+o*_+i*T+m*L,W=s*M+o*V+i*Q+m*R,P=s*A+o*S+i*q+m*$,j=s*f+o*B+i*k+m*Y,O=l*z+b*_+h*T+x*L,tt=l*M+b*V+h*Q+x*R,rt=l*A+b*S+h*q+x*$,et=l*f+b*B+h*k+x*Y,nt=y*z+v*_+p*T+g*L,st=y*M+v*V+p*Q+g*R,ut=y*A+v*S+p*q+g*$,ot=y*f+v*B+p*k+g*Y;return new a(G,N,O,nt,H,W,tt,st,J,P,rt,ut,K,j,et,ot)}mulByMatrix4(t){return this.mulByMatrix4x4(t)}translate(t,r,e){let n=a.translation(t,r,e);return this.mulByMatrix4x4(n)}scale(t,r,e){let n=a.scaling(t,r,e);return this.mulByMatrix4x4(n)}rotateX(t){let r=a.rotationX(t);return this.mulByMatrix4x4(r)}rotateY(t){let r=a.rotationY(t);return this.mulByMatrix4x4(r)}rotateZ(t){let r=a.rotationZ(t);return this.mulByMatrix4x4(r)}rotateAround(t,r){let e=a.rotationAround(t,r);return this.mulByMatrix4x4(e)}get values(){return this._values}toString(){return this._values.toString()}},vt=I,pt=X,wt=a;})(); 2 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- 1 | TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. -------------------------------------------------------------------------------- /docs/assets/highlight.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --light-hl-0: #800000; 3 | --dark-hl-0: #808080; 4 | --light-hl-1: #800000; 5 | --dark-hl-1: #569CD6; 6 | --light-hl-2: #000000FF; 7 | --dark-hl-2: #D4D4D4; 8 | --light-hl-3: #FF0000; 9 | --dark-hl-3: #9CDCFE; 10 | --light-hl-4: #0000FF; 11 | --dark-hl-4: #CE9178; 12 | --light-hl-5: #008000; 13 | --dark-hl-5: #6A9955; 14 | --light-hl-6: #001080; 15 | --dark-hl-6: #9CDCFE; 16 | --light-hl-7: #000000; 17 | --dark-hl-7: #D4D4D4; 18 | --light-hl-8: #0000FF; 19 | --dark-hl-8: #569CD6; 20 | --light-hl-9: #0070C1; 21 | --dark-hl-9: #4FC1FF; 22 | --light-hl-10: #795E26; 23 | --dark-hl-10: #DCDCAA; 24 | --light-hl-11: #A31515; 25 | --dark-hl-11: #CE9178; 26 | --light-hl-12: #AF00DB; 27 | --dark-hl-12: #C586C0; 28 | --light-hl-13: #098658; 29 | --dark-hl-13: #B5CEA8; 30 | --light-hl-14: #267F99; 31 | --dark-hl-14: #4EC9B0; 32 | --light-code-background: #FFFFFF; 33 | --dark-code-background: #1E1E1E; 34 | } 35 | 36 | @media (prefers-color-scheme: light) { :root { 37 | --hl-0: var(--light-hl-0); 38 | --hl-1: var(--light-hl-1); 39 | --hl-2: var(--light-hl-2); 40 | --hl-3: var(--light-hl-3); 41 | --hl-4: var(--light-hl-4); 42 | --hl-5: var(--light-hl-5); 43 | --hl-6: var(--light-hl-6); 44 | --hl-7: var(--light-hl-7); 45 | --hl-8: var(--light-hl-8); 46 | --hl-9: var(--light-hl-9); 47 | --hl-10: var(--light-hl-10); 48 | --hl-11: var(--light-hl-11); 49 | --hl-12: var(--light-hl-12); 50 | --hl-13: var(--light-hl-13); 51 | --hl-14: var(--light-hl-14); 52 | --code-background: var(--light-code-background); 53 | } } 54 | 55 | @media (prefers-color-scheme: dark) { :root { 56 | --hl-0: var(--dark-hl-0); 57 | --hl-1: var(--dark-hl-1); 58 | --hl-2: var(--dark-hl-2); 59 | --hl-3: var(--dark-hl-3); 60 | --hl-4: var(--dark-hl-4); 61 | --hl-5: var(--dark-hl-5); 62 | --hl-6: var(--dark-hl-6); 63 | --hl-7: var(--dark-hl-7); 64 | --hl-8: var(--dark-hl-8); 65 | --hl-9: var(--dark-hl-9); 66 | --hl-10: var(--dark-hl-10); 67 | --hl-11: var(--dark-hl-11); 68 | --hl-12: var(--dark-hl-12); 69 | --hl-13: var(--dark-hl-13); 70 | --hl-14: var(--dark-hl-14); 71 | --code-background: var(--dark-code-background); 72 | } } 73 | 74 | body.light { 75 | --hl-0: var(--light-hl-0); 76 | --hl-1: var(--light-hl-1); 77 | --hl-2: var(--light-hl-2); 78 | --hl-3: var(--light-hl-3); 79 | --hl-4: var(--light-hl-4); 80 | --hl-5: var(--light-hl-5); 81 | --hl-6: var(--light-hl-6); 82 | --hl-7: var(--light-hl-7); 83 | --hl-8: var(--light-hl-8); 84 | --hl-9: var(--light-hl-9); 85 | --hl-10: var(--light-hl-10); 86 | --hl-11: var(--light-hl-11); 87 | --hl-12: var(--light-hl-12); 88 | --hl-13: var(--light-hl-13); 89 | --hl-14: var(--light-hl-14); 90 | --code-background: var(--light-code-background); 91 | } 92 | 93 | body.dark { 94 | --hl-0: var(--dark-hl-0); 95 | --hl-1: var(--dark-hl-1); 96 | --hl-2: var(--dark-hl-2); 97 | --hl-3: var(--dark-hl-3); 98 | --hl-4: var(--dark-hl-4); 99 | --hl-5: var(--dark-hl-5); 100 | --hl-6: var(--dark-hl-6); 101 | --hl-7: var(--dark-hl-7); 102 | --hl-8: var(--dark-hl-8); 103 | --hl-9: var(--dark-hl-9); 104 | --hl-10: var(--dark-hl-10); 105 | --hl-11: var(--dark-hl-11); 106 | --hl-12: var(--dark-hl-12); 107 | --hl-13: var(--dark-hl-13); 108 | --hl-14: var(--dark-hl-14); 109 | --code-background: var(--dark-code-background); 110 | } 111 | 112 | .hl-0 { color: var(--hl-0); } 113 | .hl-1 { color: var(--hl-1); } 114 | .hl-2 { color: var(--hl-2); } 115 | .hl-3 { color: var(--hl-3); } 116 | .hl-4 { color: var(--hl-4); } 117 | .hl-5 { color: var(--hl-5); } 118 | .hl-6 { color: var(--hl-6); } 119 | .hl-7 { color: var(--hl-7); } 120 | .hl-8 { color: var(--hl-8); } 121 | .hl-9 { color: var(--hl-9); } 122 | .hl-10 { color: var(--hl-10); } 123 | .hl-11 { color: var(--hl-11); } 124 | .hl-12 { color: var(--hl-12); } 125 | .hl-13 { color: var(--hl-13); } 126 | .hl-14 { color: var(--hl-14); } 127 | pre, code { background: var(--code-background); } 128 | -------------------------------------------------------------------------------- /docs/assets/icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kotofurumiya/matrixgl/cba6203ad2d8f5179aa48d457d76a343bc25da91/docs/assets/icons.png -------------------------------------------------------------------------------- /docs/assets/icons@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kotofurumiya/matrixgl/cba6203ad2d8f5179aa48d457d76a343bc25da91/docs/assets/icons@2x.png -------------------------------------------------------------------------------- /docs/assets/widgets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kotofurumiya/matrixgl/cba6203ad2d8f5179aa48d457d76a343bc25da91/docs/assets/widgets.png -------------------------------------------------------------------------------- /docs/assets/widgets@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kotofurumiya/matrixgl/cba6203ad2d8f5179aa48d457d76a343bc25da91/docs/assets/widgets@2x.png -------------------------------------------------------------------------------- /docs/classes/Matrix2x2.html: -------------------------------------------------------------------------------- 1 | Matrix2x2 | matrixgl
Options
All
  • Public
  • Public/Protected
  • All
Menu

Class Matrix2x2

2 |

2x2 Matrix of single-precision float numbers.

3 |

Values are stored in column major order.

4 |

Hierarchy

  • Matrix2x2

Implements

Index

Constructors

Properties

Accessors

Methods

Constructors

constructor

  • new Matrix2x2(m11: number, m21: number, m12: number, m22: number): Matrix2x2

Properties

Protected _values

_values: Float32Array

Accessors

values

  • get values(): Float32Array
  • 5 |

    Values of the matrix, that is stored in column major order.

    6 |

    Returns Float32Array

Methods

toString

  • toString(): string

Static identity

Legend

  • Constructor
  • Method
  • Accessor
  • Property
  • Method
  • Inherited method
  • Inherited accessor
  • Protected property
  • Static method

Settings

Theme

Generated using TypeDoc

-------------------------------------------------------------------------------- /docs/classes/Matrix3x3.html: -------------------------------------------------------------------------------- 1 | Matrix3x3 | matrixgl
Options
All
  • Public
  • Public/Protected
  • All
Menu

Class Matrix3x3

2 |

3x3 Matrix of single-precision float numbers.

3 |

Values are stored in column major order.

4 |

Hierarchy

  • Matrix3x3

Implements

Index

Constructors

Properties

Accessors

Methods

Constructors

constructor

  • new Matrix3x3(m11: number, m21: number, m31: number, m12: number, m22: number, m32: number, m13: number, m23: number, m33: number): Matrix3x3
  • Parameters

    • m11: number
    • m21: number
    • m31: number
    • m12: number
    • m22: number
    • m32: number
    • m13: number
    • m23: number
    • m33: number

    Returns Matrix3x3

Properties

Protected _values

_values: Float32Array

Accessors

values

  • get values(): Float32Array
  • 5 |

    Values of the matrix, that is stored in column major order.

    6 |

    Returns Float32Array

Methods

toString

  • toString(): string

Static identity

Legend

  • Constructor
  • Method
  • Accessor
  • Property
  • Method
  • Inherited method
  • Inherited accessor
  • Protected property
  • Static method

Settings

Theme

Generated using TypeDoc

-------------------------------------------------------------------------------- /docs/interfaces/Matrix.html: -------------------------------------------------------------------------------- 1 | Matrix | matrixgl
Options
All
  • Public
  • Public/Protected
  • All
Menu

Interface Matrix

2 |

An interface for matrices;

3 |

Hierarchy

  • Matrix

Implemented by

Index

Properties

Methods

Properties

Readonly values

values: Float32Array
4 |

Values of the matrix, that is stored in column major order.

5 |

Methods

toString

  • toString(): string
  • 6 |

    Returns values as string.

    7 |

    Returns string

Legend

  • Constructor
  • Method
  • Accessor
  • Property
  • Method
  • Inherited method
  • Inherited accessor
  • Protected property
  • Static method

Settings

Theme

Generated using TypeDoc

-------------------------------------------------------------------------------- /docs/modules.html: -------------------------------------------------------------------------------- 1 | matrixgl
Options
All
  • Public
  • Public/Protected
  • All
Menu

matrixgl

Index

Variables

Matrix2

Matrix2: typeof Matrix2x2 = Matrix2x2
2 |

An alias for Matrix2x2.

3 |

Matrix3

Matrix3: typeof Matrix3x3 = Matrix3x3
4 |

An alias for Matrix3x3.

5 |

Matrix4

Matrix4: typeof Matrix4x4 = Matrix4x4
6 |

An alias for Matrix4x4.

7 |

Vector2

Vector2: typeof Float32Vector2 = Float32Vector2
8 |

An alias for Float32Vector2.

9 |

Vector3

Vector3: typeof Float32Vector3 = Float32Vector3
10 |

An alias for Float32Vector3.

11 |

Vector4

Vector4: typeof Float32Vector4 = Float32Vector4
12 |

An alias for Float32Vector4.

13 |

Legend

  • Constructor
  • Method
  • Accessor
  • Property
  • Method
  • Inherited method
  • Inherited accessor
  • Protected property
  • Static method

Settings

Theme

Generated using TypeDoc

-------------------------------------------------------------------------------- /lib/cjs/float32vector.d.ts: -------------------------------------------------------------------------------- 1 | import { Vector2Base, Vector3Base, Vector4Base } from './vector_base'; 2 | /** 3 | * A 2-dimensional vector of single-precision float numbers. 4 | */ 5 | export declare class Float32Vector2 extends Vector2Base { 6 | constructor(x: number, y: number); 7 | /** 8 | * Add `other` to the vector and returns new `Float32Vector2`. 9 | * 10 | * This method does not mutate the vector. 11 | * @param {Float32Vector2} other 12 | * @returns {Float32Vector2} 13 | */ 14 | add(other: Float32Vector2): Float32Vector2; 15 | /** 16 | * Subtract `other` from the vector and returns new `Float32Vector2`. 17 | * 18 | * This method does not mutate the vector. 19 | * @param {Float32Vector2} other 20 | * @returns {Float32Vector2} 21 | */ 22 | sub(other: Float32Vector2): Float32Vector2; 23 | /** 24 | * Multiply the vector by `scalar` and returns new `Float32Vector2`. 25 | * 26 | * This method does not mutate the vector. 27 | * @param {number} scalar 28 | * @returns {Float32Vector2} 29 | */ 30 | mulByScalar(scalar: number): Float32Vector2; 31 | } 32 | /** 33 | * A 3-dimensional vector of single-precision float numbers. 34 | */ 35 | export declare class Float32Vector3 extends Vector3Base { 36 | constructor(x: number, y: number, z: number); 37 | /** 38 | * Add `other` to the vector and returns new `Float32Vector3`. 39 | * 40 | * This method does not mutate the vector. 41 | * @param {Float32Vector3} other 42 | * @returns {Float32Vector3} 43 | */ 44 | add(other: Float32Vector3): Float32Vector3; 45 | /** 46 | * Subtract `other` from the vector and returns new `Float32Vector3`. 47 | * 48 | * This method does not mutate the vector. 49 | * @param {Float32Vector3} other 50 | * @returns {Float32Vector3} 51 | */ 52 | sub(other: Float32Vector3): Float32Vector3; 53 | /** 54 | * Multiply the vector by `scalar` and returns new `Float32Vector3`. 55 | * 56 | * This method does not mutate the vector. 57 | * @param {number} scalar 58 | * @returns {Float32Vector3} 59 | */ 60 | mulByScalar(scalar: number): Float32Vector3; 61 | /** 62 | * Calculate dot product. 63 | * @param {Float32Vector3} other 64 | * @returns {number} 65 | */ 66 | dot(other: Float32Vector3): number; 67 | /** 68 | * Calculate cross product. 69 | * @param {Float32Vector3} other 70 | * @returns {Float32Vector3} 71 | */ 72 | cross(other: Float32Vector3): Float32Vector3; 73 | /** 74 | * Normalize the vector and returns new `Float32Vector3`. 75 | * 76 | * This method does not mutate the vector. 77 | * @returns {Float32Vector3} 78 | */ 79 | normalize(): Float32Vector3; 80 | /** 81 | * Returns xy values of the vector as `Float32Vector2`. 82 | * @returns {Float32Vector2} 83 | */ 84 | get xy(): Float32Vector2; 85 | } 86 | /** 87 | * A 4-dimensional vector of single-precision float numbers. 88 | */ 89 | export declare class Float32Vector4 extends Vector4Base { 90 | constructor(x: number, y: number, z: number, w: number); 91 | /** 92 | * Add `other` to the vector and returns new `Float32Vector4`. 93 | * 94 | * This method does not mutate the vector. 95 | * @param {Float32Vector4} other 96 | * @returns {Float32Vector4} 97 | */ 98 | add(other: Float32Vector4): Float32Vector4; 99 | /** 100 | * Subtract `other` from the vector and returns new `Float32Vector4`. 101 | * 102 | * This method does not mutate the vector. 103 | * @param {Float32Vector4} other 104 | * @returns {Float32Vector4} 105 | */ 106 | sub(other: Float32Vector4): Float32Vector4; 107 | /** 108 | * Multiply the vector by `scalar` and returns new `Float32Vector4`. 109 | * 110 | * This method does not mutate the vector. 111 | * @param {number} scalar 112 | * @returns {Float32Vector4} 113 | */ 114 | mulByScalar(scalar: number): Float32Vector4; 115 | /** 116 | * Returns xyz values of the vector as `Float32Vector3`. 117 | * @returns {Float32Vector3} 118 | */ 119 | get xyz(): Float32Vector3; 120 | } 121 | /** 122 | * An alias for `Float32Vector2`. 123 | * @type {Float32Vector2} 124 | */ 125 | export declare const Vector2: typeof Float32Vector2; 126 | /** 127 | * An alias for `Float32Vector3`. 128 | * @type {Float32Vector3} 129 | */ 130 | export declare const Vector3: typeof Float32Vector3; 131 | /** 132 | * An alias for `Float32Vector4`. 133 | * @type {Float32Vector4} 134 | */ 135 | export declare const Vector4: typeof Float32Vector4; 136 | -------------------------------------------------------------------------------- /lib/cjs/float32vector.js: -------------------------------------------------------------------------------- 1 | var __defProp = Object.defineProperty; 2 | var __markAsModule = (target) => __defProp(target, "__esModule", { value: true }); 3 | var __export = (target, all) => { 4 | __markAsModule(target); 5 | for (var name in all) 6 | __defProp(target, name, { get: all[name], enumerable: true }); 7 | }; 8 | 9 | // src/float32vector.ts 10 | __export(exports, { 11 | Float32Vector2: () => Float32Vector2, 12 | Float32Vector3: () => Float32Vector3, 13 | Float32Vector4: () => Float32Vector4, 14 | Vector2: () => Vector2, 15 | Vector3: () => Vector3, 16 | Vector4: () => Vector4 17 | }); 18 | 19 | // src/vector_base.ts 20 | var VectorBase = class { 21 | get values() { 22 | return this._values; 23 | } 24 | get magnitude() { 25 | let sumSq = 0; 26 | for (const val of this._values) { 27 | sumSq += val ** 2; 28 | } 29 | return Math.sqrt(sumSq); 30 | } 31 | toString() { 32 | const dimension = this._values.length; 33 | return `Vector${dimension}(${this._values.join(", ")})`; 34 | } 35 | }; 36 | var Vector2Base = class extends VectorBase { 37 | get x() { 38 | return this._values[0]; 39 | } 40 | get y() { 41 | return this._values[1]; 42 | } 43 | set x(value) { 44 | this._values[0] = value; 45 | } 46 | set y(value) { 47 | this._values[1] = value; 48 | } 49 | }; 50 | var Vector3Base = class extends VectorBase { 51 | get x() { 52 | return this._values[0]; 53 | } 54 | get y() { 55 | return this._values[1]; 56 | } 57 | get z() { 58 | return this._values[2]; 59 | } 60 | set x(value) { 61 | this._values[0] = value; 62 | } 63 | set y(value) { 64 | this._values[1] = value; 65 | } 66 | set z(value) { 67 | this._values[2] = value; 68 | } 69 | }; 70 | var Vector4Base = class extends VectorBase { 71 | get x() { 72 | return this._values[0]; 73 | } 74 | get y() { 75 | return this._values[1]; 76 | } 77 | get z() { 78 | return this._values[2]; 79 | } 80 | get w() { 81 | return this._values[3]; 82 | } 83 | set x(value) { 84 | this._values[0] = value; 85 | } 86 | set y(value) { 87 | this._values[1] = value; 88 | } 89 | set z(value) { 90 | this._values[2] = value; 91 | } 92 | set w(value) { 93 | this._values[3] = value; 94 | } 95 | }; 96 | 97 | // src/float32vector.ts 98 | var Float32Vector2 = class extends Vector2Base { 99 | constructor(x, y) { 100 | super(); 101 | this._values = new Float32Array([x, y]); 102 | } 103 | add(other) { 104 | return new Float32Vector2(this.x + other.x, this.y + other.y); 105 | } 106 | sub(other) { 107 | return new Float32Vector2(this.x - other.x, this.y - other.y); 108 | } 109 | mulByScalar(scalar) { 110 | return new Float32Vector2(this.x * scalar, this.y * scalar); 111 | } 112 | }; 113 | var Float32Vector3 = class extends Vector3Base { 114 | constructor(x, y, z) { 115 | super(); 116 | this._values = new Float32Array([x, y, z]); 117 | } 118 | add(other) { 119 | return new Float32Vector3(this.x + other.x, this.y + other.y, this.z + other.z); 120 | } 121 | sub(other) { 122 | return new Float32Vector3(this.x - other.x, this.y - other.y, this.z - other.z); 123 | } 124 | mulByScalar(scalar) { 125 | return new Float32Vector3(this.x * scalar, this.y * scalar, this.z * scalar); 126 | } 127 | dot(other) { 128 | return this.x * other.x + this.y * other.y + this.z * other.z; 129 | } 130 | cross(other) { 131 | const cx = this.y * other.z - this.z * other.y; 132 | const cy = this.z * other.x - this.x * other.z; 133 | const cz = this.x * other.y - this.y * other.x; 134 | return new Float32Vector3(cx, cy, cz); 135 | } 136 | normalize() { 137 | const mag = this.magnitude; 138 | if (mag === 0) { 139 | return this; 140 | } 141 | return new Float32Vector3(this.x / mag, this.y / mag, this.z / mag); 142 | } 143 | get xy() { 144 | return new Float32Vector2(this.x, this.y); 145 | } 146 | }; 147 | var Float32Vector4 = class extends Vector4Base { 148 | constructor(x, y, z, w) { 149 | super(); 150 | this._values = new Float32Array([x, y, z, w]); 151 | } 152 | add(other) { 153 | return new Float32Vector4(this.x + other.x, this.y + other.y, this.z + other.z, this.w + other.w); 154 | } 155 | sub(other) { 156 | return new Float32Vector4(this.x - other.x, this.y - other.y, this.z - other.z, this.w - other.w); 157 | } 158 | mulByScalar(scalar) { 159 | return new Float32Vector4(this.x * scalar, this.y * scalar, this.z * scalar, this.w * scalar); 160 | } 161 | get xyz() { 162 | return new Float32Vector3(this.x, this.y, this.z); 163 | } 164 | }; 165 | var Vector2 = Float32Vector2; 166 | var Vector3 = Float32Vector3; 167 | var Vector4 = Float32Vector4; 168 | // Annotate the CommonJS export names for ESM import in node: 169 | 0 && (module.exports = { 170 | Float32Vector2, 171 | Float32Vector3, 172 | Float32Vector4, 173 | Vector2, 174 | Vector3, 175 | Vector4 176 | }); 177 | -------------------------------------------------------------------------------- /lib/cjs/index.d.ts: -------------------------------------------------------------------------------- 1 | export * from './float32vector'; 2 | export * from './matrix'; 3 | export * from './quaternion'; 4 | -------------------------------------------------------------------------------- /lib/cjs/matrix.d.ts: -------------------------------------------------------------------------------- 1 | import { Float32Vector3 } from './float32vector'; 2 | /** 3 | * An interface for matrices; 4 | */ 5 | export interface Matrix { 6 | /** 7 | * Values of the matrix, that is stored in column major order. 8 | */ 9 | readonly values: Float32Array; 10 | /** 11 | * Returns `values` as string. 12 | * @returns {string} 13 | */ 14 | toString(): string; 15 | } 16 | /** 17 | * 2x2 Matrix of single-precision float numbers. 18 | * 19 | * Values are stored in column major order. 20 | */ 21 | export declare class Matrix2x2 implements Matrix { 22 | protected _values: Float32Array; 23 | constructor(m11: number, m21: number, m12: number, m22: number); 24 | /** 25 | * Returns an identity matrix. 26 | * @returns {Matrix2x2} 27 | */ 28 | static identity(): Matrix2x2; 29 | get values(): Float32Array; 30 | toString(): string; 31 | } 32 | /** 33 | * 3x3 Matrix of single-precision float numbers. 34 | * 35 | * Values are stored in column major order. 36 | */ 37 | export declare class Matrix3x3 implements Matrix { 38 | protected _values: Float32Array; 39 | constructor(m11: number, m21: number, m31: number, m12: number, m22: number, m32: number, m13: number, m23: number, m33: number); 40 | /** 41 | * Returns an identity matrix. 42 | * @returns {Matrix3x3} 43 | */ 44 | static identity(): Matrix3x3; 45 | get values(): Float32Array; 46 | toString(): string; 47 | } 48 | /** 49 | * 4x4 Matrix of single-precision float numbers. 50 | * 51 | * Values are stored in column major order. 52 | */ 53 | export declare class Matrix4x4 implements Matrix { 54 | protected _values: Float32Array; 55 | constructor(m11: number, m21: number, m31: number, m41: number, m12: number, m22: number, m32: number, m42: number, m13: number, m23: number, m33: number, m43: number, m14: number, m24: number, m34: number, m44: number); 56 | /** 57 | * Returns an identity matrix. 58 | * @returns {Matrix4x4} 59 | */ 60 | static identity(): Matrix4x4; 61 | /** 62 | * Returns translation matrix. 63 | * @param {number} tx 64 | * @param {number} ty 65 | * @param {number} tz 66 | * @returns {Matrix4x4} 67 | */ 68 | static translation(tx: number, ty: number, tz: number): Matrix4x4; 69 | /** 70 | * Returns scaling matrix. 71 | * @param {number} sx 72 | * @param {number} sy 73 | * @param {number} sz 74 | * @returns {Matrix4x4} 75 | */ 76 | static scaling(sx: number, sy: number, sz: number): Matrix4x4; 77 | /** 78 | * Returns rotation matrix around x-axis. 79 | * @param {number} radian 80 | * @returns {Matrix4x4} 81 | */ 82 | static rotationX(radian: number): Matrix4x4; 83 | /** 84 | * Returns rotation matrix around y-axis. 85 | * @param {number} radian 86 | * @returns {Matrix4x4} 87 | */ 88 | static rotationY(radian: number): Matrix4x4; 89 | /** 90 | * Returns rotation matrix around z-axis. 91 | * @param {number} radian 92 | * @returns {Matrix4x4} 93 | */ 94 | static rotationZ(radian: number): Matrix4x4; 95 | /** 96 | * Returns rotation matrix around `normalizedAxis`. `normalizedAxis` must be normalized. 97 | * @param {Float32Vector3} normalizedAxis 98 | * @param {number} radian 99 | * @returns {Matrix4x4} 100 | */ 101 | static rotationAround(normalizedAxis: Float32Vector3, radian: number): Matrix4x4; 102 | /** 103 | * Returns "look at" matrix. 104 | * @param {Float32Vector3} cameraPosition 105 | * @param {Float32Vector3} lookAtPosition 106 | * @param {Float32Vector3} cameraUp 107 | * @returns {Matrix4x4} 108 | */ 109 | static lookAt(cameraPosition: Float32Vector3, lookAtPosition: Float32Vector3, cameraUp: Float32Vector3): Matrix4x4; 110 | /** 111 | * Returns an orthographic projection matrix. 112 | * @param {{top: number; bottom: number; left: number; right: number; near: number; far: number}} argsObject 113 | * @returns {Matrix4x4} 114 | */ 115 | static orthographic(argsObject: { 116 | top: number; 117 | bottom: number; 118 | left: number; 119 | right: number; 120 | near: number; 121 | far: number; 122 | }): Matrix4x4; 123 | /** 124 | * Returns a frustrum projection matrix. 125 | * @param {{top: number; bottom: number; left: number; right: number; near: number; far: number}} argsObject 126 | * @returns {Matrix4x4} 127 | */ 128 | static frustum(argsObject: { 129 | top: number; 130 | bottom: number; 131 | left: number; 132 | right: number; 133 | near: number; 134 | far: number; 135 | }): Matrix4x4; 136 | /** 137 | * Returns a perspective projection matrix. 138 | * @param {{fovY: number; aspect: number; near: number; far: number}} argsObject 139 | * @returns {Matrix4x4} 140 | */ 141 | static perspective(argsObject: { 142 | fovYRadian: number; 143 | aspectRatio: number; 144 | near: number; 145 | far: number; 146 | }): Matrix4x4; 147 | /** 148 | * Multiply by `other` matrix and returns a product. 149 | * 150 | * This method does not mutate the matrix. 151 | * @param {Matrix4x4} other 152 | * @returns {Matrix4x4} 153 | */ 154 | mulByMatrix4x4(other: Matrix4x4): Matrix4x4; 155 | /** 156 | * An alias for `mulByMatrix4x4`. 157 | * @param {Matrix4x4} other 158 | * @returns {Matrix4x4} 159 | */ 160 | mulByMatrix4(other: Matrix4x4): Matrix4x4; 161 | /** 162 | * Translate the matrix and returns new `Matrix4x4`. 163 | * 164 | * This method does not mutate the matrix. 165 | * @param {number} tx 166 | * @param {number} ty 167 | * @param {number} tz 168 | * @returns {Matrix4x4} 169 | */ 170 | translate(tx: number, ty: number, tz: number): Matrix4x4; 171 | /** 172 | * Scale the matrix and returns new `Matrix4x4`. 173 | * @param {number} sx 174 | * @param {number} sy 175 | * @param {number} sz 176 | * @returns {Matrix4x4} 177 | */ 178 | scale(sx: number, sy: number, sz: number): Matrix4x4; 179 | /** 180 | * Rotate the matrix around x-axis and returns new `Matrix4x4`. 181 | * 182 | * This method does not mutate the matrix. 183 | * @param {number} radian 184 | * @returns {Matrix4x4} 185 | */ 186 | rotateX(radian: number): Matrix4x4; 187 | /** 188 | * Rotate the matrix around y-axis and returns new `Matrix4x4`. 189 | * 190 | * This method does not mutate the matrix. 191 | * @param {number} radian 192 | * @returns {Matrix4x4} 193 | */ 194 | rotateY(radian: number): Matrix4x4; 195 | /** 196 | * Rotate the matrix around z-axis and returns new `Matrix4x4`. 197 | * 198 | * This method does not mutate the matrix. 199 | * @param {number} radian 200 | * @returns {Matrix4x4} 201 | */ 202 | rotateZ(radian: number): Matrix4x4; 203 | /** 204 | * Rotate the matrix around the `normalizedAxis` and return new Matrix4x4. 205 | * 206 | * This method does not mutate the matrix. 207 | * @param {Float32Vector3} normalizedAxis 208 | * @param {number} radian 209 | * @returns {Matrix4x4} 210 | */ 211 | rotateAround(normalizedAxis: Float32Vector3, radian: number): Matrix4x4; 212 | get values(): Float32Array; 213 | toString(): string; 214 | } 215 | /** 216 | * An alias for `Matrix2x2`. 217 | * @type {Matrix2x2} 218 | */ 219 | export declare const Matrix2: typeof Matrix2x2; 220 | /** 221 | * An alias for `Matrix3x3`. 222 | * @type {Matrix3x3} 223 | */ 224 | export declare const Matrix3: typeof Matrix3x3; 225 | /** 226 | * An alias for `Matrix4x4`. 227 | * @type {Matrix4x4} 228 | */ 229 | export declare const Matrix4: typeof Matrix4x4; 230 | -------------------------------------------------------------------------------- /lib/cjs/matrix.js: -------------------------------------------------------------------------------- 1 | var __defProp = Object.defineProperty; 2 | var __markAsModule = (target) => __defProp(target, "__esModule", { value: true }); 3 | var __export = (target, all) => { 4 | __markAsModule(target); 5 | for (var name in all) 6 | __defProp(target, name, { get: all[name], enumerable: true }); 7 | }; 8 | 9 | // src/matrix.ts 10 | __export(exports, { 11 | Matrix2: () => Matrix2, 12 | Matrix2x2: () => Matrix2x2, 13 | Matrix3: () => Matrix3, 14 | Matrix3x3: () => Matrix3x3, 15 | Matrix4: () => Matrix4, 16 | Matrix4x4: () => Matrix4x4 17 | }); 18 | 19 | // src/quaternion.ts 20 | var Quaternion = class { 21 | constructor(x, y, z, w) { 22 | this._values = new Float32Array([x, y, z, w]); 23 | } 24 | static rotationAround(normalizedAxis, radian) { 25 | const sin = Math.sin(radian / 2); 26 | const cos = Math.cos(radian / 2); 27 | return new Quaternion(normalizedAxis.x * sin, normalizedAxis.y * sin, normalizedAxis.z * sin, cos); 28 | } 29 | normalize() { 30 | const mag = this.magnitude; 31 | if (mag === 0) { 32 | return this; 33 | } 34 | const r = 1 / mag; 35 | return new Quaternion(this.x * r, this.y * r, this.z * r, this.w * r); 36 | } 37 | add(other) { 38 | return new Quaternion(this.x + other.x, this.y + other.y, this.z + other.z, this.w + other.w); 39 | } 40 | mulByScalar(scalar) { 41 | return new Quaternion(this.x * scalar, this.y * scalar, this.z * scalar, this.w * scalar); 42 | } 43 | dot(other) { 44 | return this.x * other.x + this.y * other.y + this.z * other.z + this.w * other.w; 45 | } 46 | slerp(other, t, options = { chooseShorterAngle: true }) { 47 | let dotProd = this.dot(other); 48 | let otherQuaternion = other; 49 | if (dotProd < 0) { 50 | dotProd = -dotProd; 51 | otherQuaternion = other.mulByScalar(-1); 52 | } 53 | const omega = Math.acos(dotProd); 54 | const sinOmega = Math.sin(omega); 55 | const q1 = this.mulByScalar(Math.sin((1 - t) * omega) / sinOmega); 56 | const q2 = otherQuaternion.mulByScalar(Math.sin(t * omega) / sinOmega); 57 | return q1.add(q2); 58 | } 59 | get magnitude() { 60 | return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w); 61 | } 62 | get norm() { 63 | return this.magnitude; 64 | } 65 | get x() { 66 | return this._values[0]; 67 | } 68 | get y() { 69 | return this._values[1]; 70 | } 71 | get z() { 72 | return this._values[2]; 73 | } 74 | get w() { 75 | return this._values[3]; 76 | } 77 | set x(value) { 78 | this._values[0] = value; 79 | } 80 | set y(value) { 81 | this._values[1] = value; 82 | } 83 | set z(value) { 84 | this._values[2] = value; 85 | } 86 | set w(value) { 87 | this._values[3] = value; 88 | } 89 | get values() { 90 | return this._values; 91 | } 92 | toRotationMatrix4() { 93 | const x = this.x; 94 | const y = this.y; 95 | const z = this.z; 96 | const w = this.w; 97 | const m11 = 1 - 2 * y * y - 2 * z * z; 98 | const m12 = 2 * x * y - 2 * w * z; 99 | const m13 = 2 * x * z + 2 * w * y; 100 | const m14 = 0; 101 | const m21 = 2 * x * y + 2 * w * z; 102 | const m22 = 1 - 2 * x * x - 2 * z * z; 103 | const m23 = 2 * y * z - 2 * w * x; 104 | const m24 = 0; 105 | const m31 = 2 * x * z - 2 * w * y; 106 | const m32 = 2 * y * z + 2 * w * x; 107 | const m33 = 1 - 2 * x * x - 2 * y * y; 108 | const m34 = 0; 109 | const m41 = 0; 110 | const m42 = 0; 111 | const m43 = 0; 112 | const m44 = 1; 113 | return new Matrix4x4(m11, m21, m31, m41, m12, m22, m32, m42, m13, m23, m33, m43, m14, m24, m34, m44); 114 | } 115 | toString() { 116 | return `Quaternion(${this.x}, ${this.y}, ${this.z}, ${this.w})`; 117 | } 118 | }; 119 | 120 | // src/matrix.ts 121 | var Matrix2x2 = class { 122 | constructor(m11, m21, m12, m22) { 123 | this._values = new Float32Array([ 124 | m11, 125 | m21, 126 | m12, 127 | m22 128 | ]); 129 | } 130 | static identity() { 131 | return new Matrix2x2(1, 0, 0, 1); 132 | } 133 | get values() { 134 | return this._values; 135 | } 136 | toString() { 137 | return this._values.toString(); 138 | } 139 | }; 140 | var Matrix3x3 = class { 141 | constructor(m11, m21, m31, m12, m22, m32, m13, m23, m33) { 142 | this._values = new Float32Array([ 143 | m11, 144 | m21, 145 | m31, 146 | m12, 147 | m22, 148 | m32, 149 | m13, 150 | m23, 151 | m33 152 | ]); 153 | } 154 | static identity() { 155 | return new Matrix3x3(1, 0, 0, 0, 1, 0, 0, 0, 1); 156 | } 157 | get values() { 158 | return this._values; 159 | } 160 | toString() { 161 | return this._values.toString(); 162 | } 163 | }; 164 | var Matrix4x4 = class { 165 | constructor(m11, m21, m31, m41, m12, m22, m32, m42, m13, m23, m33, m43, m14, m24, m34, m44) { 166 | this._values = new Float32Array([ 167 | m11, 168 | m21, 169 | m31, 170 | m41, 171 | m12, 172 | m22, 173 | m32, 174 | m42, 175 | m13, 176 | m23, 177 | m33, 178 | m43, 179 | m14, 180 | m24, 181 | m34, 182 | m44 183 | ]); 184 | } 185 | static identity() { 186 | return new Matrix4x4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 187 | } 188 | static translation(tx, ty, tz) { 189 | return new Matrix4x4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, tx, ty, tz, 1); 190 | } 191 | static scaling(sx, sy, sz) { 192 | return new Matrix4x4(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, sz, 0, 0, 0, 0, 1); 193 | } 194 | static rotationX(radian) { 195 | const sin = Math.sin(radian); 196 | const cos = Math.cos(radian); 197 | return new Matrix4x4(1, 0, 0, 0, 0, cos, sin, 0, 0, -sin, cos, 0, 0, 0, 0, 1); 198 | } 199 | static rotationY(radian) { 200 | const sin = Math.sin(radian); 201 | const cos = Math.cos(radian); 202 | return new Matrix4x4(cos, 0, -sin, 0, 0, 1, 0, 0, sin, 0, cos, 0, 0, 0, 0, 1); 203 | } 204 | static rotationZ(radian) { 205 | const sin = Math.sin(radian); 206 | const cos = Math.cos(radian); 207 | return new Matrix4x4(cos, sin, 0, 0, -sin, cos, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 208 | } 209 | static rotationAround(normalizedAxis, radian) { 210 | const q = Quaternion.rotationAround(normalizedAxis, radian); 211 | return q.toRotationMatrix4(); 212 | } 213 | static lookAt(cameraPosition, lookAtPosition, cameraUp) { 214 | const zAxis = cameraPosition.sub(lookAtPosition).normalize(); 215 | const xAxis = cameraUp.cross(zAxis).normalize(); 216 | const yAxis = zAxis.cross(xAxis).normalize(); 217 | return new Matrix4x4(xAxis.x, yAxis.x, zAxis.x, 0, xAxis.y, yAxis.y, zAxis.y, 0, xAxis.z, yAxis.z, zAxis.z, 0, -cameraPosition.dot(xAxis), -cameraPosition.dot(yAxis), -cameraPosition.dot(zAxis), 1); 218 | } 219 | static orthographic(argsObject) { 220 | const top = argsObject.top; 221 | const bottom = argsObject.bottom; 222 | const left = argsObject.left; 223 | const right = argsObject.right; 224 | const near = argsObject.near; 225 | const far = argsObject.far; 226 | return new Matrix4x4(2 / (right - left), 0, 0, 0, 0, 2 / (top - bottom), 0, 0, 0, 0, -2 / (far - near), 0, -(right + left) / (right - left), -(top + bottom) / (top - bottom), -(far + near) / (far - near), 1); 227 | } 228 | static frustum(argsObject) { 229 | const top = argsObject.top; 230 | const bottom = argsObject.bottom; 231 | const left = argsObject.left; 232 | const right = argsObject.right; 233 | const near = argsObject.near; 234 | const far = argsObject.far; 235 | return new Matrix4x4(2 * near / (right - left), 0, 0, 0, 0, 2 * near / (top - bottom), 0, 0, (right + left) / (right - left), (top + bottom) / (top - bottom), -(far + near) / (far - near), -1, 0, 0, -2 * far * near / (far - near), 0); 236 | } 237 | static perspective(argsObject) { 238 | const top = argsObject.near * Math.tan(argsObject.fovYRadian * 0.5); 239 | const height = top * 2; 240 | const width = argsObject.aspectRatio * height; 241 | const left = -0.5 * width; 242 | const right = left + width; 243 | const bottom = top - height; 244 | return Matrix4x4.frustum({ 245 | top, 246 | bottom, 247 | left, 248 | right, 249 | near: argsObject.near, 250 | far: argsObject.far 251 | }); 252 | } 253 | mulByMatrix4x4(other) { 254 | const m11 = this._values[0]; 255 | const m12 = this._values[4]; 256 | const m13 = this._values[8]; 257 | const m14 = this._values[12]; 258 | const m21 = this._values[1]; 259 | const m22 = this._values[5]; 260 | const m23 = this._values[9]; 261 | const m24 = this._values[13]; 262 | const m31 = this._values[2]; 263 | const m32 = this._values[6]; 264 | const m33 = this._values[10]; 265 | const m34 = this._values[14]; 266 | const m41 = this._values[3]; 267 | const m42 = this._values[7]; 268 | const m43 = this._values[11]; 269 | const m44 = this._values[15]; 270 | const o11 = other.values[0]; 271 | const o12 = other.values[4]; 272 | const o13 = other.values[8]; 273 | const o14 = other.values[12]; 274 | const o21 = other.values[1]; 275 | const o22 = other.values[5]; 276 | const o23 = other.values[9]; 277 | const o24 = other.values[13]; 278 | const o31 = other.values[2]; 279 | const o32 = other.values[6]; 280 | const o33 = other.values[10]; 281 | const o34 = other.values[14]; 282 | const o41 = other.values[3]; 283 | const o42 = other.values[7]; 284 | const o43 = other.values[11]; 285 | const o44 = other.values[15]; 286 | const p11 = m11 * o11 + m12 * o21 + m13 * o31 + m14 * o41; 287 | const p12 = m11 * o12 + m12 * o22 + m13 * o32 + m14 * o42; 288 | const p13 = m11 * o13 + m12 * o23 + m13 * o33 + m14 * o43; 289 | const p14 = m11 * o14 + m12 * o24 + m13 * o34 + m14 * o44; 290 | const p21 = m21 * o11 + m22 * o21 + m23 * o31 + m24 * o41; 291 | const p22 = m21 * o12 + m22 * o22 + m23 * o32 + m24 * o42; 292 | const p23 = m21 * o13 + m22 * o23 + m23 * o33 + m24 * o43; 293 | const p24 = m21 * o14 + m22 * o24 + m23 * o34 + m24 * o44; 294 | const p31 = m31 * o11 + m32 * o21 + m33 * o31 + m34 * o41; 295 | const p32 = m31 * o12 + m32 * o22 + m33 * o32 + m34 * o42; 296 | const p33 = m31 * o13 + m32 * o23 + m33 * o33 + m34 * o43; 297 | const p34 = m31 * o14 + m32 * o24 + m33 * o34 + m34 * o44; 298 | const p41 = m41 * o11 + m42 * o21 + m43 * o31 + m44 * o41; 299 | const p42 = m41 * o12 + m42 * o22 + m43 * o32 + m44 * o42; 300 | const p43 = m41 * o13 + m42 * o23 + m43 * o33 + m44 * o43; 301 | const p44 = m41 * o14 + m42 * o24 + m43 * o34 + m44 * o44; 302 | return new Matrix4x4(p11, p21, p31, p41, p12, p22, p32, p42, p13, p23, p33, p43, p14, p24, p34, p44); 303 | } 304 | mulByMatrix4(other) { 305 | return this.mulByMatrix4x4(other); 306 | } 307 | translate(tx, ty, tz) { 308 | const t = Matrix4x4.translation(tx, ty, tz); 309 | return this.mulByMatrix4x4(t); 310 | } 311 | scale(sx, sy, sz) { 312 | const s = Matrix4x4.scaling(sx, sy, sz); 313 | return this.mulByMatrix4x4(s); 314 | } 315 | rotateX(radian) { 316 | const rx = Matrix4x4.rotationX(radian); 317 | return this.mulByMatrix4x4(rx); 318 | } 319 | rotateY(radian) { 320 | const ry = Matrix4x4.rotationY(radian); 321 | return this.mulByMatrix4x4(ry); 322 | } 323 | rotateZ(radian) { 324 | const rz = Matrix4x4.rotationZ(radian); 325 | return this.mulByMatrix4x4(rz); 326 | } 327 | rotateAround(normalizedAxis, radian) { 328 | const r = Matrix4x4.rotationAround(normalizedAxis, radian); 329 | return this.mulByMatrix4x4(r); 330 | } 331 | get values() { 332 | return this._values; 333 | } 334 | toString() { 335 | return this._values.toString(); 336 | } 337 | }; 338 | var Matrix2 = Matrix2x2; 339 | var Matrix3 = Matrix3x3; 340 | var Matrix4 = Matrix4x4; 341 | // Annotate the CommonJS export names for ESM import in node: 342 | 0 && (module.exports = { 343 | Matrix2, 344 | Matrix2x2, 345 | Matrix3, 346 | Matrix3x3, 347 | Matrix4, 348 | Matrix4x4 349 | }); 350 | -------------------------------------------------------------------------------- /lib/cjs/quaternion.d.ts: -------------------------------------------------------------------------------- 1 | import { Float32Vector3 } from './float32vector'; 2 | import { Matrix4x4 } from './matrix'; 3 | /** 4 | * Quaternion which is 4-dimensional complex number. 5 | * See [Wikipedia](https://en.wikipedia.org/wiki/Quaternion). 6 | */ 7 | export declare class Quaternion { 8 | protected _values: Float32Array; 9 | constructor(x: number, y: number, z: number, w: number); 10 | /** 11 | * Create a rotation quaternion around `normalizedAxis`. 12 | * `normalizedAxis` must be normalized. 13 | * @param {Float32Vector3} normalizedAxis 14 | * @param {number} radian 15 | * @returns {Quaternion} 16 | */ 17 | static rotationAround(normalizedAxis: Float32Vector3, radian: number): Quaternion; 18 | /** 19 | * Returns a normalized quaternion. 20 | * @returns {Quaternion} 21 | */ 22 | normalize(): Quaternion; 23 | /** 24 | * Adds the `other` to the quaternion and returns the sum. 25 | * 26 | * This method does not mutate the quaternion. 27 | * @param {Quaternion} other 28 | * @returns {Quaternion} 29 | */ 30 | add(other: Quaternion): Quaternion; 31 | /** 32 | * Multiplies the quaternion by `scalar` and returns the product. 33 | * 34 | * This method does not mutate the quaternion. 35 | * @param {number} scalar 36 | * @returns {Quaternion} 37 | */ 38 | mulByScalar(scalar: number): Quaternion; 39 | /** 40 | * Calculates dot product. 41 | * @param {Quaternion} other 42 | * @returns {number} 43 | */ 44 | dot(other: Quaternion): number; 45 | /** 46 | * Calculates spherical linear interpolation(also known as Slerp) and returns new `Quaternion` between the quaternion and the other. 47 | * @param {Quaternion} other 48 | * @param {number} t 0.0 <= t <= 1.0 49 | * @param {{chooseShorterAngle: boolean}} options Does not work currently. slerp chooses shorter angle regardless of this value. 50 | * @returns {Quaternion} 51 | */ 52 | slerp(other: Quaternion, t: number, options?: { 53 | chooseShorterAngle: boolean; 54 | }): Quaternion; 55 | /** 56 | * Calc magnitude of the quaternion. 57 | * @returns {number} 58 | */ 59 | get magnitude(): number; 60 | /** 61 | * Calc norm of the quaternion. 62 | * An alias for `magnitude`. 63 | * @returns {number} 64 | */ 65 | get norm(): number; 66 | /** 67 | * Returns x value of the vector. 68 | * @returns {number} 69 | */ 70 | get x(): number; 71 | /** 72 | * Returns y value of the vector. 73 | * @returns {number} 74 | */ 75 | get y(): number; 76 | /** 77 | * Returns z value of the vector. 78 | * @returns {number} 79 | */ 80 | get z(): number; 81 | /** 82 | * Returns w value of the vector. 83 | * @returns {number} 84 | */ 85 | get w(): number; 86 | /** 87 | * Set the `value` as new x. 88 | * @param {number} value 89 | */ 90 | set x(value: number); 91 | /** 92 | * Set the `value` as new y. 93 | * @param {number} value 94 | */ 95 | set y(value: number); 96 | /** 97 | * Set the `value` as new z. 98 | * @param {number} value 99 | */ 100 | set z(value: number); 101 | /** 102 | * Set the `value` as new w. 103 | * @param {number} value 104 | */ 105 | set w(value: number); 106 | /** 107 | * Returns values of the quaternion. 108 | * @returns {Float32Array} 109 | */ 110 | get values(): Float32Array; 111 | /** 112 | * Convert the quaternion to a rotation matrix. 113 | * @returns {Matrix4x4} 114 | */ 115 | toRotationMatrix4(): Matrix4x4; 116 | /** 117 | * Returns values as `String`. 118 | * @returns {string} 119 | */ 120 | toString(): string; 121 | } 122 | -------------------------------------------------------------------------------- /lib/cjs/quaternion.js: -------------------------------------------------------------------------------- 1 | var __defProp = Object.defineProperty; 2 | var __markAsModule = (target) => __defProp(target, "__esModule", { value: true }); 3 | var __export = (target, all) => { 4 | __markAsModule(target); 5 | for (var name in all) 6 | __defProp(target, name, { get: all[name], enumerable: true }); 7 | }; 8 | 9 | // src/quaternion.ts 10 | __export(exports, { 11 | Quaternion: () => Quaternion 12 | }); 13 | 14 | // src/matrix.ts 15 | var Matrix4x4 = class { 16 | constructor(m11, m21, m31, m41, m12, m22, m32, m42, m13, m23, m33, m43, m14, m24, m34, m44) { 17 | this._values = new Float32Array([ 18 | m11, 19 | m21, 20 | m31, 21 | m41, 22 | m12, 23 | m22, 24 | m32, 25 | m42, 26 | m13, 27 | m23, 28 | m33, 29 | m43, 30 | m14, 31 | m24, 32 | m34, 33 | m44 34 | ]); 35 | } 36 | static identity() { 37 | return new Matrix4x4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 38 | } 39 | static translation(tx, ty, tz) { 40 | return new Matrix4x4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, tx, ty, tz, 1); 41 | } 42 | static scaling(sx, sy, sz) { 43 | return new Matrix4x4(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, sz, 0, 0, 0, 0, 1); 44 | } 45 | static rotationX(radian) { 46 | const sin = Math.sin(radian); 47 | const cos = Math.cos(radian); 48 | return new Matrix4x4(1, 0, 0, 0, 0, cos, sin, 0, 0, -sin, cos, 0, 0, 0, 0, 1); 49 | } 50 | static rotationY(radian) { 51 | const sin = Math.sin(radian); 52 | const cos = Math.cos(radian); 53 | return new Matrix4x4(cos, 0, -sin, 0, 0, 1, 0, 0, sin, 0, cos, 0, 0, 0, 0, 1); 54 | } 55 | static rotationZ(radian) { 56 | const sin = Math.sin(radian); 57 | const cos = Math.cos(radian); 58 | return new Matrix4x4(cos, sin, 0, 0, -sin, cos, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 59 | } 60 | static rotationAround(normalizedAxis, radian) { 61 | const q = Quaternion.rotationAround(normalizedAxis, radian); 62 | return q.toRotationMatrix4(); 63 | } 64 | static lookAt(cameraPosition, lookAtPosition, cameraUp) { 65 | const zAxis = cameraPosition.sub(lookAtPosition).normalize(); 66 | const xAxis = cameraUp.cross(zAxis).normalize(); 67 | const yAxis = zAxis.cross(xAxis).normalize(); 68 | return new Matrix4x4(xAxis.x, yAxis.x, zAxis.x, 0, xAxis.y, yAxis.y, zAxis.y, 0, xAxis.z, yAxis.z, zAxis.z, 0, -cameraPosition.dot(xAxis), -cameraPosition.dot(yAxis), -cameraPosition.dot(zAxis), 1); 69 | } 70 | static orthographic(argsObject) { 71 | const top = argsObject.top; 72 | const bottom = argsObject.bottom; 73 | const left = argsObject.left; 74 | const right = argsObject.right; 75 | const near = argsObject.near; 76 | const far = argsObject.far; 77 | return new Matrix4x4(2 / (right - left), 0, 0, 0, 0, 2 / (top - bottom), 0, 0, 0, 0, -2 / (far - near), 0, -(right + left) / (right - left), -(top + bottom) / (top - bottom), -(far + near) / (far - near), 1); 78 | } 79 | static frustum(argsObject) { 80 | const top = argsObject.top; 81 | const bottom = argsObject.bottom; 82 | const left = argsObject.left; 83 | const right = argsObject.right; 84 | const near = argsObject.near; 85 | const far = argsObject.far; 86 | return new Matrix4x4(2 * near / (right - left), 0, 0, 0, 0, 2 * near / (top - bottom), 0, 0, (right + left) / (right - left), (top + bottom) / (top - bottom), -(far + near) / (far - near), -1, 0, 0, -2 * far * near / (far - near), 0); 87 | } 88 | static perspective(argsObject) { 89 | const top = argsObject.near * Math.tan(argsObject.fovYRadian * 0.5); 90 | const height = top * 2; 91 | const width = argsObject.aspectRatio * height; 92 | const left = -0.5 * width; 93 | const right = left + width; 94 | const bottom = top - height; 95 | return Matrix4x4.frustum({ 96 | top, 97 | bottom, 98 | left, 99 | right, 100 | near: argsObject.near, 101 | far: argsObject.far 102 | }); 103 | } 104 | mulByMatrix4x4(other) { 105 | const m11 = this._values[0]; 106 | const m12 = this._values[4]; 107 | const m13 = this._values[8]; 108 | const m14 = this._values[12]; 109 | const m21 = this._values[1]; 110 | const m22 = this._values[5]; 111 | const m23 = this._values[9]; 112 | const m24 = this._values[13]; 113 | const m31 = this._values[2]; 114 | const m32 = this._values[6]; 115 | const m33 = this._values[10]; 116 | const m34 = this._values[14]; 117 | const m41 = this._values[3]; 118 | const m42 = this._values[7]; 119 | const m43 = this._values[11]; 120 | const m44 = this._values[15]; 121 | const o11 = other.values[0]; 122 | const o12 = other.values[4]; 123 | const o13 = other.values[8]; 124 | const o14 = other.values[12]; 125 | const o21 = other.values[1]; 126 | const o22 = other.values[5]; 127 | const o23 = other.values[9]; 128 | const o24 = other.values[13]; 129 | const o31 = other.values[2]; 130 | const o32 = other.values[6]; 131 | const o33 = other.values[10]; 132 | const o34 = other.values[14]; 133 | const o41 = other.values[3]; 134 | const o42 = other.values[7]; 135 | const o43 = other.values[11]; 136 | const o44 = other.values[15]; 137 | const p11 = m11 * o11 + m12 * o21 + m13 * o31 + m14 * o41; 138 | const p12 = m11 * o12 + m12 * o22 + m13 * o32 + m14 * o42; 139 | const p13 = m11 * o13 + m12 * o23 + m13 * o33 + m14 * o43; 140 | const p14 = m11 * o14 + m12 * o24 + m13 * o34 + m14 * o44; 141 | const p21 = m21 * o11 + m22 * o21 + m23 * o31 + m24 * o41; 142 | const p22 = m21 * o12 + m22 * o22 + m23 * o32 + m24 * o42; 143 | const p23 = m21 * o13 + m22 * o23 + m23 * o33 + m24 * o43; 144 | const p24 = m21 * o14 + m22 * o24 + m23 * o34 + m24 * o44; 145 | const p31 = m31 * o11 + m32 * o21 + m33 * o31 + m34 * o41; 146 | const p32 = m31 * o12 + m32 * o22 + m33 * o32 + m34 * o42; 147 | const p33 = m31 * o13 + m32 * o23 + m33 * o33 + m34 * o43; 148 | const p34 = m31 * o14 + m32 * o24 + m33 * o34 + m34 * o44; 149 | const p41 = m41 * o11 + m42 * o21 + m43 * o31 + m44 * o41; 150 | const p42 = m41 * o12 + m42 * o22 + m43 * o32 + m44 * o42; 151 | const p43 = m41 * o13 + m42 * o23 + m43 * o33 + m44 * o43; 152 | const p44 = m41 * o14 + m42 * o24 + m43 * o34 + m44 * o44; 153 | return new Matrix4x4(p11, p21, p31, p41, p12, p22, p32, p42, p13, p23, p33, p43, p14, p24, p34, p44); 154 | } 155 | mulByMatrix4(other) { 156 | return this.mulByMatrix4x4(other); 157 | } 158 | translate(tx, ty, tz) { 159 | const t = Matrix4x4.translation(tx, ty, tz); 160 | return this.mulByMatrix4x4(t); 161 | } 162 | scale(sx, sy, sz) { 163 | const s = Matrix4x4.scaling(sx, sy, sz); 164 | return this.mulByMatrix4x4(s); 165 | } 166 | rotateX(radian) { 167 | const rx = Matrix4x4.rotationX(radian); 168 | return this.mulByMatrix4x4(rx); 169 | } 170 | rotateY(radian) { 171 | const ry = Matrix4x4.rotationY(radian); 172 | return this.mulByMatrix4x4(ry); 173 | } 174 | rotateZ(radian) { 175 | const rz = Matrix4x4.rotationZ(radian); 176 | return this.mulByMatrix4x4(rz); 177 | } 178 | rotateAround(normalizedAxis, radian) { 179 | const r = Matrix4x4.rotationAround(normalizedAxis, radian); 180 | return this.mulByMatrix4x4(r); 181 | } 182 | get values() { 183 | return this._values; 184 | } 185 | toString() { 186 | return this._values.toString(); 187 | } 188 | }; 189 | 190 | // src/quaternion.ts 191 | var Quaternion = class { 192 | constructor(x, y, z, w) { 193 | this._values = new Float32Array([x, y, z, w]); 194 | } 195 | static rotationAround(normalizedAxis, radian) { 196 | const sin = Math.sin(radian / 2); 197 | const cos = Math.cos(radian / 2); 198 | return new Quaternion(normalizedAxis.x * sin, normalizedAxis.y * sin, normalizedAxis.z * sin, cos); 199 | } 200 | normalize() { 201 | const mag = this.magnitude; 202 | if (mag === 0) { 203 | return this; 204 | } 205 | const r = 1 / mag; 206 | return new Quaternion(this.x * r, this.y * r, this.z * r, this.w * r); 207 | } 208 | add(other) { 209 | return new Quaternion(this.x + other.x, this.y + other.y, this.z + other.z, this.w + other.w); 210 | } 211 | mulByScalar(scalar) { 212 | return new Quaternion(this.x * scalar, this.y * scalar, this.z * scalar, this.w * scalar); 213 | } 214 | dot(other) { 215 | return this.x * other.x + this.y * other.y + this.z * other.z + this.w * other.w; 216 | } 217 | slerp(other, t, options = { chooseShorterAngle: true }) { 218 | let dotProd = this.dot(other); 219 | let otherQuaternion = other; 220 | if (dotProd < 0) { 221 | dotProd = -dotProd; 222 | otherQuaternion = other.mulByScalar(-1); 223 | } 224 | const omega = Math.acos(dotProd); 225 | const sinOmega = Math.sin(omega); 226 | const q1 = this.mulByScalar(Math.sin((1 - t) * omega) / sinOmega); 227 | const q2 = otherQuaternion.mulByScalar(Math.sin(t * omega) / sinOmega); 228 | return q1.add(q2); 229 | } 230 | get magnitude() { 231 | return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w); 232 | } 233 | get norm() { 234 | return this.magnitude; 235 | } 236 | get x() { 237 | return this._values[0]; 238 | } 239 | get y() { 240 | return this._values[1]; 241 | } 242 | get z() { 243 | return this._values[2]; 244 | } 245 | get w() { 246 | return this._values[3]; 247 | } 248 | set x(value) { 249 | this._values[0] = value; 250 | } 251 | set y(value) { 252 | this._values[1] = value; 253 | } 254 | set z(value) { 255 | this._values[2] = value; 256 | } 257 | set w(value) { 258 | this._values[3] = value; 259 | } 260 | get values() { 261 | return this._values; 262 | } 263 | toRotationMatrix4() { 264 | const x = this.x; 265 | const y = this.y; 266 | const z = this.z; 267 | const w = this.w; 268 | const m11 = 1 - 2 * y * y - 2 * z * z; 269 | const m12 = 2 * x * y - 2 * w * z; 270 | const m13 = 2 * x * z + 2 * w * y; 271 | const m14 = 0; 272 | const m21 = 2 * x * y + 2 * w * z; 273 | const m22 = 1 - 2 * x * x - 2 * z * z; 274 | const m23 = 2 * y * z - 2 * w * x; 275 | const m24 = 0; 276 | const m31 = 2 * x * z - 2 * w * y; 277 | const m32 = 2 * y * z + 2 * w * x; 278 | const m33 = 1 - 2 * x * x - 2 * y * y; 279 | const m34 = 0; 280 | const m41 = 0; 281 | const m42 = 0; 282 | const m43 = 0; 283 | const m44 = 1; 284 | return new Matrix4x4(m11, m21, m31, m41, m12, m22, m32, m42, m13, m23, m33, m43, m14, m24, m34, m44); 285 | } 286 | toString() { 287 | return `Quaternion(${this.x}, ${this.y}, ${this.z}, ${this.w})`; 288 | } 289 | }; 290 | // Annotate the CommonJS export names for ESM import in node: 291 | 0 && (module.exports = { 292 | Quaternion 293 | }); 294 | -------------------------------------------------------------------------------- /lib/cjs/vector_base.d.ts: -------------------------------------------------------------------------------- 1 | export declare type TypedArrayLike = Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array; 2 | /** 3 | * An interface for vectors. 4 | */ 5 | export interface Vector { 6 | /** 7 | * Returns values of the vector. 8 | * @returns {T} 9 | */ 10 | readonly values: T; 11 | /** 12 | * Returns magnitude of the vector. 13 | */ 14 | readonly magnitude: number; 15 | /** 16 | * Returns `values` as a string. 17 | * @returns {string} 18 | */ 19 | toString(): string; 20 | } 21 | /** 22 | * An abstract class for vectors. 23 | */ 24 | export declare abstract class VectorBase implements Vector { 25 | /** 26 | * Values that the vector contains. 27 | */ 28 | protected _values: T; 29 | get values(): T; 30 | get magnitude(): number; 31 | toString(): string; 32 | } 33 | /** 34 | * A base abstract class for 2-dimensional vectors. 35 | */ 36 | export declare abstract class Vector2Base extends VectorBase { 37 | /** 38 | * Returns x value of the vector. 39 | * @returns {number} 40 | */ 41 | get x(): number; 42 | /** 43 | * Returns y value of the vector. 44 | * @returns {number} 45 | */ 46 | get y(): number; 47 | /** 48 | * Set the `value` as new x. 49 | * @param {number} value 50 | */ 51 | set x(value: number); 52 | /** 53 | * Set the `value` as new y. 54 | * @param {number} value 55 | */ 56 | set y(value: number); 57 | } 58 | /** 59 | * A base abstract class for 3-dimensional vectors. 60 | */ 61 | export declare abstract class Vector3Base extends VectorBase { 62 | /** 63 | * Returns x value of the vector. 64 | * @returns {number} 65 | */ 66 | get x(): number; 67 | /** 68 | * Returns y value of the vector. 69 | * @returns {number} 70 | */ 71 | get y(): number; 72 | /** 73 | * Returns z value of the vector. 74 | * @returns {number} 75 | */ 76 | get z(): number; 77 | /** 78 | * Set the `value` as new x. 79 | * @param {number} value 80 | */ 81 | set x(value: number); 82 | /** 83 | * Set the `value` as new y. 84 | * @param {number} value 85 | */ 86 | set y(value: number); 87 | /** 88 | * Set the `value` as new z. 89 | * @param {number} value 90 | */ 91 | set z(value: number); 92 | } 93 | /** 94 | * A base abstract class for 4-dimensional vectors. 95 | */ 96 | export declare abstract class Vector4Base extends VectorBase { 97 | /** 98 | * Returns x value of the vector. 99 | * @returns {number} 100 | */ 101 | get x(): number; 102 | /** 103 | * Returns y value of the vector. 104 | * @returns {number} 105 | */ 106 | get y(): number; 107 | /** 108 | * Returns z value of the vector. 109 | * @returns {number} 110 | */ 111 | get z(): number; 112 | /** 113 | * Returns w value of the vector. 114 | * @returns {number} 115 | */ 116 | get w(): number; 117 | /** 118 | * Set the `value` as new x. 119 | * @param {number} value 120 | */ 121 | set x(value: number); 122 | /** 123 | * Set the `value` as new y. 124 | * @param {number} value 125 | */ 126 | set y(value: number); 127 | /** 128 | * Set the `value` as new z. 129 | * @param {number} value 130 | */ 131 | set z(value: number); 132 | /** 133 | * Set the `value` as new w. 134 | * @param {number} value 135 | */ 136 | set w(value: number); 137 | } 138 | -------------------------------------------------------------------------------- /lib/cjs/vector_base.js: -------------------------------------------------------------------------------- 1 | var __defProp = Object.defineProperty; 2 | var __markAsModule = (target) => __defProp(target, "__esModule", { value: true }); 3 | var __export = (target, all) => { 4 | __markAsModule(target); 5 | for (var name in all) 6 | __defProp(target, name, { get: all[name], enumerable: true }); 7 | }; 8 | 9 | // src/vector_base.ts 10 | __export(exports, { 11 | Vector2Base: () => Vector2Base, 12 | Vector3Base: () => Vector3Base, 13 | Vector4Base: () => Vector4Base, 14 | VectorBase: () => VectorBase 15 | }); 16 | var VectorBase = class { 17 | get values() { 18 | return this._values; 19 | } 20 | get magnitude() { 21 | let sumSq = 0; 22 | for (const val of this._values) { 23 | sumSq += val ** 2; 24 | } 25 | return Math.sqrt(sumSq); 26 | } 27 | toString() { 28 | const dimension = this._values.length; 29 | return `Vector${dimension}(${this._values.join(", ")})`; 30 | } 31 | }; 32 | var Vector2Base = class extends VectorBase { 33 | get x() { 34 | return this._values[0]; 35 | } 36 | get y() { 37 | return this._values[1]; 38 | } 39 | set x(value) { 40 | this._values[0] = value; 41 | } 42 | set y(value) { 43 | this._values[1] = value; 44 | } 45 | }; 46 | var Vector3Base = class extends VectorBase { 47 | get x() { 48 | return this._values[0]; 49 | } 50 | get y() { 51 | return this._values[1]; 52 | } 53 | get z() { 54 | return this._values[2]; 55 | } 56 | set x(value) { 57 | this._values[0] = value; 58 | } 59 | set y(value) { 60 | this._values[1] = value; 61 | } 62 | set z(value) { 63 | this._values[2] = value; 64 | } 65 | }; 66 | var Vector4Base = class extends VectorBase { 67 | get x() { 68 | return this._values[0]; 69 | } 70 | get y() { 71 | return this._values[1]; 72 | } 73 | get z() { 74 | return this._values[2]; 75 | } 76 | get w() { 77 | return this._values[3]; 78 | } 79 | set x(value) { 80 | this._values[0] = value; 81 | } 82 | set y(value) { 83 | this._values[1] = value; 84 | } 85 | set z(value) { 86 | this._values[2] = value; 87 | } 88 | set w(value) { 89 | this._values[3] = value; 90 | } 91 | }; 92 | // Annotate the CommonJS export names for ESM import in node: 93 | 0 && (module.exports = { 94 | Vector2Base, 95 | Vector3Base, 96 | Vector4Base, 97 | VectorBase 98 | }); 99 | -------------------------------------------------------------------------------- /lib/esm/float32vector.d.ts: -------------------------------------------------------------------------------- 1 | import { Vector2Base, Vector3Base, Vector4Base } from './vector_base'; 2 | /** 3 | * A 2-dimensional vector of single-precision float numbers. 4 | */ 5 | export declare class Float32Vector2 extends Vector2Base { 6 | constructor(x: number, y: number); 7 | /** 8 | * Add `other` to the vector and returns new `Float32Vector2`. 9 | * 10 | * This method does not mutate the vector. 11 | * @param {Float32Vector2} other 12 | * @returns {Float32Vector2} 13 | */ 14 | add(other: Float32Vector2): Float32Vector2; 15 | /** 16 | * Subtract `other` from the vector and returns new `Float32Vector2`. 17 | * 18 | * This method does not mutate the vector. 19 | * @param {Float32Vector2} other 20 | * @returns {Float32Vector2} 21 | */ 22 | sub(other: Float32Vector2): Float32Vector2; 23 | /** 24 | * Multiply the vector by `scalar` and returns new `Float32Vector2`. 25 | * 26 | * This method does not mutate the vector. 27 | * @param {number} scalar 28 | * @returns {Float32Vector2} 29 | */ 30 | mulByScalar(scalar: number): Float32Vector2; 31 | } 32 | /** 33 | * A 3-dimensional vector of single-precision float numbers. 34 | */ 35 | export declare class Float32Vector3 extends Vector3Base { 36 | constructor(x: number, y: number, z: number); 37 | /** 38 | * Add `other` to the vector and returns new `Float32Vector3`. 39 | * 40 | * This method does not mutate the vector. 41 | * @param {Float32Vector3} other 42 | * @returns {Float32Vector3} 43 | */ 44 | add(other: Float32Vector3): Float32Vector3; 45 | /** 46 | * Subtract `other` from the vector and returns new `Float32Vector3`. 47 | * 48 | * This method does not mutate the vector. 49 | * @param {Float32Vector3} other 50 | * @returns {Float32Vector3} 51 | */ 52 | sub(other: Float32Vector3): Float32Vector3; 53 | /** 54 | * Multiply the vector by `scalar` and returns new `Float32Vector3`. 55 | * 56 | * This method does not mutate the vector. 57 | * @param {number} scalar 58 | * @returns {Float32Vector3} 59 | */ 60 | mulByScalar(scalar: number): Float32Vector3; 61 | /** 62 | * Calculate dot product. 63 | * @param {Float32Vector3} other 64 | * @returns {number} 65 | */ 66 | dot(other: Float32Vector3): number; 67 | /** 68 | * Calculate cross product. 69 | * @param {Float32Vector3} other 70 | * @returns {Float32Vector3} 71 | */ 72 | cross(other: Float32Vector3): Float32Vector3; 73 | /** 74 | * Normalize the vector and returns new `Float32Vector3`. 75 | * 76 | * This method does not mutate the vector. 77 | * @returns {Float32Vector3} 78 | */ 79 | normalize(): Float32Vector3; 80 | /** 81 | * Returns xy values of the vector as `Float32Vector2`. 82 | * @returns {Float32Vector2} 83 | */ 84 | get xy(): Float32Vector2; 85 | } 86 | /** 87 | * A 4-dimensional vector of single-precision float numbers. 88 | */ 89 | export declare class Float32Vector4 extends Vector4Base { 90 | constructor(x: number, y: number, z: number, w: number); 91 | /** 92 | * Add `other` to the vector and returns new `Float32Vector4`. 93 | * 94 | * This method does not mutate the vector. 95 | * @param {Float32Vector4} other 96 | * @returns {Float32Vector4} 97 | */ 98 | add(other: Float32Vector4): Float32Vector4; 99 | /** 100 | * Subtract `other` from the vector and returns new `Float32Vector4`. 101 | * 102 | * This method does not mutate the vector. 103 | * @param {Float32Vector4} other 104 | * @returns {Float32Vector4} 105 | */ 106 | sub(other: Float32Vector4): Float32Vector4; 107 | /** 108 | * Multiply the vector by `scalar` and returns new `Float32Vector4`. 109 | * 110 | * This method does not mutate the vector. 111 | * @param {number} scalar 112 | * @returns {Float32Vector4} 113 | */ 114 | mulByScalar(scalar: number): Float32Vector4; 115 | /** 116 | * Returns xyz values of the vector as `Float32Vector3`. 117 | * @returns {Float32Vector3} 118 | */ 119 | get xyz(): Float32Vector3; 120 | } 121 | /** 122 | * An alias for `Float32Vector2`. 123 | * @type {Float32Vector2} 124 | */ 125 | export declare const Vector2: typeof Float32Vector2; 126 | /** 127 | * An alias for `Float32Vector3`. 128 | * @type {Float32Vector3} 129 | */ 130 | export declare const Vector3: typeof Float32Vector3; 131 | /** 132 | * An alias for `Float32Vector4`. 133 | * @type {Float32Vector4} 134 | */ 135 | export declare const Vector4: typeof Float32Vector4; 136 | -------------------------------------------------------------------------------- /lib/esm/float32vector.js: -------------------------------------------------------------------------------- 1 | // src/vector_base.ts 2 | var VectorBase = class { 3 | get values() { 4 | return this._values; 5 | } 6 | get magnitude() { 7 | let sumSq = 0; 8 | for (const val of this._values) { 9 | sumSq += val ** 2; 10 | } 11 | return Math.sqrt(sumSq); 12 | } 13 | toString() { 14 | const dimension = this._values.length; 15 | return `Vector${dimension}(${this._values.join(", ")})`; 16 | } 17 | }; 18 | var Vector2Base = class extends VectorBase { 19 | get x() { 20 | return this._values[0]; 21 | } 22 | get y() { 23 | return this._values[1]; 24 | } 25 | set x(value) { 26 | this._values[0] = value; 27 | } 28 | set y(value) { 29 | this._values[1] = value; 30 | } 31 | }; 32 | var Vector3Base = class extends VectorBase { 33 | get x() { 34 | return this._values[0]; 35 | } 36 | get y() { 37 | return this._values[1]; 38 | } 39 | get z() { 40 | return this._values[2]; 41 | } 42 | set x(value) { 43 | this._values[0] = value; 44 | } 45 | set y(value) { 46 | this._values[1] = value; 47 | } 48 | set z(value) { 49 | this._values[2] = value; 50 | } 51 | }; 52 | var Vector4Base = class extends VectorBase { 53 | get x() { 54 | return this._values[0]; 55 | } 56 | get y() { 57 | return this._values[1]; 58 | } 59 | get z() { 60 | return this._values[2]; 61 | } 62 | get w() { 63 | return this._values[3]; 64 | } 65 | set x(value) { 66 | this._values[0] = value; 67 | } 68 | set y(value) { 69 | this._values[1] = value; 70 | } 71 | set z(value) { 72 | this._values[2] = value; 73 | } 74 | set w(value) { 75 | this._values[3] = value; 76 | } 77 | }; 78 | 79 | // src/float32vector.ts 80 | var Float32Vector2 = class extends Vector2Base { 81 | constructor(x, y) { 82 | super(); 83 | this._values = new Float32Array([x, y]); 84 | } 85 | add(other) { 86 | return new Float32Vector2(this.x + other.x, this.y + other.y); 87 | } 88 | sub(other) { 89 | return new Float32Vector2(this.x - other.x, this.y - other.y); 90 | } 91 | mulByScalar(scalar) { 92 | return new Float32Vector2(this.x * scalar, this.y * scalar); 93 | } 94 | }; 95 | var Float32Vector3 = class extends Vector3Base { 96 | constructor(x, y, z) { 97 | super(); 98 | this._values = new Float32Array([x, y, z]); 99 | } 100 | add(other) { 101 | return new Float32Vector3(this.x + other.x, this.y + other.y, this.z + other.z); 102 | } 103 | sub(other) { 104 | return new Float32Vector3(this.x - other.x, this.y - other.y, this.z - other.z); 105 | } 106 | mulByScalar(scalar) { 107 | return new Float32Vector3(this.x * scalar, this.y * scalar, this.z * scalar); 108 | } 109 | dot(other) { 110 | return this.x * other.x + this.y * other.y + this.z * other.z; 111 | } 112 | cross(other) { 113 | const cx = this.y * other.z - this.z * other.y; 114 | const cy = this.z * other.x - this.x * other.z; 115 | const cz = this.x * other.y - this.y * other.x; 116 | return new Float32Vector3(cx, cy, cz); 117 | } 118 | normalize() { 119 | const mag = this.magnitude; 120 | if (mag === 0) { 121 | return this; 122 | } 123 | return new Float32Vector3(this.x / mag, this.y / mag, this.z / mag); 124 | } 125 | get xy() { 126 | return new Float32Vector2(this.x, this.y); 127 | } 128 | }; 129 | var Float32Vector4 = class extends Vector4Base { 130 | constructor(x, y, z, w) { 131 | super(); 132 | this._values = new Float32Array([x, y, z, w]); 133 | } 134 | add(other) { 135 | return new Float32Vector4(this.x + other.x, this.y + other.y, this.z + other.z, this.w + other.w); 136 | } 137 | sub(other) { 138 | return new Float32Vector4(this.x - other.x, this.y - other.y, this.z - other.z, this.w - other.w); 139 | } 140 | mulByScalar(scalar) { 141 | return new Float32Vector4(this.x * scalar, this.y * scalar, this.z * scalar, this.w * scalar); 142 | } 143 | get xyz() { 144 | return new Float32Vector3(this.x, this.y, this.z); 145 | } 146 | }; 147 | var Vector2 = Float32Vector2; 148 | var Vector3 = Float32Vector3; 149 | var Vector4 = Float32Vector4; 150 | export { 151 | Float32Vector2, 152 | Float32Vector3, 153 | Float32Vector4, 154 | Vector2, 155 | Vector3, 156 | Vector4 157 | }; 158 | -------------------------------------------------------------------------------- /lib/esm/index.d.ts: -------------------------------------------------------------------------------- 1 | export * from './float32vector'; 2 | export * from './matrix'; 3 | export * from './quaternion'; 4 | -------------------------------------------------------------------------------- /lib/esm/index.js: -------------------------------------------------------------------------------- 1 | // src/vector_base.ts 2 | var VectorBase = class { 3 | get values() { 4 | return this._values; 5 | } 6 | get magnitude() { 7 | let sumSq = 0; 8 | for (const val of this._values) { 9 | sumSq += val ** 2; 10 | } 11 | return Math.sqrt(sumSq); 12 | } 13 | toString() { 14 | const dimension = this._values.length; 15 | return `Vector${dimension}(${this._values.join(", ")})`; 16 | } 17 | }; 18 | var Vector2Base = class extends VectorBase { 19 | get x() { 20 | return this._values[0]; 21 | } 22 | get y() { 23 | return this._values[1]; 24 | } 25 | set x(value) { 26 | this._values[0] = value; 27 | } 28 | set y(value) { 29 | this._values[1] = value; 30 | } 31 | }; 32 | var Vector3Base = class extends VectorBase { 33 | get x() { 34 | return this._values[0]; 35 | } 36 | get y() { 37 | return this._values[1]; 38 | } 39 | get z() { 40 | return this._values[2]; 41 | } 42 | set x(value) { 43 | this._values[0] = value; 44 | } 45 | set y(value) { 46 | this._values[1] = value; 47 | } 48 | set z(value) { 49 | this._values[2] = value; 50 | } 51 | }; 52 | var Vector4Base = class extends VectorBase { 53 | get x() { 54 | return this._values[0]; 55 | } 56 | get y() { 57 | return this._values[1]; 58 | } 59 | get z() { 60 | return this._values[2]; 61 | } 62 | get w() { 63 | return this._values[3]; 64 | } 65 | set x(value) { 66 | this._values[0] = value; 67 | } 68 | set y(value) { 69 | this._values[1] = value; 70 | } 71 | set z(value) { 72 | this._values[2] = value; 73 | } 74 | set w(value) { 75 | this._values[3] = value; 76 | } 77 | }; 78 | 79 | // src/float32vector.ts 80 | var Float32Vector2 = class extends Vector2Base { 81 | constructor(x, y) { 82 | super(); 83 | this._values = new Float32Array([x, y]); 84 | } 85 | add(other) { 86 | return new Float32Vector2(this.x + other.x, this.y + other.y); 87 | } 88 | sub(other) { 89 | return new Float32Vector2(this.x - other.x, this.y - other.y); 90 | } 91 | mulByScalar(scalar) { 92 | return new Float32Vector2(this.x * scalar, this.y * scalar); 93 | } 94 | }; 95 | var Float32Vector3 = class extends Vector3Base { 96 | constructor(x, y, z) { 97 | super(); 98 | this._values = new Float32Array([x, y, z]); 99 | } 100 | add(other) { 101 | return new Float32Vector3(this.x + other.x, this.y + other.y, this.z + other.z); 102 | } 103 | sub(other) { 104 | return new Float32Vector3(this.x - other.x, this.y - other.y, this.z - other.z); 105 | } 106 | mulByScalar(scalar) { 107 | return new Float32Vector3(this.x * scalar, this.y * scalar, this.z * scalar); 108 | } 109 | dot(other) { 110 | return this.x * other.x + this.y * other.y + this.z * other.z; 111 | } 112 | cross(other) { 113 | const cx = this.y * other.z - this.z * other.y; 114 | const cy = this.z * other.x - this.x * other.z; 115 | const cz = this.x * other.y - this.y * other.x; 116 | return new Float32Vector3(cx, cy, cz); 117 | } 118 | normalize() { 119 | const mag = this.magnitude; 120 | if (mag === 0) { 121 | return this; 122 | } 123 | return new Float32Vector3(this.x / mag, this.y / mag, this.z / mag); 124 | } 125 | get xy() { 126 | return new Float32Vector2(this.x, this.y); 127 | } 128 | }; 129 | var Float32Vector4 = class extends Vector4Base { 130 | constructor(x, y, z, w) { 131 | super(); 132 | this._values = new Float32Array([x, y, z, w]); 133 | } 134 | add(other) { 135 | return new Float32Vector4(this.x + other.x, this.y + other.y, this.z + other.z, this.w + other.w); 136 | } 137 | sub(other) { 138 | return new Float32Vector4(this.x - other.x, this.y - other.y, this.z - other.z, this.w - other.w); 139 | } 140 | mulByScalar(scalar) { 141 | return new Float32Vector4(this.x * scalar, this.y * scalar, this.z * scalar, this.w * scalar); 142 | } 143 | get xyz() { 144 | return new Float32Vector3(this.x, this.y, this.z); 145 | } 146 | }; 147 | var Vector2 = Float32Vector2; 148 | var Vector3 = Float32Vector3; 149 | var Vector4 = Float32Vector4; 150 | 151 | // src/quaternion.ts 152 | var Quaternion = class { 153 | constructor(x, y, z, w) { 154 | this._values = new Float32Array([x, y, z, w]); 155 | } 156 | static rotationAround(normalizedAxis, radian) { 157 | const sin = Math.sin(radian / 2); 158 | const cos = Math.cos(radian / 2); 159 | return new Quaternion(normalizedAxis.x * sin, normalizedAxis.y * sin, normalizedAxis.z * sin, cos); 160 | } 161 | normalize() { 162 | const mag = this.magnitude; 163 | if (mag === 0) { 164 | return this; 165 | } 166 | const r = 1 / mag; 167 | return new Quaternion(this.x * r, this.y * r, this.z * r, this.w * r); 168 | } 169 | add(other) { 170 | return new Quaternion(this.x + other.x, this.y + other.y, this.z + other.z, this.w + other.w); 171 | } 172 | mulByScalar(scalar) { 173 | return new Quaternion(this.x * scalar, this.y * scalar, this.z * scalar, this.w * scalar); 174 | } 175 | dot(other) { 176 | return this.x * other.x + this.y * other.y + this.z * other.z + this.w * other.w; 177 | } 178 | slerp(other, t, options = { chooseShorterAngle: true }) { 179 | let dotProd = this.dot(other); 180 | let otherQuaternion = other; 181 | if (dotProd < 0) { 182 | dotProd = -dotProd; 183 | otherQuaternion = other.mulByScalar(-1); 184 | } 185 | const omega = Math.acos(dotProd); 186 | const sinOmega = Math.sin(omega); 187 | const q1 = this.mulByScalar(Math.sin((1 - t) * omega) / sinOmega); 188 | const q2 = otherQuaternion.mulByScalar(Math.sin(t * omega) / sinOmega); 189 | return q1.add(q2); 190 | } 191 | get magnitude() { 192 | return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w); 193 | } 194 | get norm() { 195 | return this.magnitude; 196 | } 197 | get x() { 198 | return this._values[0]; 199 | } 200 | get y() { 201 | return this._values[1]; 202 | } 203 | get z() { 204 | return this._values[2]; 205 | } 206 | get w() { 207 | return this._values[3]; 208 | } 209 | set x(value) { 210 | this._values[0] = value; 211 | } 212 | set y(value) { 213 | this._values[1] = value; 214 | } 215 | set z(value) { 216 | this._values[2] = value; 217 | } 218 | set w(value) { 219 | this._values[3] = value; 220 | } 221 | get values() { 222 | return this._values; 223 | } 224 | toRotationMatrix4() { 225 | const x = this.x; 226 | const y = this.y; 227 | const z = this.z; 228 | const w = this.w; 229 | const m11 = 1 - 2 * y * y - 2 * z * z; 230 | const m12 = 2 * x * y - 2 * w * z; 231 | const m13 = 2 * x * z + 2 * w * y; 232 | const m14 = 0; 233 | const m21 = 2 * x * y + 2 * w * z; 234 | const m22 = 1 - 2 * x * x - 2 * z * z; 235 | const m23 = 2 * y * z - 2 * w * x; 236 | const m24 = 0; 237 | const m31 = 2 * x * z - 2 * w * y; 238 | const m32 = 2 * y * z + 2 * w * x; 239 | const m33 = 1 - 2 * x * x - 2 * y * y; 240 | const m34 = 0; 241 | const m41 = 0; 242 | const m42 = 0; 243 | const m43 = 0; 244 | const m44 = 1; 245 | return new Matrix4x4(m11, m21, m31, m41, m12, m22, m32, m42, m13, m23, m33, m43, m14, m24, m34, m44); 246 | } 247 | toString() { 248 | return `Quaternion(${this.x}, ${this.y}, ${this.z}, ${this.w})`; 249 | } 250 | }; 251 | 252 | // src/matrix.ts 253 | var Matrix2x2 = class { 254 | constructor(m11, m21, m12, m22) { 255 | this._values = new Float32Array([ 256 | m11, 257 | m21, 258 | m12, 259 | m22 260 | ]); 261 | } 262 | static identity() { 263 | return new Matrix2x2(1, 0, 0, 1); 264 | } 265 | get values() { 266 | return this._values; 267 | } 268 | toString() { 269 | return this._values.toString(); 270 | } 271 | }; 272 | var Matrix3x3 = class { 273 | constructor(m11, m21, m31, m12, m22, m32, m13, m23, m33) { 274 | this._values = new Float32Array([ 275 | m11, 276 | m21, 277 | m31, 278 | m12, 279 | m22, 280 | m32, 281 | m13, 282 | m23, 283 | m33 284 | ]); 285 | } 286 | static identity() { 287 | return new Matrix3x3(1, 0, 0, 0, 1, 0, 0, 0, 1); 288 | } 289 | get values() { 290 | return this._values; 291 | } 292 | toString() { 293 | return this._values.toString(); 294 | } 295 | }; 296 | var Matrix4x4 = class { 297 | constructor(m11, m21, m31, m41, m12, m22, m32, m42, m13, m23, m33, m43, m14, m24, m34, m44) { 298 | this._values = new Float32Array([ 299 | m11, 300 | m21, 301 | m31, 302 | m41, 303 | m12, 304 | m22, 305 | m32, 306 | m42, 307 | m13, 308 | m23, 309 | m33, 310 | m43, 311 | m14, 312 | m24, 313 | m34, 314 | m44 315 | ]); 316 | } 317 | static identity() { 318 | return new Matrix4x4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 319 | } 320 | static translation(tx, ty, tz) { 321 | return new Matrix4x4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, tx, ty, tz, 1); 322 | } 323 | static scaling(sx, sy, sz) { 324 | return new Matrix4x4(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, sz, 0, 0, 0, 0, 1); 325 | } 326 | static rotationX(radian) { 327 | const sin = Math.sin(radian); 328 | const cos = Math.cos(radian); 329 | return new Matrix4x4(1, 0, 0, 0, 0, cos, sin, 0, 0, -sin, cos, 0, 0, 0, 0, 1); 330 | } 331 | static rotationY(radian) { 332 | const sin = Math.sin(radian); 333 | const cos = Math.cos(radian); 334 | return new Matrix4x4(cos, 0, -sin, 0, 0, 1, 0, 0, sin, 0, cos, 0, 0, 0, 0, 1); 335 | } 336 | static rotationZ(radian) { 337 | const sin = Math.sin(radian); 338 | const cos = Math.cos(radian); 339 | return new Matrix4x4(cos, sin, 0, 0, -sin, cos, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 340 | } 341 | static rotationAround(normalizedAxis, radian) { 342 | const q = Quaternion.rotationAround(normalizedAxis, radian); 343 | return q.toRotationMatrix4(); 344 | } 345 | static lookAt(cameraPosition, lookAtPosition, cameraUp) { 346 | const zAxis = cameraPosition.sub(lookAtPosition).normalize(); 347 | const xAxis = cameraUp.cross(zAxis).normalize(); 348 | const yAxis = zAxis.cross(xAxis).normalize(); 349 | return new Matrix4x4(xAxis.x, yAxis.x, zAxis.x, 0, xAxis.y, yAxis.y, zAxis.y, 0, xAxis.z, yAxis.z, zAxis.z, 0, -cameraPosition.dot(xAxis), -cameraPosition.dot(yAxis), -cameraPosition.dot(zAxis), 1); 350 | } 351 | static orthographic(argsObject) { 352 | const top = argsObject.top; 353 | const bottom = argsObject.bottom; 354 | const left = argsObject.left; 355 | const right = argsObject.right; 356 | const near = argsObject.near; 357 | const far = argsObject.far; 358 | return new Matrix4x4(2 / (right - left), 0, 0, 0, 0, 2 / (top - bottom), 0, 0, 0, 0, -2 / (far - near), 0, -(right + left) / (right - left), -(top + bottom) / (top - bottom), -(far + near) / (far - near), 1); 359 | } 360 | static frustum(argsObject) { 361 | const top = argsObject.top; 362 | const bottom = argsObject.bottom; 363 | const left = argsObject.left; 364 | const right = argsObject.right; 365 | const near = argsObject.near; 366 | const far = argsObject.far; 367 | return new Matrix4x4(2 * near / (right - left), 0, 0, 0, 0, 2 * near / (top - bottom), 0, 0, (right + left) / (right - left), (top + bottom) / (top - bottom), -(far + near) / (far - near), -1, 0, 0, -2 * far * near / (far - near), 0); 368 | } 369 | static perspective(argsObject) { 370 | const top = argsObject.near * Math.tan(argsObject.fovYRadian * 0.5); 371 | const height = top * 2; 372 | const width = argsObject.aspectRatio * height; 373 | const left = -0.5 * width; 374 | const right = left + width; 375 | const bottom = top - height; 376 | return Matrix4x4.frustum({ 377 | top, 378 | bottom, 379 | left, 380 | right, 381 | near: argsObject.near, 382 | far: argsObject.far 383 | }); 384 | } 385 | mulByMatrix4x4(other) { 386 | const m11 = this._values[0]; 387 | const m12 = this._values[4]; 388 | const m13 = this._values[8]; 389 | const m14 = this._values[12]; 390 | const m21 = this._values[1]; 391 | const m22 = this._values[5]; 392 | const m23 = this._values[9]; 393 | const m24 = this._values[13]; 394 | const m31 = this._values[2]; 395 | const m32 = this._values[6]; 396 | const m33 = this._values[10]; 397 | const m34 = this._values[14]; 398 | const m41 = this._values[3]; 399 | const m42 = this._values[7]; 400 | const m43 = this._values[11]; 401 | const m44 = this._values[15]; 402 | const o11 = other.values[0]; 403 | const o12 = other.values[4]; 404 | const o13 = other.values[8]; 405 | const o14 = other.values[12]; 406 | const o21 = other.values[1]; 407 | const o22 = other.values[5]; 408 | const o23 = other.values[9]; 409 | const o24 = other.values[13]; 410 | const o31 = other.values[2]; 411 | const o32 = other.values[6]; 412 | const o33 = other.values[10]; 413 | const o34 = other.values[14]; 414 | const o41 = other.values[3]; 415 | const o42 = other.values[7]; 416 | const o43 = other.values[11]; 417 | const o44 = other.values[15]; 418 | const p11 = m11 * o11 + m12 * o21 + m13 * o31 + m14 * o41; 419 | const p12 = m11 * o12 + m12 * o22 + m13 * o32 + m14 * o42; 420 | const p13 = m11 * o13 + m12 * o23 + m13 * o33 + m14 * o43; 421 | const p14 = m11 * o14 + m12 * o24 + m13 * o34 + m14 * o44; 422 | const p21 = m21 * o11 + m22 * o21 + m23 * o31 + m24 * o41; 423 | const p22 = m21 * o12 + m22 * o22 + m23 * o32 + m24 * o42; 424 | const p23 = m21 * o13 + m22 * o23 + m23 * o33 + m24 * o43; 425 | const p24 = m21 * o14 + m22 * o24 + m23 * o34 + m24 * o44; 426 | const p31 = m31 * o11 + m32 * o21 + m33 * o31 + m34 * o41; 427 | const p32 = m31 * o12 + m32 * o22 + m33 * o32 + m34 * o42; 428 | const p33 = m31 * o13 + m32 * o23 + m33 * o33 + m34 * o43; 429 | const p34 = m31 * o14 + m32 * o24 + m33 * o34 + m34 * o44; 430 | const p41 = m41 * o11 + m42 * o21 + m43 * o31 + m44 * o41; 431 | const p42 = m41 * o12 + m42 * o22 + m43 * o32 + m44 * o42; 432 | const p43 = m41 * o13 + m42 * o23 + m43 * o33 + m44 * o43; 433 | const p44 = m41 * o14 + m42 * o24 + m43 * o34 + m44 * o44; 434 | return new Matrix4x4(p11, p21, p31, p41, p12, p22, p32, p42, p13, p23, p33, p43, p14, p24, p34, p44); 435 | } 436 | mulByMatrix4(other) { 437 | return this.mulByMatrix4x4(other); 438 | } 439 | translate(tx, ty, tz) { 440 | const t = Matrix4x4.translation(tx, ty, tz); 441 | return this.mulByMatrix4x4(t); 442 | } 443 | scale(sx, sy, sz) { 444 | const s = Matrix4x4.scaling(sx, sy, sz); 445 | return this.mulByMatrix4x4(s); 446 | } 447 | rotateX(radian) { 448 | const rx = Matrix4x4.rotationX(radian); 449 | return this.mulByMatrix4x4(rx); 450 | } 451 | rotateY(radian) { 452 | const ry = Matrix4x4.rotationY(radian); 453 | return this.mulByMatrix4x4(ry); 454 | } 455 | rotateZ(radian) { 456 | const rz = Matrix4x4.rotationZ(radian); 457 | return this.mulByMatrix4x4(rz); 458 | } 459 | rotateAround(normalizedAxis, radian) { 460 | const r = Matrix4x4.rotationAround(normalizedAxis, radian); 461 | return this.mulByMatrix4x4(r); 462 | } 463 | get values() { 464 | return this._values; 465 | } 466 | toString() { 467 | return this._values.toString(); 468 | } 469 | }; 470 | var Matrix2 = Matrix2x2; 471 | var Matrix3 = Matrix3x3; 472 | var Matrix4 = Matrix4x4; 473 | export { 474 | Float32Vector2, 475 | Float32Vector3, 476 | Float32Vector4, 477 | Matrix2, 478 | Matrix2x2, 479 | Matrix3, 480 | Matrix3x3, 481 | Matrix4, 482 | Matrix4x4, 483 | Quaternion, 484 | Vector2, 485 | Vector3, 486 | Vector4 487 | }; 488 | -------------------------------------------------------------------------------- /lib/esm/matrix.d.ts: -------------------------------------------------------------------------------- 1 | import { Float32Vector3 } from './float32vector'; 2 | /** 3 | * An interface for matrices; 4 | */ 5 | export interface Matrix { 6 | /** 7 | * Values of the matrix, that is stored in column major order. 8 | */ 9 | readonly values: Float32Array; 10 | /** 11 | * Returns `values` as string. 12 | * @returns {string} 13 | */ 14 | toString(): string; 15 | } 16 | /** 17 | * 2x2 Matrix of single-precision float numbers. 18 | * 19 | * Values are stored in column major order. 20 | */ 21 | export declare class Matrix2x2 implements Matrix { 22 | protected _values: Float32Array; 23 | constructor(m11: number, m21: number, m12: number, m22: number); 24 | /** 25 | * Returns an identity matrix. 26 | * @returns {Matrix2x2} 27 | */ 28 | static identity(): Matrix2x2; 29 | get values(): Float32Array; 30 | toString(): string; 31 | } 32 | /** 33 | * 3x3 Matrix of single-precision float numbers. 34 | * 35 | * Values are stored in column major order. 36 | */ 37 | export declare class Matrix3x3 implements Matrix { 38 | protected _values: Float32Array; 39 | constructor(m11: number, m21: number, m31: number, m12: number, m22: number, m32: number, m13: number, m23: number, m33: number); 40 | /** 41 | * Returns an identity matrix. 42 | * @returns {Matrix3x3} 43 | */ 44 | static identity(): Matrix3x3; 45 | get values(): Float32Array; 46 | toString(): string; 47 | } 48 | /** 49 | * 4x4 Matrix of single-precision float numbers. 50 | * 51 | * Values are stored in column major order. 52 | */ 53 | export declare class Matrix4x4 implements Matrix { 54 | protected _values: Float32Array; 55 | constructor(m11: number, m21: number, m31: number, m41: number, m12: number, m22: number, m32: number, m42: number, m13: number, m23: number, m33: number, m43: number, m14: number, m24: number, m34: number, m44: number); 56 | /** 57 | * Returns an identity matrix. 58 | * @returns {Matrix4x4} 59 | */ 60 | static identity(): Matrix4x4; 61 | /** 62 | * Returns translation matrix. 63 | * @param {number} tx 64 | * @param {number} ty 65 | * @param {number} tz 66 | * @returns {Matrix4x4} 67 | */ 68 | static translation(tx: number, ty: number, tz: number): Matrix4x4; 69 | /** 70 | * Returns scaling matrix. 71 | * @param {number} sx 72 | * @param {number} sy 73 | * @param {number} sz 74 | * @returns {Matrix4x4} 75 | */ 76 | static scaling(sx: number, sy: number, sz: number): Matrix4x4; 77 | /** 78 | * Returns rotation matrix around x-axis. 79 | * @param {number} radian 80 | * @returns {Matrix4x4} 81 | */ 82 | static rotationX(radian: number): Matrix4x4; 83 | /** 84 | * Returns rotation matrix around y-axis. 85 | * @param {number} radian 86 | * @returns {Matrix4x4} 87 | */ 88 | static rotationY(radian: number): Matrix4x4; 89 | /** 90 | * Returns rotation matrix around z-axis. 91 | * @param {number} radian 92 | * @returns {Matrix4x4} 93 | */ 94 | static rotationZ(radian: number): Matrix4x4; 95 | /** 96 | * Returns rotation matrix around `normalizedAxis`. `normalizedAxis` must be normalized. 97 | * @param {Float32Vector3} normalizedAxis 98 | * @param {number} radian 99 | * @returns {Matrix4x4} 100 | */ 101 | static rotationAround(normalizedAxis: Float32Vector3, radian: number): Matrix4x4; 102 | /** 103 | * Returns "look at" matrix. 104 | * @param {Float32Vector3} cameraPosition 105 | * @param {Float32Vector3} lookAtPosition 106 | * @param {Float32Vector3} cameraUp 107 | * @returns {Matrix4x4} 108 | */ 109 | static lookAt(cameraPosition: Float32Vector3, lookAtPosition: Float32Vector3, cameraUp: Float32Vector3): Matrix4x4; 110 | /** 111 | * Returns an orthographic projection matrix. 112 | * @param {{top: number; bottom: number; left: number; right: number; near: number; far: number}} argsObject 113 | * @returns {Matrix4x4} 114 | */ 115 | static orthographic(argsObject: { 116 | top: number; 117 | bottom: number; 118 | left: number; 119 | right: number; 120 | near: number; 121 | far: number; 122 | }): Matrix4x4; 123 | /** 124 | * Returns a frustrum projection matrix. 125 | * @param {{top: number; bottom: number; left: number; right: number; near: number; far: number}} argsObject 126 | * @returns {Matrix4x4} 127 | */ 128 | static frustum(argsObject: { 129 | top: number; 130 | bottom: number; 131 | left: number; 132 | right: number; 133 | near: number; 134 | far: number; 135 | }): Matrix4x4; 136 | /** 137 | * Returns a perspective projection matrix. 138 | * @param {{fovY: number; aspect: number; near: number; far: number}} argsObject 139 | * @returns {Matrix4x4} 140 | */ 141 | static perspective(argsObject: { 142 | fovYRadian: number; 143 | aspectRatio: number; 144 | near: number; 145 | far: number; 146 | }): Matrix4x4; 147 | /** 148 | * Multiply by `other` matrix and returns a product. 149 | * 150 | * This method does not mutate the matrix. 151 | * @param {Matrix4x4} other 152 | * @returns {Matrix4x4} 153 | */ 154 | mulByMatrix4x4(other: Matrix4x4): Matrix4x4; 155 | /** 156 | * An alias for `mulByMatrix4x4`. 157 | * @param {Matrix4x4} other 158 | * @returns {Matrix4x4} 159 | */ 160 | mulByMatrix4(other: Matrix4x4): Matrix4x4; 161 | /** 162 | * Translate the matrix and returns new `Matrix4x4`. 163 | * 164 | * This method does not mutate the matrix. 165 | * @param {number} tx 166 | * @param {number} ty 167 | * @param {number} tz 168 | * @returns {Matrix4x4} 169 | */ 170 | translate(tx: number, ty: number, tz: number): Matrix4x4; 171 | /** 172 | * Scale the matrix and returns new `Matrix4x4`. 173 | * @param {number} sx 174 | * @param {number} sy 175 | * @param {number} sz 176 | * @returns {Matrix4x4} 177 | */ 178 | scale(sx: number, sy: number, sz: number): Matrix4x4; 179 | /** 180 | * Rotate the matrix around x-axis and returns new `Matrix4x4`. 181 | * 182 | * This method does not mutate the matrix. 183 | * @param {number} radian 184 | * @returns {Matrix4x4} 185 | */ 186 | rotateX(radian: number): Matrix4x4; 187 | /** 188 | * Rotate the matrix around y-axis and returns new `Matrix4x4`. 189 | * 190 | * This method does not mutate the matrix. 191 | * @param {number} radian 192 | * @returns {Matrix4x4} 193 | */ 194 | rotateY(radian: number): Matrix4x4; 195 | /** 196 | * Rotate the matrix around z-axis and returns new `Matrix4x4`. 197 | * 198 | * This method does not mutate the matrix. 199 | * @param {number} radian 200 | * @returns {Matrix4x4} 201 | */ 202 | rotateZ(radian: number): Matrix4x4; 203 | /** 204 | * Rotate the matrix around the `normalizedAxis` and return new Matrix4x4. 205 | * 206 | * This method does not mutate the matrix. 207 | * @param {Float32Vector3} normalizedAxis 208 | * @param {number} radian 209 | * @returns {Matrix4x4} 210 | */ 211 | rotateAround(normalizedAxis: Float32Vector3, radian: number): Matrix4x4; 212 | get values(): Float32Array; 213 | toString(): string; 214 | } 215 | /** 216 | * An alias for `Matrix2x2`. 217 | * @type {Matrix2x2} 218 | */ 219 | export declare const Matrix2: typeof Matrix2x2; 220 | /** 221 | * An alias for `Matrix3x3`. 222 | * @type {Matrix3x3} 223 | */ 224 | export declare const Matrix3: typeof Matrix3x3; 225 | /** 226 | * An alias for `Matrix4x4`. 227 | * @type {Matrix4x4} 228 | */ 229 | export declare const Matrix4: typeof Matrix4x4; 230 | -------------------------------------------------------------------------------- /lib/esm/matrix.js: -------------------------------------------------------------------------------- 1 | // src/quaternion.ts 2 | var Quaternion = class { 3 | constructor(x, y, z, w) { 4 | this._values = new Float32Array([x, y, z, w]); 5 | } 6 | static rotationAround(normalizedAxis, radian) { 7 | const sin = Math.sin(radian / 2); 8 | const cos = Math.cos(radian / 2); 9 | return new Quaternion(normalizedAxis.x * sin, normalizedAxis.y * sin, normalizedAxis.z * sin, cos); 10 | } 11 | normalize() { 12 | const mag = this.magnitude; 13 | if (mag === 0) { 14 | return this; 15 | } 16 | const r = 1 / mag; 17 | return new Quaternion(this.x * r, this.y * r, this.z * r, this.w * r); 18 | } 19 | add(other) { 20 | return new Quaternion(this.x + other.x, this.y + other.y, this.z + other.z, this.w + other.w); 21 | } 22 | mulByScalar(scalar) { 23 | return new Quaternion(this.x * scalar, this.y * scalar, this.z * scalar, this.w * scalar); 24 | } 25 | dot(other) { 26 | return this.x * other.x + this.y * other.y + this.z * other.z + this.w * other.w; 27 | } 28 | slerp(other, t, options = { chooseShorterAngle: true }) { 29 | let dotProd = this.dot(other); 30 | let otherQuaternion = other; 31 | if (dotProd < 0) { 32 | dotProd = -dotProd; 33 | otherQuaternion = other.mulByScalar(-1); 34 | } 35 | const omega = Math.acos(dotProd); 36 | const sinOmega = Math.sin(omega); 37 | const q1 = this.mulByScalar(Math.sin((1 - t) * omega) / sinOmega); 38 | const q2 = otherQuaternion.mulByScalar(Math.sin(t * omega) / sinOmega); 39 | return q1.add(q2); 40 | } 41 | get magnitude() { 42 | return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w); 43 | } 44 | get norm() { 45 | return this.magnitude; 46 | } 47 | get x() { 48 | return this._values[0]; 49 | } 50 | get y() { 51 | return this._values[1]; 52 | } 53 | get z() { 54 | return this._values[2]; 55 | } 56 | get w() { 57 | return this._values[3]; 58 | } 59 | set x(value) { 60 | this._values[0] = value; 61 | } 62 | set y(value) { 63 | this._values[1] = value; 64 | } 65 | set z(value) { 66 | this._values[2] = value; 67 | } 68 | set w(value) { 69 | this._values[3] = value; 70 | } 71 | get values() { 72 | return this._values; 73 | } 74 | toRotationMatrix4() { 75 | const x = this.x; 76 | const y = this.y; 77 | const z = this.z; 78 | const w = this.w; 79 | const m11 = 1 - 2 * y * y - 2 * z * z; 80 | const m12 = 2 * x * y - 2 * w * z; 81 | const m13 = 2 * x * z + 2 * w * y; 82 | const m14 = 0; 83 | const m21 = 2 * x * y + 2 * w * z; 84 | const m22 = 1 - 2 * x * x - 2 * z * z; 85 | const m23 = 2 * y * z - 2 * w * x; 86 | const m24 = 0; 87 | const m31 = 2 * x * z - 2 * w * y; 88 | const m32 = 2 * y * z + 2 * w * x; 89 | const m33 = 1 - 2 * x * x - 2 * y * y; 90 | const m34 = 0; 91 | const m41 = 0; 92 | const m42 = 0; 93 | const m43 = 0; 94 | const m44 = 1; 95 | return new Matrix4x4(m11, m21, m31, m41, m12, m22, m32, m42, m13, m23, m33, m43, m14, m24, m34, m44); 96 | } 97 | toString() { 98 | return `Quaternion(${this.x}, ${this.y}, ${this.z}, ${this.w})`; 99 | } 100 | }; 101 | 102 | // src/matrix.ts 103 | var Matrix2x2 = class { 104 | constructor(m11, m21, m12, m22) { 105 | this._values = new Float32Array([ 106 | m11, 107 | m21, 108 | m12, 109 | m22 110 | ]); 111 | } 112 | static identity() { 113 | return new Matrix2x2(1, 0, 0, 1); 114 | } 115 | get values() { 116 | return this._values; 117 | } 118 | toString() { 119 | return this._values.toString(); 120 | } 121 | }; 122 | var Matrix3x3 = class { 123 | constructor(m11, m21, m31, m12, m22, m32, m13, m23, m33) { 124 | this._values = new Float32Array([ 125 | m11, 126 | m21, 127 | m31, 128 | m12, 129 | m22, 130 | m32, 131 | m13, 132 | m23, 133 | m33 134 | ]); 135 | } 136 | static identity() { 137 | return new Matrix3x3(1, 0, 0, 0, 1, 0, 0, 0, 1); 138 | } 139 | get values() { 140 | return this._values; 141 | } 142 | toString() { 143 | return this._values.toString(); 144 | } 145 | }; 146 | var Matrix4x4 = class { 147 | constructor(m11, m21, m31, m41, m12, m22, m32, m42, m13, m23, m33, m43, m14, m24, m34, m44) { 148 | this._values = new Float32Array([ 149 | m11, 150 | m21, 151 | m31, 152 | m41, 153 | m12, 154 | m22, 155 | m32, 156 | m42, 157 | m13, 158 | m23, 159 | m33, 160 | m43, 161 | m14, 162 | m24, 163 | m34, 164 | m44 165 | ]); 166 | } 167 | static identity() { 168 | return new Matrix4x4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 169 | } 170 | static translation(tx, ty, tz) { 171 | return new Matrix4x4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, tx, ty, tz, 1); 172 | } 173 | static scaling(sx, sy, sz) { 174 | return new Matrix4x4(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, sz, 0, 0, 0, 0, 1); 175 | } 176 | static rotationX(radian) { 177 | const sin = Math.sin(radian); 178 | const cos = Math.cos(radian); 179 | return new Matrix4x4(1, 0, 0, 0, 0, cos, sin, 0, 0, -sin, cos, 0, 0, 0, 0, 1); 180 | } 181 | static rotationY(radian) { 182 | const sin = Math.sin(radian); 183 | const cos = Math.cos(radian); 184 | return new Matrix4x4(cos, 0, -sin, 0, 0, 1, 0, 0, sin, 0, cos, 0, 0, 0, 0, 1); 185 | } 186 | static rotationZ(radian) { 187 | const sin = Math.sin(radian); 188 | const cos = Math.cos(radian); 189 | return new Matrix4x4(cos, sin, 0, 0, -sin, cos, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 190 | } 191 | static rotationAround(normalizedAxis, radian) { 192 | const q = Quaternion.rotationAround(normalizedAxis, radian); 193 | return q.toRotationMatrix4(); 194 | } 195 | static lookAt(cameraPosition, lookAtPosition, cameraUp) { 196 | const zAxis = cameraPosition.sub(lookAtPosition).normalize(); 197 | const xAxis = cameraUp.cross(zAxis).normalize(); 198 | const yAxis = zAxis.cross(xAxis).normalize(); 199 | return new Matrix4x4(xAxis.x, yAxis.x, zAxis.x, 0, xAxis.y, yAxis.y, zAxis.y, 0, xAxis.z, yAxis.z, zAxis.z, 0, -cameraPosition.dot(xAxis), -cameraPosition.dot(yAxis), -cameraPosition.dot(zAxis), 1); 200 | } 201 | static orthographic(argsObject) { 202 | const top = argsObject.top; 203 | const bottom = argsObject.bottom; 204 | const left = argsObject.left; 205 | const right = argsObject.right; 206 | const near = argsObject.near; 207 | const far = argsObject.far; 208 | return new Matrix4x4(2 / (right - left), 0, 0, 0, 0, 2 / (top - bottom), 0, 0, 0, 0, -2 / (far - near), 0, -(right + left) / (right - left), -(top + bottom) / (top - bottom), -(far + near) / (far - near), 1); 209 | } 210 | static frustum(argsObject) { 211 | const top = argsObject.top; 212 | const bottom = argsObject.bottom; 213 | const left = argsObject.left; 214 | const right = argsObject.right; 215 | const near = argsObject.near; 216 | const far = argsObject.far; 217 | return new Matrix4x4(2 * near / (right - left), 0, 0, 0, 0, 2 * near / (top - bottom), 0, 0, (right + left) / (right - left), (top + bottom) / (top - bottom), -(far + near) / (far - near), -1, 0, 0, -2 * far * near / (far - near), 0); 218 | } 219 | static perspective(argsObject) { 220 | const top = argsObject.near * Math.tan(argsObject.fovYRadian * 0.5); 221 | const height = top * 2; 222 | const width = argsObject.aspectRatio * height; 223 | const left = -0.5 * width; 224 | const right = left + width; 225 | const bottom = top - height; 226 | return Matrix4x4.frustum({ 227 | top, 228 | bottom, 229 | left, 230 | right, 231 | near: argsObject.near, 232 | far: argsObject.far 233 | }); 234 | } 235 | mulByMatrix4x4(other) { 236 | const m11 = this._values[0]; 237 | const m12 = this._values[4]; 238 | const m13 = this._values[8]; 239 | const m14 = this._values[12]; 240 | const m21 = this._values[1]; 241 | const m22 = this._values[5]; 242 | const m23 = this._values[9]; 243 | const m24 = this._values[13]; 244 | const m31 = this._values[2]; 245 | const m32 = this._values[6]; 246 | const m33 = this._values[10]; 247 | const m34 = this._values[14]; 248 | const m41 = this._values[3]; 249 | const m42 = this._values[7]; 250 | const m43 = this._values[11]; 251 | const m44 = this._values[15]; 252 | const o11 = other.values[0]; 253 | const o12 = other.values[4]; 254 | const o13 = other.values[8]; 255 | const o14 = other.values[12]; 256 | const o21 = other.values[1]; 257 | const o22 = other.values[5]; 258 | const o23 = other.values[9]; 259 | const o24 = other.values[13]; 260 | const o31 = other.values[2]; 261 | const o32 = other.values[6]; 262 | const o33 = other.values[10]; 263 | const o34 = other.values[14]; 264 | const o41 = other.values[3]; 265 | const o42 = other.values[7]; 266 | const o43 = other.values[11]; 267 | const o44 = other.values[15]; 268 | const p11 = m11 * o11 + m12 * o21 + m13 * o31 + m14 * o41; 269 | const p12 = m11 * o12 + m12 * o22 + m13 * o32 + m14 * o42; 270 | const p13 = m11 * o13 + m12 * o23 + m13 * o33 + m14 * o43; 271 | const p14 = m11 * o14 + m12 * o24 + m13 * o34 + m14 * o44; 272 | const p21 = m21 * o11 + m22 * o21 + m23 * o31 + m24 * o41; 273 | const p22 = m21 * o12 + m22 * o22 + m23 * o32 + m24 * o42; 274 | const p23 = m21 * o13 + m22 * o23 + m23 * o33 + m24 * o43; 275 | const p24 = m21 * o14 + m22 * o24 + m23 * o34 + m24 * o44; 276 | const p31 = m31 * o11 + m32 * o21 + m33 * o31 + m34 * o41; 277 | const p32 = m31 * o12 + m32 * o22 + m33 * o32 + m34 * o42; 278 | const p33 = m31 * o13 + m32 * o23 + m33 * o33 + m34 * o43; 279 | const p34 = m31 * o14 + m32 * o24 + m33 * o34 + m34 * o44; 280 | const p41 = m41 * o11 + m42 * o21 + m43 * o31 + m44 * o41; 281 | const p42 = m41 * o12 + m42 * o22 + m43 * o32 + m44 * o42; 282 | const p43 = m41 * o13 + m42 * o23 + m43 * o33 + m44 * o43; 283 | const p44 = m41 * o14 + m42 * o24 + m43 * o34 + m44 * o44; 284 | return new Matrix4x4(p11, p21, p31, p41, p12, p22, p32, p42, p13, p23, p33, p43, p14, p24, p34, p44); 285 | } 286 | mulByMatrix4(other) { 287 | return this.mulByMatrix4x4(other); 288 | } 289 | translate(tx, ty, tz) { 290 | const t = Matrix4x4.translation(tx, ty, tz); 291 | return this.mulByMatrix4x4(t); 292 | } 293 | scale(sx, sy, sz) { 294 | const s = Matrix4x4.scaling(sx, sy, sz); 295 | return this.mulByMatrix4x4(s); 296 | } 297 | rotateX(radian) { 298 | const rx = Matrix4x4.rotationX(radian); 299 | return this.mulByMatrix4x4(rx); 300 | } 301 | rotateY(radian) { 302 | const ry = Matrix4x4.rotationY(radian); 303 | return this.mulByMatrix4x4(ry); 304 | } 305 | rotateZ(radian) { 306 | const rz = Matrix4x4.rotationZ(radian); 307 | return this.mulByMatrix4x4(rz); 308 | } 309 | rotateAround(normalizedAxis, radian) { 310 | const r = Matrix4x4.rotationAround(normalizedAxis, radian); 311 | return this.mulByMatrix4x4(r); 312 | } 313 | get values() { 314 | return this._values; 315 | } 316 | toString() { 317 | return this._values.toString(); 318 | } 319 | }; 320 | var Matrix2 = Matrix2x2; 321 | var Matrix3 = Matrix3x3; 322 | var Matrix4 = Matrix4x4; 323 | export { 324 | Matrix2, 325 | Matrix2x2, 326 | Matrix3, 327 | Matrix3x3, 328 | Matrix4, 329 | Matrix4x4 330 | }; 331 | -------------------------------------------------------------------------------- /lib/esm/quaternion.d.ts: -------------------------------------------------------------------------------- 1 | import { Float32Vector3 } from './float32vector'; 2 | import { Matrix4x4 } from './matrix'; 3 | /** 4 | * Quaternion which is 4-dimensional complex number. 5 | * See [Wikipedia](https://en.wikipedia.org/wiki/Quaternion). 6 | */ 7 | export declare class Quaternion { 8 | protected _values: Float32Array; 9 | constructor(x: number, y: number, z: number, w: number); 10 | /** 11 | * Create a rotation quaternion around `normalizedAxis`. 12 | * `normalizedAxis` must be normalized. 13 | * @param {Float32Vector3} normalizedAxis 14 | * @param {number} radian 15 | * @returns {Quaternion} 16 | */ 17 | static rotationAround(normalizedAxis: Float32Vector3, radian: number): Quaternion; 18 | /** 19 | * Returns a normalized quaternion. 20 | * @returns {Quaternion} 21 | */ 22 | normalize(): Quaternion; 23 | /** 24 | * Adds the `other` to the quaternion and returns the sum. 25 | * 26 | * This method does not mutate the quaternion. 27 | * @param {Quaternion} other 28 | * @returns {Quaternion} 29 | */ 30 | add(other: Quaternion): Quaternion; 31 | /** 32 | * Multiplies the quaternion by `scalar` and returns the product. 33 | * 34 | * This method does not mutate the quaternion. 35 | * @param {number} scalar 36 | * @returns {Quaternion} 37 | */ 38 | mulByScalar(scalar: number): Quaternion; 39 | /** 40 | * Calculates dot product. 41 | * @param {Quaternion} other 42 | * @returns {number} 43 | */ 44 | dot(other: Quaternion): number; 45 | /** 46 | * Calculates spherical linear interpolation(also known as Slerp) and returns new `Quaternion` between the quaternion and the other. 47 | * @param {Quaternion} other 48 | * @param {number} t 0.0 <= t <= 1.0 49 | * @param {{chooseShorterAngle: boolean}} options Does not work currently. slerp chooses shorter angle regardless of this value. 50 | * @returns {Quaternion} 51 | */ 52 | slerp(other: Quaternion, t: number, options?: { 53 | chooseShorterAngle: boolean; 54 | }): Quaternion; 55 | /** 56 | * Calc magnitude of the quaternion. 57 | * @returns {number} 58 | */ 59 | get magnitude(): number; 60 | /** 61 | * Calc norm of the quaternion. 62 | * An alias for `magnitude`. 63 | * @returns {number} 64 | */ 65 | get norm(): number; 66 | /** 67 | * Returns x value of the vector. 68 | * @returns {number} 69 | */ 70 | get x(): number; 71 | /** 72 | * Returns y value of the vector. 73 | * @returns {number} 74 | */ 75 | get y(): number; 76 | /** 77 | * Returns z value of the vector. 78 | * @returns {number} 79 | */ 80 | get z(): number; 81 | /** 82 | * Returns w value of the vector. 83 | * @returns {number} 84 | */ 85 | get w(): number; 86 | /** 87 | * Set the `value` as new x. 88 | * @param {number} value 89 | */ 90 | set x(value: number); 91 | /** 92 | * Set the `value` as new y. 93 | * @param {number} value 94 | */ 95 | set y(value: number); 96 | /** 97 | * Set the `value` as new z. 98 | * @param {number} value 99 | */ 100 | set z(value: number); 101 | /** 102 | * Set the `value` as new w. 103 | * @param {number} value 104 | */ 105 | set w(value: number); 106 | /** 107 | * Returns values of the quaternion. 108 | * @returns {Float32Array} 109 | */ 110 | get values(): Float32Array; 111 | /** 112 | * Convert the quaternion to a rotation matrix. 113 | * @returns {Matrix4x4} 114 | */ 115 | toRotationMatrix4(): Matrix4x4; 116 | /** 117 | * Returns values as `String`. 118 | * @returns {string} 119 | */ 120 | toString(): string; 121 | } 122 | -------------------------------------------------------------------------------- /lib/esm/quaternion.js: -------------------------------------------------------------------------------- 1 | // src/matrix.ts 2 | var Matrix4x4 = class { 3 | constructor(m11, m21, m31, m41, m12, m22, m32, m42, m13, m23, m33, m43, m14, m24, m34, m44) { 4 | this._values = new Float32Array([ 5 | m11, 6 | m21, 7 | m31, 8 | m41, 9 | m12, 10 | m22, 11 | m32, 12 | m42, 13 | m13, 14 | m23, 15 | m33, 16 | m43, 17 | m14, 18 | m24, 19 | m34, 20 | m44 21 | ]); 22 | } 23 | static identity() { 24 | return new Matrix4x4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 25 | } 26 | static translation(tx, ty, tz) { 27 | return new Matrix4x4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, tx, ty, tz, 1); 28 | } 29 | static scaling(sx, sy, sz) { 30 | return new Matrix4x4(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, sz, 0, 0, 0, 0, 1); 31 | } 32 | static rotationX(radian) { 33 | const sin = Math.sin(radian); 34 | const cos = Math.cos(radian); 35 | return new Matrix4x4(1, 0, 0, 0, 0, cos, sin, 0, 0, -sin, cos, 0, 0, 0, 0, 1); 36 | } 37 | static rotationY(radian) { 38 | const sin = Math.sin(radian); 39 | const cos = Math.cos(radian); 40 | return new Matrix4x4(cos, 0, -sin, 0, 0, 1, 0, 0, sin, 0, cos, 0, 0, 0, 0, 1); 41 | } 42 | static rotationZ(radian) { 43 | const sin = Math.sin(radian); 44 | const cos = Math.cos(radian); 45 | return new Matrix4x4(cos, sin, 0, 0, -sin, cos, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 46 | } 47 | static rotationAround(normalizedAxis, radian) { 48 | const q = Quaternion.rotationAround(normalizedAxis, radian); 49 | return q.toRotationMatrix4(); 50 | } 51 | static lookAt(cameraPosition, lookAtPosition, cameraUp) { 52 | const zAxis = cameraPosition.sub(lookAtPosition).normalize(); 53 | const xAxis = cameraUp.cross(zAxis).normalize(); 54 | const yAxis = zAxis.cross(xAxis).normalize(); 55 | return new Matrix4x4(xAxis.x, yAxis.x, zAxis.x, 0, xAxis.y, yAxis.y, zAxis.y, 0, xAxis.z, yAxis.z, zAxis.z, 0, -cameraPosition.dot(xAxis), -cameraPosition.dot(yAxis), -cameraPosition.dot(zAxis), 1); 56 | } 57 | static orthographic(argsObject) { 58 | const top = argsObject.top; 59 | const bottom = argsObject.bottom; 60 | const left = argsObject.left; 61 | const right = argsObject.right; 62 | const near = argsObject.near; 63 | const far = argsObject.far; 64 | return new Matrix4x4(2 / (right - left), 0, 0, 0, 0, 2 / (top - bottom), 0, 0, 0, 0, -2 / (far - near), 0, -(right + left) / (right - left), -(top + bottom) / (top - bottom), -(far + near) / (far - near), 1); 65 | } 66 | static frustum(argsObject) { 67 | const top = argsObject.top; 68 | const bottom = argsObject.bottom; 69 | const left = argsObject.left; 70 | const right = argsObject.right; 71 | const near = argsObject.near; 72 | const far = argsObject.far; 73 | return new Matrix4x4(2 * near / (right - left), 0, 0, 0, 0, 2 * near / (top - bottom), 0, 0, (right + left) / (right - left), (top + bottom) / (top - bottom), -(far + near) / (far - near), -1, 0, 0, -2 * far * near / (far - near), 0); 74 | } 75 | static perspective(argsObject) { 76 | const top = argsObject.near * Math.tan(argsObject.fovYRadian * 0.5); 77 | const height = top * 2; 78 | const width = argsObject.aspectRatio * height; 79 | const left = -0.5 * width; 80 | const right = left + width; 81 | const bottom = top - height; 82 | return Matrix4x4.frustum({ 83 | top, 84 | bottom, 85 | left, 86 | right, 87 | near: argsObject.near, 88 | far: argsObject.far 89 | }); 90 | } 91 | mulByMatrix4x4(other) { 92 | const m11 = this._values[0]; 93 | const m12 = this._values[4]; 94 | const m13 = this._values[8]; 95 | const m14 = this._values[12]; 96 | const m21 = this._values[1]; 97 | const m22 = this._values[5]; 98 | const m23 = this._values[9]; 99 | const m24 = this._values[13]; 100 | const m31 = this._values[2]; 101 | const m32 = this._values[6]; 102 | const m33 = this._values[10]; 103 | const m34 = this._values[14]; 104 | const m41 = this._values[3]; 105 | const m42 = this._values[7]; 106 | const m43 = this._values[11]; 107 | const m44 = this._values[15]; 108 | const o11 = other.values[0]; 109 | const o12 = other.values[4]; 110 | const o13 = other.values[8]; 111 | const o14 = other.values[12]; 112 | const o21 = other.values[1]; 113 | const o22 = other.values[5]; 114 | const o23 = other.values[9]; 115 | const o24 = other.values[13]; 116 | const o31 = other.values[2]; 117 | const o32 = other.values[6]; 118 | const o33 = other.values[10]; 119 | const o34 = other.values[14]; 120 | const o41 = other.values[3]; 121 | const o42 = other.values[7]; 122 | const o43 = other.values[11]; 123 | const o44 = other.values[15]; 124 | const p11 = m11 * o11 + m12 * o21 + m13 * o31 + m14 * o41; 125 | const p12 = m11 * o12 + m12 * o22 + m13 * o32 + m14 * o42; 126 | const p13 = m11 * o13 + m12 * o23 + m13 * o33 + m14 * o43; 127 | const p14 = m11 * o14 + m12 * o24 + m13 * o34 + m14 * o44; 128 | const p21 = m21 * o11 + m22 * o21 + m23 * o31 + m24 * o41; 129 | const p22 = m21 * o12 + m22 * o22 + m23 * o32 + m24 * o42; 130 | const p23 = m21 * o13 + m22 * o23 + m23 * o33 + m24 * o43; 131 | const p24 = m21 * o14 + m22 * o24 + m23 * o34 + m24 * o44; 132 | const p31 = m31 * o11 + m32 * o21 + m33 * o31 + m34 * o41; 133 | const p32 = m31 * o12 + m32 * o22 + m33 * o32 + m34 * o42; 134 | const p33 = m31 * o13 + m32 * o23 + m33 * o33 + m34 * o43; 135 | const p34 = m31 * o14 + m32 * o24 + m33 * o34 + m34 * o44; 136 | const p41 = m41 * o11 + m42 * o21 + m43 * o31 + m44 * o41; 137 | const p42 = m41 * o12 + m42 * o22 + m43 * o32 + m44 * o42; 138 | const p43 = m41 * o13 + m42 * o23 + m43 * o33 + m44 * o43; 139 | const p44 = m41 * o14 + m42 * o24 + m43 * o34 + m44 * o44; 140 | return new Matrix4x4(p11, p21, p31, p41, p12, p22, p32, p42, p13, p23, p33, p43, p14, p24, p34, p44); 141 | } 142 | mulByMatrix4(other) { 143 | return this.mulByMatrix4x4(other); 144 | } 145 | translate(tx, ty, tz) { 146 | const t = Matrix4x4.translation(tx, ty, tz); 147 | return this.mulByMatrix4x4(t); 148 | } 149 | scale(sx, sy, sz) { 150 | const s = Matrix4x4.scaling(sx, sy, sz); 151 | return this.mulByMatrix4x4(s); 152 | } 153 | rotateX(radian) { 154 | const rx = Matrix4x4.rotationX(radian); 155 | return this.mulByMatrix4x4(rx); 156 | } 157 | rotateY(radian) { 158 | const ry = Matrix4x4.rotationY(radian); 159 | return this.mulByMatrix4x4(ry); 160 | } 161 | rotateZ(radian) { 162 | const rz = Matrix4x4.rotationZ(radian); 163 | return this.mulByMatrix4x4(rz); 164 | } 165 | rotateAround(normalizedAxis, radian) { 166 | const r = Matrix4x4.rotationAround(normalizedAxis, radian); 167 | return this.mulByMatrix4x4(r); 168 | } 169 | get values() { 170 | return this._values; 171 | } 172 | toString() { 173 | return this._values.toString(); 174 | } 175 | }; 176 | 177 | // src/quaternion.ts 178 | var Quaternion = class { 179 | constructor(x, y, z, w) { 180 | this._values = new Float32Array([x, y, z, w]); 181 | } 182 | static rotationAround(normalizedAxis, radian) { 183 | const sin = Math.sin(radian / 2); 184 | const cos = Math.cos(radian / 2); 185 | return new Quaternion(normalizedAxis.x * sin, normalizedAxis.y * sin, normalizedAxis.z * sin, cos); 186 | } 187 | normalize() { 188 | const mag = this.magnitude; 189 | if (mag === 0) { 190 | return this; 191 | } 192 | const r = 1 / mag; 193 | return new Quaternion(this.x * r, this.y * r, this.z * r, this.w * r); 194 | } 195 | add(other) { 196 | return new Quaternion(this.x + other.x, this.y + other.y, this.z + other.z, this.w + other.w); 197 | } 198 | mulByScalar(scalar) { 199 | return new Quaternion(this.x * scalar, this.y * scalar, this.z * scalar, this.w * scalar); 200 | } 201 | dot(other) { 202 | return this.x * other.x + this.y * other.y + this.z * other.z + this.w * other.w; 203 | } 204 | slerp(other, t, options = { chooseShorterAngle: true }) { 205 | let dotProd = this.dot(other); 206 | let otherQuaternion = other; 207 | if (dotProd < 0) { 208 | dotProd = -dotProd; 209 | otherQuaternion = other.mulByScalar(-1); 210 | } 211 | const omega = Math.acos(dotProd); 212 | const sinOmega = Math.sin(omega); 213 | const q1 = this.mulByScalar(Math.sin((1 - t) * omega) / sinOmega); 214 | const q2 = otherQuaternion.mulByScalar(Math.sin(t * omega) / sinOmega); 215 | return q1.add(q2); 216 | } 217 | get magnitude() { 218 | return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w); 219 | } 220 | get norm() { 221 | return this.magnitude; 222 | } 223 | get x() { 224 | return this._values[0]; 225 | } 226 | get y() { 227 | return this._values[1]; 228 | } 229 | get z() { 230 | return this._values[2]; 231 | } 232 | get w() { 233 | return this._values[3]; 234 | } 235 | set x(value) { 236 | this._values[0] = value; 237 | } 238 | set y(value) { 239 | this._values[1] = value; 240 | } 241 | set z(value) { 242 | this._values[2] = value; 243 | } 244 | set w(value) { 245 | this._values[3] = value; 246 | } 247 | get values() { 248 | return this._values; 249 | } 250 | toRotationMatrix4() { 251 | const x = this.x; 252 | const y = this.y; 253 | const z = this.z; 254 | const w = this.w; 255 | const m11 = 1 - 2 * y * y - 2 * z * z; 256 | const m12 = 2 * x * y - 2 * w * z; 257 | const m13 = 2 * x * z + 2 * w * y; 258 | const m14 = 0; 259 | const m21 = 2 * x * y + 2 * w * z; 260 | const m22 = 1 - 2 * x * x - 2 * z * z; 261 | const m23 = 2 * y * z - 2 * w * x; 262 | const m24 = 0; 263 | const m31 = 2 * x * z - 2 * w * y; 264 | const m32 = 2 * y * z + 2 * w * x; 265 | const m33 = 1 - 2 * x * x - 2 * y * y; 266 | const m34 = 0; 267 | const m41 = 0; 268 | const m42 = 0; 269 | const m43 = 0; 270 | const m44 = 1; 271 | return new Matrix4x4(m11, m21, m31, m41, m12, m22, m32, m42, m13, m23, m33, m43, m14, m24, m34, m44); 272 | } 273 | toString() { 274 | return `Quaternion(${this.x}, ${this.y}, ${this.z}, ${this.w})`; 275 | } 276 | }; 277 | export { 278 | Quaternion 279 | }; 280 | -------------------------------------------------------------------------------- /lib/esm/vector_base.d.ts: -------------------------------------------------------------------------------- 1 | export declare type TypedArrayLike = Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array; 2 | /** 3 | * An interface for vectors. 4 | */ 5 | export interface Vector { 6 | /** 7 | * Returns values of the vector. 8 | * @returns {T} 9 | */ 10 | readonly values: T; 11 | /** 12 | * Returns magnitude of the vector. 13 | */ 14 | readonly magnitude: number; 15 | /** 16 | * Returns `values` as a string. 17 | * @returns {string} 18 | */ 19 | toString(): string; 20 | } 21 | /** 22 | * An abstract class for vectors. 23 | */ 24 | export declare abstract class VectorBase implements Vector { 25 | /** 26 | * Values that the vector contains. 27 | */ 28 | protected _values: T; 29 | get values(): T; 30 | get magnitude(): number; 31 | toString(): string; 32 | } 33 | /** 34 | * A base abstract class for 2-dimensional vectors. 35 | */ 36 | export declare abstract class Vector2Base extends VectorBase { 37 | /** 38 | * Returns x value of the vector. 39 | * @returns {number} 40 | */ 41 | get x(): number; 42 | /** 43 | * Returns y value of the vector. 44 | * @returns {number} 45 | */ 46 | get y(): number; 47 | /** 48 | * Set the `value` as new x. 49 | * @param {number} value 50 | */ 51 | set x(value: number); 52 | /** 53 | * Set the `value` as new y. 54 | * @param {number} value 55 | */ 56 | set y(value: number); 57 | } 58 | /** 59 | * A base abstract class for 3-dimensional vectors. 60 | */ 61 | export declare abstract class Vector3Base extends VectorBase { 62 | /** 63 | * Returns x value of the vector. 64 | * @returns {number} 65 | */ 66 | get x(): number; 67 | /** 68 | * Returns y value of the vector. 69 | * @returns {number} 70 | */ 71 | get y(): number; 72 | /** 73 | * Returns z value of the vector. 74 | * @returns {number} 75 | */ 76 | get z(): number; 77 | /** 78 | * Set the `value` as new x. 79 | * @param {number} value 80 | */ 81 | set x(value: number); 82 | /** 83 | * Set the `value` as new y. 84 | * @param {number} value 85 | */ 86 | set y(value: number); 87 | /** 88 | * Set the `value` as new z. 89 | * @param {number} value 90 | */ 91 | set z(value: number); 92 | } 93 | /** 94 | * A base abstract class for 4-dimensional vectors. 95 | */ 96 | export declare abstract class Vector4Base extends VectorBase { 97 | /** 98 | * Returns x value of the vector. 99 | * @returns {number} 100 | */ 101 | get x(): number; 102 | /** 103 | * Returns y value of the vector. 104 | * @returns {number} 105 | */ 106 | get y(): number; 107 | /** 108 | * Returns z value of the vector. 109 | * @returns {number} 110 | */ 111 | get z(): number; 112 | /** 113 | * Returns w value of the vector. 114 | * @returns {number} 115 | */ 116 | get w(): number; 117 | /** 118 | * Set the `value` as new x. 119 | * @param {number} value 120 | */ 121 | set x(value: number); 122 | /** 123 | * Set the `value` as new y. 124 | * @param {number} value 125 | */ 126 | set y(value: number); 127 | /** 128 | * Set the `value` as new z. 129 | * @param {number} value 130 | */ 131 | set z(value: number); 132 | /** 133 | * Set the `value` as new w. 134 | * @param {number} value 135 | */ 136 | set w(value: number); 137 | } 138 | -------------------------------------------------------------------------------- /lib/esm/vector_base.js: -------------------------------------------------------------------------------- 1 | // src/vector_base.ts 2 | var VectorBase = class { 3 | get values() { 4 | return this._values; 5 | } 6 | get magnitude() { 7 | let sumSq = 0; 8 | for (const val of this._values) { 9 | sumSq += val ** 2; 10 | } 11 | return Math.sqrt(sumSq); 12 | } 13 | toString() { 14 | const dimension = this._values.length; 15 | return `Vector${dimension}(${this._values.join(", ")})`; 16 | } 17 | }; 18 | var Vector2Base = class extends VectorBase { 19 | get x() { 20 | return this._values[0]; 21 | } 22 | get y() { 23 | return this._values[1]; 24 | } 25 | set x(value) { 26 | this._values[0] = value; 27 | } 28 | set y(value) { 29 | this._values[1] = value; 30 | } 31 | }; 32 | var Vector3Base = class extends VectorBase { 33 | get x() { 34 | return this._values[0]; 35 | } 36 | get y() { 37 | return this._values[1]; 38 | } 39 | get z() { 40 | return this._values[2]; 41 | } 42 | set x(value) { 43 | this._values[0] = value; 44 | } 45 | set y(value) { 46 | this._values[1] = value; 47 | } 48 | set z(value) { 49 | this._values[2] = value; 50 | } 51 | }; 52 | var Vector4Base = class extends VectorBase { 53 | get x() { 54 | return this._values[0]; 55 | } 56 | get y() { 57 | return this._values[1]; 58 | } 59 | get z() { 60 | return this._values[2]; 61 | } 62 | get w() { 63 | return this._values[3]; 64 | } 65 | set x(value) { 66 | this._values[0] = value; 67 | } 68 | set y(value) { 69 | this._values[1] = value; 70 | } 71 | set z(value) { 72 | this._values[2] = value; 73 | } 74 | set w(value) { 75 | this._values[3] = value; 76 | } 77 | }; 78 | export { 79 | Vector2Base, 80 | Vector3Base, 81 | Vector4Base, 82 | VectorBase 83 | }; 84 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "matrixgl", 3 | "version": "2.0.0", 4 | "description": "Yet another matrix library for WebGL", 5 | "keywords": [ 6 | "webgl", 7 | "math", 8 | "matrix", 9 | "vector" 10 | ], 11 | "type": "module", 12 | "main": "./lib/esm/index.js", 13 | "types": "./lib/esm/index.d.ts", 14 | "author": "Koto Furumiya ", 15 | "license": "Zlib", 16 | "files": [ 17 | "lib/" 18 | ], 19 | "exports": { 20 | "import": "./lib/esm/index.js", 21 | "require": "./lib/csm/index.js", 22 | "default": "./lib/esm/index.js" 23 | }, 24 | "repository": { 25 | "type": "git", 26 | "url": "https://github.com/kotofurumiya/matrixgl.git" 27 | }, 28 | "bugs": { 29 | "url": "https://github.com/kotofurumiya/matrixgl/issues", 30 | "email": "kotofurumiya@gmail.com" 31 | }, 32 | "homepage": "https://github.com/kotofurumiya/matrixgl", 33 | "scripts": { 34 | "typedoc": "typedoc ./src --out ./docs --readme README.md && nodetouch ./docs/.nojekyll", 35 | "test": "uvu -r tsm __tests__", 36 | "build:esm": "esbuild src/*.ts --bundle --platform=node --format=esm --target=es2020 --outdir=lib/esm && tsc --emitDeclarationOnly --outDir lib/esm", 37 | "build:cjs": "esbuild src/*.ts --bundle --platform=node --format=cjs --target=es2020 --outdir=lib/cjs && tsc --emitDeclarationOnly --outDir lib/cjs", 38 | "build:browser": "esbuild src/index.ts --bundle --minify --platform=browser --target=es2020 --outfile=build/matrixgl.min.js", 39 | "build": "npm run build:esm && npm run build:cjs && npm run build:browser && npm run typedoc" 40 | }, 41 | "devDependencies": { 42 | "esbuild": "^0.13.15", 43 | "touch": "^3.1.0", 44 | "tsm": "^2.1.4", 45 | "typedoc": "^0.22.9", 46 | "typescript": "^4.4.4", 47 | "uvu": "^0.5.2" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/float32vector.ts: -------------------------------------------------------------------------------- 1 | import { Vector2Base, Vector3Base, Vector4Base } from './vector_base'; 2 | 3 | /** 4 | * A 2-dimensional vector of single-precision float numbers. 5 | */ 6 | export class Float32Vector2 extends Vector2Base { 7 | constructor(x: number, y: number) { 8 | super(); 9 | this._values = new Float32Array([x, y]); 10 | } 11 | 12 | /** 13 | * Add `other` to the vector and returns new `Float32Vector2`. 14 | * 15 | * This method does not mutate the vector. 16 | * @param {Float32Vector2} other 17 | * @returns {Float32Vector2} 18 | */ 19 | add(other: Float32Vector2): Float32Vector2 { 20 | return new Float32Vector2(this.x + other.x, this.y + other.y); 21 | } 22 | 23 | /** 24 | * Subtract `other` from the vector and returns new `Float32Vector2`. 25 | * 26 | * This method does not mutate the vector. 27 | * @param {Float32Vector2} other 28 | * @returns {Float32Vector2} 29 | */ 30 | sub(other: Float32Vector2): Float32Vector2 { 31 | return new Float32Vector2(this.x - other.x, this.y - other.y); 32 | } 33 | 34 | /** 35 | * Multiply the vector by `scalar` and returns new `Float32Vector2`. 36 | * 37 | * This method does not mutate the vector. 38 | * @param {number} scalar 39 | * @returns {Float32Vector2} 40 | */ 41 | mulByScalar(scalar: number): Float32Vector2 { 42 | return new Float32Vector2(this.x * scalar, this.y * scalar); 43 | } 44 | } 45 | 46 | /** 47 | * A 3-dimensional vector of single-precision float numbers. 48 | */ 49 | export class Float32Vector3 extends Vector3Base { 50 | constructor(x: number, y: number, z: number) { 51 | super(); 52 | this._values = new Float32Array([x, y, z]); 53 | } 54 | 55 | /** 56 | * Add `other` to the vector and returns new `Float32Vector3`. 57 | * 58 | * This method does not mutate the vector. 59 | * @param {Float32Vector3} other 60 | * @returns {Float32Vector3} 61 | */ 62 | add(other: Float32Vector3): Float32Vector3 { 63 | return new Float32Vector3(this.x + other.x, this.y + other.y, this.z + other.z); 64 | } 65 | 66 | /** 67 | * Subtract `other` from the vector and returns new `Float32Vector3`. 68 | * 69 | * This method does not mutate the vector. 70 | * @param {Float32Vector3} other 71 | * @returns {Float32Vector3} 72 | */ 73 | sub(other: Float32Vector3): Float32Vector3 { 74 | return new Float32Vector3(this.x - other.x, this.y - other.y, this.z - other.z); 75 | } 76 | 77 | /** 78 | * Multiply the vector by `scalar` and returns new `Float32Vector3`. 79 | * 80 | * This method does not mutate the vector. 81 | * @param {number} scalar 82 | * @returns {Float32Vector3} 83 | */ 84 | mulByScalar(scalar: number): Float32Vector3 { 85 | return new Float32Vector3(this.x * scalar, this.y * scalar, this.z * scalar); 86 | } 87 | 88 | /** 89 | * Calculate dot product. 90 | * @param {Float32Vector3} other 91 | * @returns {number} 92 | */ 93 | dot(other: Float32Vector3): number { 94 | return this.x * other.x + this.y * other.y + this.z * other.z; 95 | } 96 | 97 | /** 98 | * Calculate cross product. 99 | * @param {Float32Vector3} other 100 | * @returns {Float32Vector3} 101 | */ 102 | cross(other: Float32Vector3): Float32Vector3 { 103 | const cx: number = this.y * other.z - this.z * other.y; 104 | const cy: number = this.z * other.x - this.x * other.z; 105 | const cz: number = this.x * other.y - this.y * other.x; 106 | 107 | return new Float32Vector3(cx, cy, cz); 108 | } 109 | 110 | /** 111 | * Normalize the vector and returns new `Float32Vector3`. 112 | * 113 | * This method does not mutate the vector. 114 | * @returns {Float32Vector3} 115 | */ 116 | normalize(): Float32Vector3 { 117 | const mag: number = this.magnitude; 118 | if(mag === 0) { return this; } 119 | return new Float32Vector3(this.x / mag, this.y / mag, this.z / mag); 120 | } 121 | 122 | /** 123 | * Returns xy values of the vector as `Float32Vector2`. 124 | * @returns {Float32Vector2} 125 | */ 126 | get xy(): Float32Vector2 { 127 | return new Float32Vector2(this.x, this.y); 128 | } 129 | } 130 | 131 | /** 132 | * A 4-dimensional vector of single-precision float numbers. 133 | */ 134 | export class Float32Vector4 extends Vector4Base { 135 | constructor(x: number, y: number, z: number, w: number) { 136 | super(); 137 | this._values = new Float32Array([x, y, z, w]); 138 | } 139 | 140 | /** 141 | * Add `other` to the vector and returns new `Float32Vector4`. 142 | * 143 | * This method does not mutate the vector. 144 | * @param {Float32Vector4} other 145 | * @returns {Float32Vector4} 146 | */ 147 | add(other: Float32Vector4): Float32Vector4 { 148 | return new Float32Vector4(this.x + other.x, this.y + other.y, this.z + other.z, this.w + other.w); 149 | } 150 | 151 | /** 152 | * Subtract `other` from the vector and returns new `Float32Vector4`. 153 | * 154 | * This method does not mutate the vector. 155 | * @param {Float32Vector4} other 156 | * @returns {Float32Vector4} 157 | */ 158 | sub(other: Float32Vector4): Float32Vector4 { 159 | return new Float32Vector4(this.x - other.x, this.y - other.y, this.z - other.z, this.w - other.w); 160 | } 161 | 162 | /** 163 | * Multiply the vector by `scalar` and returns new `Float32Vector4`. 164 | * 165 | * This method does not mutate the vector. 166 | * @param {number} scalar 167 | * @returns {Float32Vector4} 168 | */ 169 | mulByScalar(scalar: number): Float32Vector4 { 170 | return new Float32Vector4(this.x * scalar, this.y * scalar, this.z * scalar, this.w * scalar); 171 | } 172 | 173 | /** 174 | * Returns xyz values of the vector as `Float32Vector3`. 175 | * @returns {Float32Vector3} 176 | */ 177 | get xyz(): Float32Vector3 { 178 | return new Float32Vector3(this.x, this.y, this.z); 179 | } 180 | } 181 | 182 | /** 183 | * An alias for `Float32Vector2`. 184 | * @type {Float32Vector2} 185 | */ 186 | export const Vector2 = Float32Vector2; 187 | 188 | /** 189 | * An alias for `Float32Vector3`. 190 | * @type {Float32Vector3} 191 | */ 192 | export const Vector3 = Float32Vector3; 193 | 194 | /** 195 | * An alias for `Float32Vector4`. 196 | * @type {Float32Vector4} 197 | */ 198 | export const Vector4 = Float32Vector4; -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './float32vector'; 2 | export * from './matrix'; 3 | export * from './quaternion'; -------------------------------------------------------------------------------- /src/matrix.ts: -------------------------------------------------------------------------------- 1 | import { Float32Vector3, Float32Vector4 } from './float32vector'; 2 | import { Quaternion } from './quaternion'; 3 | 4 | /** 5 | * An interface for matrices; 6 | */ 7 | export interface Matrix { 8 | /** 9 | * Values of the matrix, that is stored in column major order. 10 | */ 11 | readonly values: Float32Array; 12 | 13 | /** 14 | * Returns `values` as string. 15 | * @returns {string} 16 | */ 17 | toString(): string; 18 | } 19 | 20 | /** 21 | * 2x2 Matrix of single-precision float numbers. 22 | * 23 | * Values are stored in column major order. 24 | */ 25 | export class Matrix2x2 implements Matrix { 26 | protected _values: Float32Array; 27 | 28 | constructor(m11: number, m21: number, m12: number, m22: number) { 29 | this._values = new Float32Array([ 30 | m11, m21, 31 | m12, m22 32 | ]); 33 | } 34 | 35 | /** 36 | * Returns an identity matrix. 37 | * @returns {Matrix2x2} 38 | */ 39 | static identity(): Matrix2x2 { 40 | return new Matrix2x2(1.0, 0.0, 0.0, 1.0); 41 | } 42 | 43 | get values(): Float32Array { 44 | return this._values; 45 | } 46 | 47 | toString(): string { 48 | return this._values.toString(); 49 | } 50 | } 51 | 52 | /** 53 | * 3x3 Matrix of single-precision float numbers. 54 | * 55 | * Values are stored in column major order. 56 | */ 57 | export class Matrix3x3 implements Matrix { 58 | protected _values: Float32Array; 59 | 60 | constructor( 61 | m11: number, m21: number, m31: number, 62 | m12: number, m22: number, m32: number, 63 | m13: number, m23: number, m33: number 64 | ) { 65 | this._values = new Float32Array([ 66 | m11, m21, m31, 67 | m12, m22, m32, 68 | m13, m23, m33 69 | ]); 70 | } 71 | 72 | /** 73 | * Returns an identity matrix. 74 | * @returns {Matrix3x3} 75 | */ 76 | static identity(): Matrix3x3 { 77 | return new Matrix3x3( 78 | 1.0, 0.0, 0.0, 79 | 0.0, 1.0, 0.0, 80 | 0.0, 0.0, 1.0 81 | ); 82 | } 83 | 84 | get values(): Float32Array { 85 | return this._values; 86 | } 87 | 88 | toString(): string { 89 | return this._values.toString(); 90 | } 91 | } 92 | 93 | /** 94 | * 4x4 Matrix of single-precision float numbers. 95 | * 96 | * Values are stored in column major order. 97 | */ 98 | export class Matrix4x4 implements Matrix { 99 | protected _values: Float32Array; 100 | 101 | constructor( 102 | m11: number, m21: number, m31: number, m41: number, 103 | m12: number, m22: number, m32: number, m42: number, 104 | m13: number, m23: number, m33: number, m43: number, 105 | m14: number, m24: number, m34: number, m44: number 106 | ) { 107 | this._values = new Float32Array([ 108 | m11, m21, m31, m41, 109 | m12, m22, m32, m42, 110 | m13, m23, m33, m43, 111 | m14, m24, m34, m44 112 | ]); 113 | } 114 | 115 | /** 116 | * Returns an identity matrix. 117 | * @returns {Matrix4x4} 118 | */ 119 | static identity(): Matrix4x4 { 120 | return new Matrix4x4( 121 | 1.0, 0.0, 0.0, 0.0, 122 | 0.0, 1.0, 0.0, 0.0, 123 | 0.0, 0.0, 1.0, 0.0, 124 | 0.0, 0.0, 0.0, 1.0 125 | ); 126 | } 127 | 128 | /** 129 | * Returns translation matrix. 130 | * @param {number} tx 131 | * @param {number} ty 132 | * @param {number} tz 133 | * @returns {Matrix4x4} 134 | */ 135 | static translation(tx: number, ty: number, tz: number): Matrix4x4 { 136 | return new Matrix4x4( 137 | 1.0, 0.0, 0.0, 0.0, 138 | 0.0, 1.0, 0.0, 0.0, 139 | 0.0, 0.0, 1.0, 0.0, 140 | tx, ty, tz, 1.0 141 | ); 142 | } 143 | 144 | /** 145 | * Returns scaling matrix. 146 | * @param {number} sx 147 | * @param {number} sy 148 | * @param {number} sz 149 | * @returns {Matrix4x4} 150 | */ 151 | static scaling(sx: number, sy: number, sz: number): Matrix4x4 { 152 | return new Matrix4x4( 153 | sx, 0.0, 0.0, 0.0, 154 | 0.0, sy, 0.0, 0.0, 155 | 0.0, 0.0, sz, 0.0, 156 | 0.0, 0.0, 0.0, 1.0 157 | ); 158 | } 159 | 160 | /** 161 | * Returns rotation matrix around x-axis. 162 | * @param {number} radian 163 | * @returns {Matrix4x4} 164 | */ 165 | static rotationX(radian: number): Matrix4x4 { 166 | const sin: number = Math.sin(radian); 167 | const cos: number = Math.cos(radian); 168 | 169 | return new Matrix4x4( 170 | 1.0, 0.0, 0.0, 0.0, 171 | 0.0, cos, sin, 0.0, 172 | 0.0, -sin, cos, 0.0, 173 | 0.0, 0.0, 0.0, 1.0 174 | ); 175 | } 176 | 177 | /** 178 | * Returns rotation matrix around y-axis. 179 | * @param {number} radian 180 | * @returns {Matrix4x4} 181 | */ 182 | static rotationY(radian: number): Matrix4x4 { 183 | const sin: number = Math.sin(radian); 184 | const cos: number = Math.cos(radian); 185 | 186 | return new Matrix4x4( 187 | cos, 0.0, -sin, 0.0, 188 | 0.0, 1.0, 0.0, 0.0, 189 | sin, 0.0, cos, 0.0, 190 | 0.0, 0.0, 0.0, 1.0 191 | ); 192 | } 193 | 194 | /** 195 | * Returns rotation matrix around z-axis. 196 | * @param {number} radian 197 | * @returns {Matrix4x4} 198 | */ 199 | static rotationZ(radian: number): Matrix4x4 { 200 | const sin: number = Math.sin(radian); 201 | const cos: number = Math.cos(radian); 202 | 203 | return new Matrix4x4( 204 | cos, sin, 0.0, 0.0, 205 | -sin, cos, 0.0, 0.0, 206 | 0.0, 0.0, 1.0, 0.0, 207 | 0.0, 0.0, 0.0, 1.0 208 | ); 209 | } 210 | 211 | /** 212 | * Returns rotation matrix around `normalizedAxis`. `normalizedAxis` must be normalized. 213 | * @param {Float32Vector3} normalizedAxis 214 | * @param {number} radian 215 | * @returns {Matrix4x4} 216 | */ 217 | static rotationAround(normalizedAxis: Float32Vector3, radian: number) : Matrix4x4 { 218 | const q = Quaternion.rotationAround(normalizedAxis, radian); 219 | return q.toRotationMatrix4(); 220 | } 221 | 222 | /** 223 | * Returns "look at" matrix. 224 | * @param {Float32Vector3} cameraPosition 225 | * @param {Float32Vector3} lookAtPosition 226 | * @param {Float32Vector3} cameraUp 227 | * @returns {Matrix4x4} 228 | */ 229 | static lookAt(cameraPosition: Float32Vector3, lookAtPosition: Float32Vector3, cameraUp: Float32Vector3): Matrix4x4 { 230 | const zAxis: Float32Vector3 = cameraPosition.sub(lookAtPosition).normalize(); 231 | const xAxis: Float32Vector3 = cameraUp.cross(zAxis).normalize(); 232 | const yAxis: Float32Vector3 = zAxis.cross(xAxis).normalize(); 233 | 234 | return new Matrix4x4( 235 | xAxis.x, yAxis.x, zAxis.x, 0.0, 236 | xAxis.y, yAxis.y, zAxis.y, 0.0, 237 | xAxis.z, yAxis.z, zAxis.z, 0.0, 238 | -cameraPosition.dot(xAxis), -cameraPosition.dot(yAxis), -cameraPosition.dot(zAxis), 1.0 239 | ); 240 | } 241 | 242 | /** 243 | * Returns an orthographic projection matrix. 244 | * @param {{top: number; bottom: number; left: number; right: number; near: number; far: number}} argsObject 245 | * @returns {Matrix4x4} 246 | */ 247 | static orthographic(argsObject: {top: number, bottom: number, left: number, right: number, near: number, far: number}): Matrix4x4 { 248 | const top: number = argsObject.top; 249 | const bottom: number = argsObject.bottom; 250 | const left: number = argsObject.left; 251 | const right: number = argsObject.right; 252 | const near: number = argsObject.near; 253 | const far: number = argsObject.far; 254 | 255 | return new Matrix4x4( 256 | 2/(right-left), 0.0, 0.0, 0.0, 257 | 0.0, 2/(top-bottom), 0.0, 0.0, 258 | 0.0, 0.0, -2/(far-near), 0.0, 259 | -(right+left)/(right-left), -(top+bottom)/(top-bottom), -(far+near)/(far-near), 1.0 260 | ); 261 | } 262 | 263 | /** 264 | * Returns a frustrum projection matrix. 265 | * @param {{top: number; bottom: number; left: number; right: number; near: number; far: number}} argsObject 266 | * @returns {Matrix4x4} 267 | */ 268 | static frustum(argsObject: {top: number, bottom: number, left: number, right: number, near: number, far: number}): Matrix4x4 { 269 | const top: number = argsObject.top; 270 | const bottom: number = argsObject.bottom; 271 | const left: number = argsObject.left; 272 | const right: number = argsObject.right; 273 | const near: number = argsObject.near; 274 | const far: number = argsObject.far; 275 | 276 | return new Matrix4x4( 277 | 2*near/(right-left), 0.0, 0.0, 0.0, 278 | 0.0, 2*near/(top-bottom), 0.0, 0.0, 279 | (right+left)/(right-left), (top+bottom)/(top-bottom), -(far+near)/(far-near), -1.0, 280 | 0.0, 0.0, -2*far*near/(far-near), 0.0 281 | ); 282 | } 283 | 284 | /** 285 | * Returns a perspective projection matrix. 286 | * @param {{fovY: number; aspect: number; near: number; far: number}} argsObject 287 | * @returns {Matrix4x4} 288 | */ 289 | static perspective(argsObject: {fovYRadian: number, aspectRatio: number, near: number, far: number}): Matrix4x4 { 290 | const top = argsObject.near * Math.tan(argsObject.fovYRadian * 0.5); 291 | const height = top * 2; 292 | const width = argsObject.aspectRatio * height; 293 | const left = -0.5 * width; 294 | const right = left + width; 295 | const bottom = top - height; 296 | 297 | return Matrix4x4.frustum({ 298 | top, 299 | bottom, 300 | left, 301 | right, 302 | near: argsObject.near, 303 | far: argsObject.far 304 | }) 305 | } 306 | 307 | /** 308 | * Multiply by `other` matrix and returns a product. 309 | * 310 | * This method does not mutate the matrix. 311 | * @param {Matrix4x4} other 312 | * @returns {Matrix4x4} 313 | */ 314 | mulByMatrix4x4(other: Matrix4x4): Matrix4x4 { 315 | const m11: number = this._values[0]; 316 | const m12: number = this._values[4]; 317 | const m13: number = this._values[8]; 318 | const m14: number = this._values[12]; 319 | const m21: number = this._values[1]; 320 | const m22: number = this._values[5]; 321 | const m23: number = this._values[9]; 322 | const m24: number = this._values[13]; 323 | const m31: number = this._values[2]; 324 | const m32: number = this._values[6]; 325 | const m33: number = this._values[10]; 326 | const m34: number = this._values[14]; 327 | const m41: number = this._values[3]; 328 | const m42: number = this._values[7]; 329 | const m43: number = this._values[11]; 330 | const m44: number = this._values[15]; 331 | 332 | const o11: number = other.values[0]; 333 | const o12: number = other.values[4]; 334 | const o13: number = other.values[8]; 335 | const o14: number = other.values[12]; 336 | const o21: number = other.values[1]; 337 | const o22: number = other.values[5]; 338 | const o23: number = other.values[9]; 339 | const o24: number = other.values[13]; 340 | const o31: number = other.values[2]; 341 | const o32: number = other.values[6]; 342 | const o33: number = other.values[10]; 343 | const o34: number = other.values[14]; 344 | const o41: number = other.values[3]; 345 | const o42: number = other.values[7]; 346 | const o43: number = other.values[11]; 347 | const o44: number = other.values[15]; 348 | 349 | const p11: number = (m11 * o11) + (m12 * o21) + (m13 * o31) + (m14 * o41); 350 | const p12: number = (m11 * o12) + (m12 * o22) + (m13 * o32) + (m14 * o42); 351 | const p13: number = (m11 * o13) + (m12 * o23) + (m13 * o33) + (m14 * o43); 352 | const p14: number = (m11 * o14) + (m12 * o24) + (m13 * o34) + (m14 * o44); 353 | 354 | const p21: number = (m21 * o11) + (m22 * o21) + (m23 * o31) + (m24 * o41); 355 | const p22: number = (m21 * o12) + (m22 * o22) + (m23 * o32) + (m24 * o42); 356 | const p23: number = (m21 * o13) + (m22 * o23) + (m23 * o33) + (m24 * o43); 357 | const p24: number = (m21 * o14) + (m22 * o24) + (m23 * o34) + (m24 * o44); 358 | 359 | const p31: number = (m31 * o11) + (m32 * o21) + (m33 * o31) + (m34 * o41); 360 | const p32: number = (m31 * o12) + (m32 * o22) + (m33 * o32) + (m34 * o42); 361 | const p33: number = (m31 * o13) + (m32 * o23) + (m33 * o33) + (m34 * o43); 362 | const p34: number = (m31 * o14) + (m32 * o24) + (m33 * o34) + (m34 * o44); 363 | 364 | const p41: number = (m41 * o11) + (m42 * o21) + (m43 * o31) + (m44 * o41); 365 | const p42: number = (m41 * o12) + (m42 * o22) + (m43 * o32) + (m44 * o42); 366 | const p43: number = (m41 * o13) + (m42 * o23) + (m43 * o33) + (m44 * o43); 367 | const p44: number = (m41 * o14) + (m42 * o24) + (m43 * o34) + (m44 * o44); 368 | 369 | return new Matrix4x4( 370 | p11, p21, p31, p41, 371 | p12, p22, p32, p42, 372 | p13, p23, p33, p43, 373 | p14, p24, p34, p44 374 | ); 375 | } 376 | 377 | /** 378 | * An alias for `mulByMatrix4x4`. 379 | * @param {Matrix4x4} other 380 | * @returns {Matrix4x4} 381 | */ 382 | mulByMatrix4(other: Matrix4x4): Matrix4x4 { 383 | return this.mulByMatrix4x4(other); 384 | } 385 | 386 | /** 387 | * Translate the matrix and returns new `Matrix4x4`. 388 | * 389 | * This method does not mutate the matrix. 390 | * @param {number} tx 391 | * @param {number} ty 392 | * @param {number} tz 393 | * @returns {Matrix4x4} 394 | */ 395 | translate(tx: number, ty: number, tz: number): Matrix4x4 { 396 | const t: Matrix4x4 = Matrix4x4.translation(tx, ty, tz); 397 | return this.mulByMatrix4x4(t); 398 | } 399 | 400 | /** 401 | * Scale the matrix and returns new `Matrix4x4`. 402 | * @param {number} sx 403 | * @param {number} sy 404 | * @param {number} sz 405 | * @returns {Matrix4x4} 406 | */ 407 | scale(sx: number, sy: number, sz: number): Matrix4x4 { 408 | const s: Matrix4x4 = Matrix4x4.scaling(sx, sy, sz); 409 | return this.mulByMatrix4x4(s); 410 | } 411 | 412 | /** 413 | * Rotate the matrix around x-axis and returns new `Matrix4x4`. 414 | * 415 | * This method does not mutate the matrix. 416 | * @param {number} radian 417 | * @returns {Matrix4x4} 418 | */ 419 | rotateX(radian: number): Matrix4x4 { 420 | const rx: Matrix4x4 = Matrix4x4.rotationX(radian); 421 | return this.mulByMatrix4x4(rx); 422 | } 423 | 424 | /** 425 | * Rotate the matrix around y-axis and returns new `Matrix4x4`. 426 | * 427 | * This method does not mutate the matrix. 428 | * @param {number} radian 429 | * @returns {Matrix4x4} 430 | */ 431 | rotateY(radian: number): Matrix4x4 { 432 | const ry: Matrix4x4 = Matrix4x4.rotationY(radian); 433 | return this.mulByMatrix4x4(ry); 434 | } 435 | 436 | /** 437 | * Rotate the matrix around z-axis and returns new `Matrix4x4`. 438 | * 439 | * This method does not mutate the matrix. 440 | * @param {number} radian 441 | * @returns {Matrix4x4} 442 | */ 443 | rotateZ(radian: number): Matrix4x4 { 444 | const rz: Matrix4x4 = Matrix4x4.rotationZ(radian); 445 | return this.mulByMatrix4x4(rz); 446 | } 447 | 448 | /** 449 | * Rotate the matrix around the `normalizedAxis` and return new Matrix4x4. 450 | * 451 | * This method does not mutate the matrix. 452 | * @param {Float32Vector3} normalizedAxis 453 | * @param {number} radian 454 | * @returns {Matrix4x4} 455 | */ 456 | rotateAround(normalizedAxis: Float32Vector3, radian: number): Matrix4x4 { 457 | const r = Matrix4x4.rotationAround(normalizedAxis, radian); 458 | return this.mulByMatrix4x4(r); 459 | } 460 | 461 | get values(): Float32Array { 462 | return this._values; 463 | } 464 | 465 | toString(): string { 466 | return this._values.toString(); 467 | } 468 | } 469 | 470 | /** 471 | * An alias for `Matrix2x2`. 472 | * @type {Matrix2x2} 473 | */ 474 | export const Matrix2 = Matrix2x2; 475 | 476 | /** 477 | * An alias for `Matrix3x3`. 478 | * @type {Matrix3x3} 479 | */ 480 | export const Matrix3 = Matrix3x3; 481 | 482 | /** 483 | * An alias for `Matrix4x4`. 484 | * @type {Matrix4x4} 485 | */ 486 | export const Matrix4 = Matrix4x4; -------------------------------------------------------------------------------- /src/quaternion.ts: -------------------------------------------------------------------------------- 1 | import { Float32Vector3 } from './float32vector'; 2 | import { Matrix4x4 } from './matrix'; 3 | 4 | /** 5 | * Quaternion which is 4-dimensional complex number. 6 | * See [Wikipedia](https://en.wikipedia.org/wiki/Quaternion). 7 | */ 8 | export class Quaternion { 9 | protected _values: Float32Array; 10 | 11 | constructor(x: number, y: number, z: number, w: number) { 12 | this._values = new Float32Array([x, y, z, w]); 13 | } 14 | 15 | /** 16 | * Create a rotation quaternion around `normalizedAxis`. 17 | * `normalizedAxis` must be normalized. 18 | * @param {Float32Vector3} normalizedAxis 19 | * @param {number} radian 20 | * @returns {Quaternion} 21 | */ 22 | static rotationAround(normalizedAxis: Float32Vector3, radian: number): Quaternion { 23 | const sin = Math.sin(radian / 2.0); 24 | const cos = Math.cos(radian / 2.0); 25 | return new Quaternion(normalizedAxis.x * sin, normalizedAxis.y * sin, normalizedAxis.z * sin, cos); 26 | } 27 | 28 | /** 29 | * Returns a normalized quaternion. 30 | * @returns {Quaternion} 31 | */ 32 | normalize() : Quaternion { 33 | const mag = this.magnitude; 34 | if(mag === 0) { return this; } 35 | const r = 1 / mag; 36 | return new Quaternion(this.x * r, this.y * r, this.z * r, this.w * r); 37 | } 38 | 39 | /** 40 | * Adds the `other` to the quaternion and returns the sum. 41 | * 42 | * This method does not mutate the quaternion. 43 | * @param {Quaternion} other 44 | * @returns {Quaternion} 45 | */ 46 | add(other: Quaternion): Quaternion { 47 | return new Quaternion(this.x + other.x, this.y + other.y, this.z + other.z, this.w + other.w); 48 | } 49 | 50 | /** 51 | * Multiplies the quaternion by `scalar` and returns the product. 52 | * 53 | * This method does not mutate the quaternion. 54 | * @param {number} scalar 55 | * @returns {Quaternion} 56 | */ 57 | mulByScalar(scalar: number): Quaternion { 58 | return new Quaternion(this.x * scalar, this.y * scalar, this.z * scalar, this.w * scalar); 59 | } 60 | 61 | /** 62 | * Calculates dot product. 63 | * @param {Quaternion} other 64 | * @returns {number} 65 | */ 66 | dot(other: Quaternion): number { 67 | return this.x * other.x + this.y * other.y + this.z * other.z + this.w * other.w; 68 | } 69 | 70 | /** 71 | * Calculates spherical linear interpolation(also known as Slerp) and returns new `Quaternion` between the quaternion and the other. 72 | * @param {Quaternion} other 73 | * @param {number} t 0.0 <= t <= 1.0 74 | * @param {{chooseShorterAngle: boolean}} options Does not work currently. slerp chooses shorter angle regardless of this value. 75 | * @returns {Quaternion} 76 | */ 77 | slerp(other: Quaternion , t: number, options: { chooseShorterAngle: boolean } = { chooseShorterAngle: true }): Quaternion { 78 | let dotProd: number = this.dot(other); 79 | let otherQuaternion: Quaternion = other; 80 | 81 | // When the dot product is negative, slerp chooses the longer way. 82 | // So we should negate the `other` quaternion. 83 | if(dotProd < 0) { 84 | dotProd = -dotProd; 85 | otherQuaternion = other.mulByScalar(-1); 86 | } 87 | 88 | const omega: number = Math.acos(dotProd); 89 | const sinOmega: number = Math.sin(omega); 90 | 91 | const q1: Quaternion = this.mulByScalar(Math.sin((1 - t) * omega) / sinOmega); 92 | const q2: Quaternion = otherQuaternion.mulByScalar(Math.sin(t * omega) / sinOmega); 93 | 94 | return q1.add(q2); 95 | } 96 | 97 | /** 98 | * Calc magnitude of the quaternion. 99 | * @returns {number} 100 | */ 101 | get magnitude(): number { 102 | return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w); 103 | } 104 | 105 | /** 106 | * Calc norm of the quaternion. 107 | * An alias for `magnitude`. 108 | * @returns {number} 109 | */ 110 | get norm(): number { 111 | return this.magnitude; 112 | } 113 | 114 | /** 115 | * Returns x value of the vector. 116 | * @returns {number} 117 | */ 118 | get x(): number { 119 | return this._values[0]; 120 | } 121 | 122 | /** 123 | * Returns y value of the vector. 124 | * @returns {number} 125 | */ 126 | get y(): number { 127 | return this._values[1]; 128 | } 129 | 130 | /** 131 | * Returns z value of the vector. 132 | * @returns {number} 133 | */ 134 | get z(): number { 135 | return this._values[2]; 136 | } 137 | 138 | /** 139 | * Returns w value of the vector. 140 | * @returns {number} 141 | */ 142 | get w(): number { 143 | return this._values[3]; 144 | } 145 | 146 | /** 147 | * Set the `value` as new x. 148 | * @param {number} value 149 | */ 150 | set x(value: number) { 151 | this._values[0] = value; 152 | } 153 | 154 | /** 155 | * Set the `value` as new y. 156 | * @param {number} value 157 | */ 158 | set y(value: number) { 159 | this._values[1] = value; 160 | } 161 | 162 | /** 163 | * Set the `value` as new z. 164 | * @param {number} value 165 | */ 166 | set z(value: number) { 167 | this._values[2] = value; 168 | } 169 | 170 | /** 171 | * Set the `value` as new w. 172 | * @param {number} value 173 | */ 174 | set w(value: number) { 175 | this._values[3] = value; 176 | } 177 | 178 | /** 179 | * Returns values of the quaternion. 180 | * @returns {Float32Array} 181 | */ 182 | get values(): Float32Array { 183 | return this._values; 184 | } 185 | 186 | /** 187 | * Convert the quaternion to a rotation matrix. 188 | * @returns {Matrix4x4} 189 | */ 190 | toRotationMatrix4(): Matrix4x4 { 191 | const x = this.x; 192 | const y = this.y; 193 | const z = this.z; 194 | const w = this.w; 195 | 196 | const m11 = 1 - 2 * y * y - 2 * z * z; 197 | const m12 = 2 * x * y - 2 * w * z; 198 | const m13 = 2 * x * z + 2 * w * y; 199 | const m14 = 0; 200 | const m21 = 2 * x * y + 2 * w * z; 201 | const m22 = 1 - 2 * x * x - 2 * z * z; 202 | const m23 = 2 * y * z - 2 * w * x; 203 | const m24 = 0; 204 | const m31 = 2 * x * z - 2 * w * y; 205 | const m32 = 2 * y * z + 2 * w * x; 206 | const m33 = 1 - 2 * x * x - 2 * y * y; 207 | const m34 = 0; 208 | const m41 = 0; 209 | const m42 = 0; 210 | const m43 = 0; 211 | const m44 = 1; 212 | 213 | return new Matrix4x4( 214 | m11, m21, m31, m41, 215 | m12, m22, m32, m42, 216 | m13, m23, m33, m43, 217 | m14, m24, m34, m44 218 | ); 219 | } 220 | 221 | /** 222 | * Returns values as `String`. 223 | * @returns {string} 224 | */ 225 | toString(): string { 226 | return `Quaternion(${this.x}, ${this.y}, ${this.z}, ${this.w})`; 227 | } 228 | } -------------------------------------------------------------------------------- /src/vector_base.ts: -------------------------------------------------------------------------------- 1 | export type TypedArrayLike = Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array; 2 | 3 | /** 4 | * An interface for vectors. 5 | */ 6 | export interface Vector { 7 | /** 8 | * Returns values of the vector. 9 | * @returns {T} 10 | */ 11 | readonly values: T; 12 | 13 | /** 14 | * Returns magnitude of the vector. 15 | */ 16 | readonly magnitude: number; 17 | 18 | /** 19 | * Returns `values` as a string. 20 | * @returns {string} 21 | */ 22 | toString(): string; 23 | } 24 | 25 | /** 26 | * An abstract class for vectors. 27 | */ 28 | export abstract class VectorBase implements Vector { 29 | /** 30 | * Values that the vector contains. 31 | */ 32 | protected _values: T; 33 | 34 | get values(): T { 35 | return this._values; 36 | } 37 | 38 | get magnitude(): number { 39 | let sumSq = 0; 40 | for(const val of this._values) { 41 | sumSq += val ** 2; 42 | } 43 | return Math.sqrt(sumSq); 44 | } 45 | 46 | toString(): string { 47 | const dimension = this._values.length; 48 | return `Vector${dimension}(${this._values.join(', ')})`; 49 | } 50 | } 51 | 52 | /** 53 | * A base abstract class for 2-dimensional vectors. 54 | */ 55 | export abstract class Vector2Base extends VectorBase { 56 | /** 57 | * Returns x value of the vector. 58 | * @returns {number} 59 | */ 60 | get x(): number { 61 | return this._values[0]; 62 | } 63 | 64 | /** 65 | * Returns y value of the vector. 66 | * @returns {number} 67 | */ 68 | get y(): number { 69 | return this._values[1]; 70 | } 71 | 72 | /** 73 | * Set the `value` as new x. 74 | * @param {number} value 75 | */ 76 | set x(value: number) { 77 | this._values[0] = value; 78 | } 79 | 80 | /** 81 | * Set the `value` as new y. 82 | * @param {number} value 83 | */ 84 | set y(value: number) { 85 | this._values[1] = value; 86 | } 87 | 88 | } 89 | 90 | /** 91 | * A base abstract class for 3-dimensional vectors. 92 | */ 93 | export abstract class Vector3Base extends VectorBase { 94 | /** 95 | * Returns x value of the vector. 96 | * @returns {number} 97 | */ 98 | get x(): number { 99 | return this._values[0]; 100 | } 101 | 102 | /** 103 | * Returns y value of the vector. 104 | * @returns {number} 105 | */ 106 | get y(): number { 107 | return this._values[1]; 108 | } 109 | 110 | /** 111 | * Returns z value of the vector. 112 | * @returns {number} 113 | */ 114 | get z(): number { 115 | return this._values[2]; 116 | } 117 | 118 | /** 119 | * Set the `value` as new x. 120 | * @param {number} value 121 | */ 122 | set x(value: number) { 123 | this._values[0] = value; 124 | } 125 | 126 | /** 127 | * Set the `value` as new y. 128 | * @param {number} value 129 | */ 130 | set y(value: number) { 131 | this._values[1] = value; 132 | } 133 | 134 | /** 135 | * Set the `value` as new z. 136 | * @param {number} value 137 | */ 138 | set z(value: number) { 139 | this._values[2] = value; 140 | } 141 | } 142 | 143 | /** 144 | * A base abstract class for 4-dimensional vectors. 145 | */ 146 | export abstract class Vector4Base extends VectorBase { 147 | /** 148 | * Returns x value of the vector. 149 | * @returns {number} 150 | */ 151 | get x(): number { 152 | return this._values[0]; 153 | } 154 | 155 | /** 156 | * Returns y value of the vector. 157 | * @returns {number} 158 | */ 159 | get y(): number { 160 | return this._values[1]; 161 | } 162 | 163 | /** 164 | * Returns z value of the vector. 165 | * @returns {number} 166 | */ 167 | get z(): number { 168 | return this._values[2]; 169 | } 170 | 171 | /** 172 | * Returns w value of the vector. 173 | * @returns {number} 174 | */ 175 | get w(): number { 176 | return this._values[3]; 177 | } 178 | 179 | /** 180 | * Set the `value` as new x. 181 | * @param {number} value 182 | */ 183 | set x(value: number) { 184 | this._values[0] = value; 185 | } 186 | 187 | /** 188 | * Set the `value` as new y. 189 | * @param {number} value 190 | */ 191 | set y(value: number) { 192 | this._values[1] = value; 193 | } 194 | 195 | /** 196 | * Set the `value` as new z. 197 | * @param {number} value 198 | */ 199 | set z(value: number) { 200 | this._values[2] = value; 201 | } 202 | 203 | /** 204 | * Set the `value` as new w. 205 | * @param {number} value 206 | */ 207 | set w(value: number) { 208 | this._values[3] = value; 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "module": "commonjs", 5 | "outDir": "lib", 6 | "newLine": "LF", 7 | "sourceMap": false, 8 | "declaration": true, 9 | "strict": true, 10 | "strictPropertyInitialization": false 11 | }, 12 | 13 | "include": [ "src/**/*" ], 14 | 15 | "exclude": [ "node_modules" ] 16 | } --------------------------------------------------------------------------------