├── .gitignore ├── .npmignore ├── README.md ├── examples ├── anisotropic.html ├── assets │ ├── acorn.jpg │ ├── acorn.json │ ├── airplane.jpg │ ├── airplane.json │ ├── anim-format.json │ ├── compressed │ │ ├── astc-m-y.ktx │ │ ├── etc-m-y.ktx │ │ ├── etc1-m-y.ktx │ │ ├── pvrtc-m-y.ktx │ │ ├── s3tc-m-y.ktx │ │ └── uv.jpg │ ├── croissant.jpg │ ├── croissant.json │ ├── cube │ │ ├── negx.jpg │ │ ├── negy.jpg │ │ ├── negz.jpg │ │ ├── posx.jpg │ │ ├── posy.jpg │ │ └── posz.jpg │ ├── earth.jpg │ ├── earth_cloud.jpg │ ├── earth_specular.jpg │ ├── favicon.png │ ├── fonts │ │ ├── FiraSans-Bold.json │ │ ├── FiraSans-Bold.png │ │ ├── FiraSans-Bold.ttf │ │ ├── raleway-bold-webfont.woff │ │ ├── raleway-bold-webfont.woff2 │ │ ├── raleway-regular-webfont.woff │ │ └── raleway-regular-webfont.woff2 │ ├── forest.jpg │ ├── forest.json │ ├── fox.jpg │ ├── fox.json │ ├── gltf │ │ ├── cottage-basis-draco.glb │ │ ├── cottage-basis.glb │ │ ├── hershel-optimized.glb │ │ └── hershel.glb │ ├── goat.jpg │ ├── goat.json │ ├── granite-diffuse.jpg │ ├── granite-normal.jpg │ ├── grid.jpg │ ├── laputa.mp4 │ ├── leaf.jpg │ ├── libs │ │ ├── basis │ │ │ ├── BasisWorker.js │ │ │ ├── basis_transcoder.js │ │ │ └── basis_transcoder.wasm │ │ └── draco │ │ │ ├── DracoWorker.js │ │ │ ├── draco_decoder.js │ │ │ ├── draco_decoder.wasm │ │ │ ├── draco_encoder.js │ │ │ ├── draco_wasm_wrapper.js │ │ │ └── gltf │ │ │ ├── draco_decoder.js │ │ │ ├── draco_decoder.wasm │ │ │ ├── draco_encoder.js │ │ │ └── draco_wasm_wrapper.js │ ├── macaw.jpg │ ├── macaw.json │ ├── main.css │ ├── matcap.jpg │ ├── octopus.jpg │ ├── octopus.json │ ├── ogl.png │ ├── pbr │ │ ├── black.jpg │ │ ├── car-ext-color.jpg │ │ ├── car-ext-emissive.jpg │ │ ├── car-ext-inner.json │ │ ├── car-ext-normal.jpg │ │ ├── car-ext-opacity.jpg │ │ ├── car-ext-rmo.jpg │ │ ├── car-ext.json │ │ ├── car-int-color.jpg │ │ ├── car-int-normal.jpg │ │ ├── car-int-rmo.jpg │ │ ├── car-int.json │ │ ├── car-shadow.jpg │ │ ├── car-shadow.png │ │ ├── lut.png │ │ ├── waterfall-diffuse-RGBM.png │ │ ├── waterfall-specular-RGBM.png │ │ └── white.jpg │ ├── plane.json │ ├── rounded-cube.json │ ├── saddle.jpg │ ├── saddle.json │ ├── sky.jpg │ ├── snout-anim.json │ ├── snout-rig.json │ ├── snout-shadow.jpg │ ├── snout.jpg │ ├── sunset-diffuse-RGBM.png │ ├── sunset-specular-RGBM.png │ ├── sunset.exr │ ├── uv.jpg │ ├── water.jpg │ ├── windmill.jpg │ └── windmill.json ├── base-primitives.html ├── compressed-textures.html ├── cube-map.html ├── curves.html ├── draw-modes.html ├── flat-shading-matcap.html ├── fog.html ├── fresnel.html ├── frustum-culling.html ├── gltf-draco-webp.html ├── gltf-ktx2-basis-draco.html ├── gltf-ktx2-basis.html ├── gpgpu-particles.html ├── helpers.html ├── high-mesh-count.html ├── index.html ├── indexed-vs-non-indexed.html ├── instancing-gpu-picking.html ├── instancing.html ├── load-gltf.html ├── load-json.html ├── mouse-flowmap.html ├── mrt.html ├── msdf-text.html ├── normal-maps.html ├── orbit-controls.html ├── particles.html ├── paths.html ├── pbr.html ├── point-lighting.html ├── polylines.html ├── post-bloom.html ├── post-fluid-distortion.html ├── post-fxaa.html ├── raycasting.html ├── render-to-texture.html ├── scene-graph.html ├── shadow-maps.html ├── skinning.html ├── skydome.html ├── sort-transparency.html ├── textures.html ├── torus.html ├── triangle-screen-shader.html ├── tube.html ├── wire-mesh.html ├── wireframe-shader.html └── wireframe.html ├── package.json ├── src ├── core │ ├── Camera.js │ ├── Geometry.js │ ├── Mesh.js │ ├── Program.js │ ├── RenderTarget.js │ ├── Renderer.js │ ├── Texture.js │ └── Transform.js ├── extras │ ├── Animation.js │ ├── BasisManager.js │ ├── Box.js │ ├── Curve.js │ ├── Cylinder.js │ ├── DracoManager.js │ ├── Flowmap.js │ ├── GLTFAnimation.js │ ├── GLTFLoader.js │ ├── GLTFSkin.js │ ├── GPGPU.js │ ├── InstancedMesh.js │ ├── KTXTexture.js │ ├── NormalProgram.js │ ├── Orbit.js │ ├── Plane.js │ ├── Polyline.js │ ├── Post.js │ ├── Raycast.js │ ├── Shadow.js │ ├── Skin.js │ ├── Sphere.js │ ├── Text.js │ ├── Texture3D.js │ ├── TextureLoader.js │ ├── Torus.js │ ├── Triangle.js │ ├── Tube.js │ ├── WireMesh.js │ ├── helpers │ │ ├── AxesHelper.js │ │ ├── FaceNormalsHelper.js │ │ ├── GridHelper.js │ │ └── VertexNormalsHelper.js │ └── path │ │ ├── BaseSegment.js │ │ ├── CubicBezierSegment.js │ │ ├── LineSegment.js │ │ ├── Path.js │ │ ├── QuadraticBezierSegment.js │ │ └── utils.js ├── index.js └── math │ ├── Color.js │ ├── Euler.js │ ├── Mat3.js │ ├── Mat4.js │ ├── Quat.js │ ├── Vec2.js │ ├── Vec3.js │ ├── Vec4.js │ └── functions │ ├── ColorFunc.js │ ├── EulerFunc.js │ ├── Mat3Func.js │ ├── Mat4Func.js │ ├── QuatFunc.js │ ├── Vec2Func.js │ ├── Vec3Func.js │ └── Vec4Func.js └── types ├── core ├── Camera.d.ts ├── Geometry.d.ts ├── Mesh.d.ts ├── Program.d.ts ├── RenderTarget.d.ts ├── Renderer.d.ts ├── Texture.d.ts └── Transform.d.ts ├── extras ├── Animation.d.ts ├── BasisManager.d.ts ├── Box.d.ts ├── Curve.d.ts ├── Cylinder.d.ts ├── DracoManager.d.ts ├── Flowmap.d.ts ├── GLTFAnimation.d.ts ├── GLTFLoader.d.ts ├── GLTFSkin.d.ts ├── GPGPU.d.ts ├── InstancedMesh.d.ts ├── KTXTexture.d.ts ├── NormalProgram.d.ts ├── Orbit.d.ts ├── Plane.d.ts ├── Polyline.d.ts ├── Post.d.ts ├── Raycast.d.ts ├── Shadow.d.ts ├── Skin.d.ts ├── Sphere.d.ts ├── Text.d.ts ├── Texture3D.d.ts ├── TextureLoader.d.ts ├── Torus.d.ts ├── Triangle.d.ts ├── Tube.d.ts ├── WireMesh.d.ts ├── helpers │ ├── AxesHelper.d.ts │ ├── FaceNormalsHelper.d.ts │ ├── GridHelper.d.ts │ └── VertexNormalsHelper.d.ts └── path │ ├── BaseSegment.d.ts │ ├── CubicBezierSegment.d.ts │ ├── LineSegment.d.ts │ ├── Path.d.ts │ └── QuadraticBezierSegment.d.ts ├── index.d.ts └── math ├── Color.d.ts ├── Euler.d.ts ├── Mat3.d.ts ├── Mat4.d.ts ├── Quat.d.ts ├── Vec2.d.ts ├── Vec3.d.ts └── Vec4.d.ts /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | dist/ -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | examples -------------------------------------------------------------------------------- /examples/assets/acorn.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/acorn.jpg -------------------------------------------------------------------------------- /examples/assets/airplane.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/airplane.jpg -------------------------------------------------------------------------------- /examples/assets/anim-format.json: -------------------------------------------------------------------------------- 1 | { 2 | frames: [ 3 | { 4 | position: [bone1X, bone1Y, bone1Z, bone2X, bone2Y, bone2Z], 5 | quaternion: [2, 3, 1, 5, 6, 2], 6 | scale: [2, 3, 1, 5, 6, 2], 7 | }, 8 | { 9 | position: [2, 3, 1, 5, 6, 2], 10 | quaternion: [2, 3, 1, 5, 6, 2], 11 | scale: [2, 3, 1, 5, 6, 2], 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /examples/assets/compressed/astc-m-y.ktx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/compressed/astc-m-y.ktx -------------------------------------------------------------------------------- /examples/assets/compressed/etc-m-y.ktx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/compressed/etc-m-y.ktx -------------------------------------------------------------------------------- /examples/assets/compressed/etc1-m-y.ktx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/compressed/etc1-m-y.ktx -------------------------------------------------------------------------------- /examples/assets/compressed/pvrtc-m-y.ktx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/compressed/pvrtc-m-y.ktx -------------------------------------------------------------------------------- /examples/assets/compressed/s3tc-m-y.ktx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/compressed/s3tc-m-y.ktx -------------------------------------------------------------------------------- /examples/assets/compressed/uv.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/compressed/uv.jpg -------------------------------------------------------------------------------- /examples/assets/croissant.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/croissant.jpg -------------------------------------------------------------------------------- /examples/assets/cube/negx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/cube/negx.jpg -------------------------------------------------------------------------------- /examples/assets/cube/negy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/cube/negy.jpg -------------------------------------------------------------------------------- /examples/assets/cube/negz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/cube/negz.jpg -------------------------------------------------------------------------------- /examples/assets/cube/posx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/cube/posx.jpg -------------------------------------------------------------------------------- /examples/assets/cube/posy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/cube/posy.jpg -------------------------------------------------------------------------------- /examples/assets/cube/posz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/cube/posz.jpg -------------------------------------------------------------------------------- /examples/assets/earth.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/earth.jpg -------------------------------------------------------------------------------- /examples/assets/earth_cloud.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/earth_cloud.jpg -------------------------------------------------------------------------------- /examples/assets/earth_specular.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/earth_specular.jpg -------------------------------------------------------------------------------- /examples/assets/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/favicon.png -------------------------------------------------------------------------------- /examples/assets/fonts/FiraSans-Bold.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/fonts/FiraSans-Bold.png -------------------------------------------------------------------------------- /examples/assets/fonts/FiraSans-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/fonts/FiraSans-Bold.ttf -------------------------------------------------------------------------------- /examples/assets/fonts/raleway-bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/fonts/raleway-bold-webfont.woff -------------------------------------------------------------------------------- /examples/assets/fonts/raleway-bold-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/fonts/raleway-bold-webfont.woff2 -------------------------------------------------------------------------------- /examples/assets/fonts/raleway-regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/fonts/raleway-regular-webfont.woff -------------------------------------------------------------------------------- /examples/assets/fonts/raleway-regular-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/fonts/raleway-regular-webfont.woff2 -------------------------------------------------------------------------------- /examples/assets/forest.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/forest.jpg -------------------------------------------------------------------------------- /examples/assets/fox.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/fox.jpg -------------------------------------------------------------------------------- /examples/assets/gltf/cottage-basis-draco.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/gltf/cottage-basis-draco.glb -------------------------------------------------------------------------------- /examples/assets/gltf/cottage-basis.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/gltf/cottage-basis.glb -------------------------------------------------------------------------------- /examples/assets/gltf/hershel-optimized.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/gltf/hershel-optimized.glb -------------------------------------------------------------------------------- /examples/assets/gltf/hershel.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/gltf/hershel.glb -------------------------------------------------------------------------------- /examples/assets/goat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/goat.jpg -------------------------------------------------------------------------------- /examples/assets/granite-diffuse.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/granite-diffuse.jpg -------------------------------------------------------------------------------- /examples/assets/granite-normal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/granite-normal.jpg -------------------------------------------------------------------------------- /examples/assets/grid.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/grid.jpg -------------------------------------------------------------------------------- /examples/assets/laputa.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/laputa.mp4 -------------------------------------------------------------------------------- /examples/assets/leaf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/leaf.jpg -------------------------------------------------------------------------------- /examples/assets/libs/basis/basis_transcoder.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/libs/basis/basis_transcoder.wasm -------------------------------------------------------------------------------- /examples/assets/libs/draco/DracoWorker.js: -------------------------------------------------------------------------------- 1 | // TODO 2 | // [ ] Cleanup decoder 3 | // [ ] Point clouds 4 | // [ ] WASM support 5 | 6 | // https://github.com/mrdoob/three.js/tree/master/examples/jsm/libs/draco 7 | importScripts('gltf/draco_decoder.js'); 8 | 9 | let draco; 10 | let decoder; 11 | 12 | let moduleReadyResolve; 13 | const moduleReady = new Promise((res) => (moduleReadyResolve = res)); 14 | 15 | // Create the Draco decoder 16 | // const initStartTime = performance.now(); 17 | DracoDecoderModule().then((module) => { 18 | draco = module; 19 | decoder = new draco.Decoder(); 20 | // const elapsed = performance.now() - initStartTime; 21 | // console.log('worker init time', `${elapsed.toFixed(2)}ms`); 22 | moduleReadyResolve(); 23 | }); 24 | 25 | addEventListener('message', ({ data }) => { 26 | decodeGeometry(data); 27 | }); 28 | 29 | async function decodeGeometry({ id, buffer, config }) { 30 | await moduleReady; 31 | 32 | // const startTime = performance.now(); 33 | const array = new Int8Array(buffer); 34 | const { attributeIds, attributeTypes } = config; 35 | 36 | const dracoGeometry = new draco.Mesh(); 37 | const decodingStatus = decoder.DecodeArrayToMesh(array, array.byteLength, dracoGeometry); 38 | 39 | if (!decodingStatus.ok() || dracoGeometry.ptr === 0) 40 | postMessage({ id, error: `Decoding failed: ${decodingStatus.error_msg()}` }); 41 | 42 | const geometry = { index: null, attributes: [] }; 43 | 44 | // Gather all vertex attributes 45 | for (const attributeName in attributeIds) { 46 | const attributeType = self[attributeTypes[attributeName]]; 47 | const attribute = decoder.GetAttributeByUniqueId(dracoGeometry, attributeIds[attributeName]); 48 | const attributeResult = decodeAttribute(dracoGeometry, attributeName, attributeType, attribute); 49 | 50 | geometry.attributes.push(attributeResult); 51 | } 52 | 53 | // Add index 54 | geometry.index = decodeIndex(dracoGeometry); 55 | 56 | draco.destroy(dracoGeometry); 57 | // draco.destroy(decoder); 58 | 59 | // const elapsed = performance.now() - startTime; 60 | // console.log('decodeGeometry time', `${elapsed.toFixed(2)}ms`); 61 | 62 | // Transfer buffers 63 | const buffers = geometry.attributes.map((attr) => attr.array.buffer); 64 | if (geometry.index) buffers.push(geometry.index.array.buffer); 65 | 66 | postMessage( 67 | { 68 | id, 69 | geometry, 70 | }, 71 | buffers 72 | ); 73 | } 74 | 75 | // https://github.com/mrdoob/three.js/blob/master/examples/jsm/loaders/DRACOLoader.js 76 | 77 | function decodeIndex(dracoGeometry) { 78 | const numFaces = dracoGeometry.num_faces(); 79 | const numIndices = numFaces * 3; 80 | const byteLength = numIndices * 4; 81 | 82 | const ptr = draco._malloc(byteLength); 83 | decoder.GetTrianglesUInt32Array(dracoGeometry, byteLength, ptr); 84 | const index = new Uint32Array(draco.HEAPF32.buffer, ptr, numIndices).slice(); 85 | draco._free(ptr); 86 | 87 | return { array: index, itemSize: 1 }; 88 | } 89 | 90 | function decodeAttribute(dracoGeometry, attributeName, attributeType, attribute) { 91 | const numComponents = attribute.num_components(); 92 | const numPoints = dracoGeometry.num_points(); 93 | const numValues = numPoints * numComponents; 94 | const byteLength = numValues * attributeType.BYTES_PER_ELEMENT; 95 | const dataType = getDracoDataType(attributeType); 96 | 97 | const ptr = draco._malloc(byteLength); 98 | decoder.GetAttributeDataArrayForAllPoints(dracoGeometry, attribute, dataType, byteLength, ptr); 99 | const array = new attributeType(draco.HEAPF32.buffer, ptr, numValues).slice(); 100 | draco._free(ptr); 101 | 102 | return { 103 | name: attributeName, 104 | array, 105 | itemSize: numComponents, 106 | }; 107 | } 108 | 109 | function getDracoDataType(attributeType) { 110 | switch (attributeType) { 111 | case Float32Array: 112 | return draco.DT_FLOAT32; 113 | case Int8Array: 114 | return draco.DT_INT8; 115 | case Int16Array: 116 | return draco.DT_INT16; 117 | case Int32Array: 118 | return draco.DT_INT32; 119 | case Uint8Array: 120 | return draco.DT_UINT8; 121 | case Uint16Array: 122 | return draco.DT_UINT16; 123 | case Uint32Array: 124 | return draco.DT_UINT32; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /examples/assets/libs/draco/draco_decoder.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/libs/draco/draco_decoder.wasm -------------------------------------------------------------------------------- /examples/assets/libs/draco/gltf/draco_decoder.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/libs/draco/gltf/draco_decoder.wasm -------------------------------------------------------------------------------- /examples/assets/macaw.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/macaw.jpg -------------------------------------------------------------------------------- /examples/assets/main.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body, 6 | html { 7 | -webkit-font-smoothing: antialiased; 8 | -moz-osx-font-smoothing: grayscale; 9 | overflow-x: hidden; 10 | height: 100%; 11 | overscroll-behavior-y: contain; 12 | } 13 | 14 | body, 15 | button, 16 | p, 17 | ul { 18 | margin: 0; 19 | padding: 0; 20 | } 21 | 22 | button, 23 | select { 24 | border: none; 25 | outline: none; 26 | background: none; 27 | font-family: inherit; 28 | } 29 | 30 | a, 31 | button, 32 | input, 33 | select, 34 | textarea { 35 | -webkit-tap-highlight-color: transparent; 36 | } 37 | 38 | a { 39 | color: inherit; /* blue colors for links too */ 40 | text-decoration: inherit; /* no underline */ 41 | } 42 | 43 | :root { 44 | overflow-x: hidden; 45 | height: 100%; 46 | } 47 | 48 | @font-face { 49 | font-family: 'Raleway'; 50 | src: url('fonts/raleway-regular-webfont.woff2') format('woff2'), 51 | url('fonts/raleway-regular-webfont.woff') format('woff'); 52 | font-weight: 400; 53 | font-style: normal; 54 | } 55 | 56 | @font-face { 57 | font-family: 'Raleway'; 58 | src: url('fonts/raleway-bold-webfont.woff2') format('woff2'), 59 | url('fonts/raleway-bold-webfont.woff') format('woff'); 60 | font-weight: 700; 61 | font-style: normal; 62 | } 63 | 64 | body { 65 | font-family: 'Raleway', sans-serif; 66 | font-weight: 700; 67 | font-size: 14px; 68 | } 69 | 70 | .Side { 71 | position: relative; 72 | width: 300px; 73 | height: 100%; 74 | overflow: auto; 75 | padding-bottom: 100px; 76 | padding-left: 20px; 77 | padding-right: 40px; 78 | background: #fff; 79 | } 80 | .Iframe { 81 | position: absolute; 82 | left: 300px; 83 | right: 0; 84 | top: 0; 85 | bottom: 0; 86 | height: 100%; 87 | width: calc(100% - 300px); 88 | border: none; 89 | margin: 0; 90 | } 91 | .Title { 92 | font-size: 18px; 93 | margin: 20px 0; 94 | display: block; 95 | } 96 | .SubTitle { 97 | font-weight: 400; 98 | font-size: 17px; 99 | margin: 20px 0 50px; 100 | } 101 | .Section { 102 | font-weight: 400; 103 | margin: 40px 0 20px; 104 | padding-left: 15px; 105 | } 106 | .Example { 107 | margin: 10px 0; 108 | padding-left: 30px; 109 | display: block; 110 | } 111 | .Example.active { 112 | background-color: #3dd6ff; 113 | margin: 0px -40px 0px -20px; 114 | padding: 5px 0px 5px 50px; 115 | font-weight: bold; 116 | color: white; 117 | } 118 | div.Example { 119 | opacity: 0.2; 120 | } 121 | 122 | .SideIcon, 123 | .CodeIcon { 124 | position: absolute; 125 | display: block; 126 | z-index: 1; 127 | margin: 30px; 128 | width: 50px; 129 | height: 50px; 130 | line-height: 50px; 131 | text-align: center; 132 | background: #fff; 133 | border-radius: 100%; 134 | font-size: 19px; 135 | letter-spacing: -0.1em; 136 | box-shadow: 1px 1px 6px rgba(0, 0, 0, 0.1); 137 | } 138 | .CodeIcon { 139 | bottom: 0; 140 | right: 0; 141 | } 142 | .SideIcon { 143 | top: 20px; 144 | left: 245px; 145 | display: none; 146 | } 147 | 148 | @media (max-width: 600px) { 149 | .Side { 150 | z-index: 1; 151 | } 152 | .Iframe { 153 | left: 0; 154 | width: 100%; 155 | } 156 | .SideIcon { 157 | display: block; 158 | } 159 | [data-hideSidebar] .Side { 160 | transform: translateX(-100%); 161 | } 162 | 163 | [data-hideSidebar] .SideIcon { 164 | left: 0; 165 | transform: rotate(180deg); 166 | } 167 | } 168 | 169 | .Info { 170 | padding: 20px; 171 | position: relative; 172 | z-index: 1; 173 | } 174 | .Info a { 175 | color: rgb(39, 124, 235); 176 | } 177 | canvas { 178 | position: absolute; 179 | width: 100%; 180 | height: 100%; 181 | top: 0; 182 | left: 0; 183 | } 184 | 185 | #dropdown { 186 | margin: 1em 0em; 187 | } 188 | -------------------------------------------------------------------------------- /examples/assets/matcap.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/matcap.jpg -------------------------------------------------------------------------------- /examples/assets/octopus.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/octopus.jpg -------------------------------------------------------------------------------- /examples/assets/ogl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/ogl.png -------------------------------------------------------------------------------- /examples/assets/pbr/black.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/pbr/black.jpg -------------------------------------------------------------------------------- /examples/assets/pbr/car-ext-color.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/pbr/car-ext-color.jpg -------------------------------------------------------------------------------- /examples/assets/pbr/car-ext-emissive.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/pbr/car-ext-emissive.jpg -------------------------------------------------------------------------------- /examples/assets/pbr/car-ext-normal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/pbr/car-ext-normal.jpg -------------------------------------------------------------------------------- /examples/assets/pbr/car-ext-opacity.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/pbr/car-ext-opacity.jpg -------------------------------------------------------------------------------- /examples/assets/pbr/car-ext-rmo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/pbr/car-ext-rmo.jpg -------------------------------------------------------------------------------- /examples/assets/pbr/car-int-color.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/pbr/car-int-color.jpg -------------------------------------------------------------------------------- /examples/assets/pbr/car-int-normal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/pbr/car-int-normal.jpg -------------------------------------------------------------------------------- /examples/assets/pbr/car-int-rmo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/pbr/car-int-rmo.jpg -------------------------------------------------------------------------------- /examples/assets/pbr/car-shadow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/pbr/car-shadow.jpg -------------------------------------------------------------------------------- /examples/assets/pbr/car-shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/pbr/car-shadow.png -------------------------------------------------------------------------------- /examples/assets/pbr/lut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/pbr/lut.png -------------------------------------------------------------------------------- /examples/assets/pbr/waterfall-diffuse-RGBM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/pbr/waterfall-diffuse-RGBM.png -------------------------------------------------------------------------------- /examples/assets/pbr/waterfall-specular-RGBM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/pbr/waterfall-specular-RGBM.png -------------------------------------------------------------------------------- /examples/assets/pbr/white.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/pbr/white.jpg -------------------------------------------------------------------------------- /examples/assets/plane.json: -------------------------------------------------------------------------------- 1 | { 2 | "position": [0.0, -0.149, -1.543, -0.002, -0.288, 0.649, 0.242, 0.149, 0.589, 0.242, 0.149, 0.589, 0.681, -0.055, 0.618, 0.0, -0.149, -1.543, -0.221, 0.149, 0.589, -0.002, -0.288, 0.649, 0.0, -0.149, -1.543, -0.681, -0.055, 0.618, -0.221, 0.149, 0.589, 0.0, -0.149, -1.543], 3 | "normal": [-0.87, 0.491, 0.03, -0.87, 0.491, 0.03, -0.87, 0.491, 0.03, 0.425, 0.889, -0.172, 0.425, 0.889, -0.172, 0.425, 0.889, -0.172, 0.892, 0.451, 0.03, 0.892, 0.451, 0.03, 0.892, 0.451, 0.03, -0.409, 0.897, -0.168, -0.409, 0.897, -0.168, -0.409, 0.897, -0.168], 4 | "uv": [0.5, 1.0, 0.5, 0.0, 0.698, 0.0, 0.698, 0.0, 1.0, 0.0, 0.5, 1.0, 0.312, 0.0, 0.5, 0.0, 0.5, 1.0, 0.0, 0.0, 0.312, 0.0, 0.5, 1.0] 5 | } -------------------------------------------------------------------------------- /examples/assets/saddle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/saddle.jpg -------------------------------------------------------------------------------- /examples/assets/sky.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/sky.jpg -------------------------------------------------------------------------------- /examples/assets/snout-shadow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/snout-shadow.jpg -------------------------------------------------------------------------------- /examples/assets/snout.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/snout.jpg -------------------------------------------------------------------------------- /examples/assets/sunset-diffuse-RGBM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/sunset-diffuse-RGBM.png -------------------------------------------------------------------------------- /examples/assets/sunset-specular-RGBM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/sunset-specular-RGBM.png -------------------------------------------------------------------------------- /examples/assets/sunset.exr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/sunset.exr -------------------------------------------------------------------------------- /examples/assets/uv.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/uv.jpg -------------------------------------------------------------------------------- /examples/assets/water.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/water.jpg -------------------------------------------------------------------------------- /examples/assets/windmill.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oframe/ogl/385ce65c352c70734a36dc98c787fdd1d30ddb3b/examples/assets/windmill.jpg -------------------------------------------------------------------------------- /examples/load-json.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | OGL • Load JSON 10 | 11 | 12 | 13 |
Load JSON (Javascript Object Notation). Model by Google Poly
14 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /examples/skydome.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | OGL • Skydome 10 | 11 | 12 | 13 |
Skydome. Image credit charlesashaw.
14 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /examples/torus.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | OGL • Torus 10 | 11 | 12 | 13 |
Torus
14 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /examples/triangle-screen-shader.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | OGL • Triangle Screen Shader 10 | 11 | 12 | 13 |
Triangle Screen Shader
14 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /examples/wire-mesh.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | OGL • WireMesh 10 | 11 | 12 | 13 |
WireMesh (wireframe). Model by Google Poly
14 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ogl", 3 | "version": "1.0.11", 4 | "description": "WebGL Library", 5 | "type": "module", 6 | "main": "./src/index.js", 7 | "exports": { 8 | ".": { 9 | "types": "./types/index.d.ts", 10 | "default": "./src/index.js" 11 | }, 12 | "./src/*": "./src/*" 13 | }, 14 | "sideEffects": false, 15 | "types": "./types/index.d.ts", 16 | "directories": { 17 | "example": "examples" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://gordonnl@github.com/oframe/ogl.git" 22 | }, 23 | "author": { 24 | "name": "Nathan Gordon", 25 | "email": "gordonnl@gmail.com", 26 | "url": "https://twitter.com/gordonnl" 27 | }, 28 | "license": "Unlicense", 29 | "bugs": { 30 | "url": "https://github.com/oframe/ogl/issues" 31 | }, 32 | "homepage": "https://github.com/oframe/ogl#readme", 33 | "prettier": { 34 | "arrowParens": "always", 35 | "bracketSpacing": true, 36 | "endOfLine": "lf", 37 | "htmlWhitespaceSensitivity": "css", 38 | "printWidth": 200, 39 | "quoteProps": "as-needed", 40 | "semi": true, 41 | "singleQuote": true, 42 | "tabWidth": 4, 43 | "trailingComma": "es5", 44 | "useTabs": false 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/core/Mesh.js: -------------------------------------------------------------------------------- 1 | import { Transform } from './Transform.js'; 2 | import { Mat3 } from '../math/Mat3.js'; 3 | import { Mat4 } from '../math/Mat4.js'; 4 | 5 | let ID = 0; 6 | 7 | export class Mesh extends Transform { 8 | constructor(gl, { geometry, program, mode = gl.TRIANGLES, frustumCulled = true, renderOrder = 0 } = {}) { 9 | super(); 10 | if (!gl.canvas) console.error('gl not passed as first argument to Mesh'); 11 | this.gl = gl; 12 | this.id = ID++; 13 | this.geometry = geometry; 14 | this.program = program; 15 | this.mode = mode; 16 | 17 | // Used to skip frustum culling 18 | this.frustumCulled = frustumCulled; 19 | 20 | // Override sorting to force an order 21 | this.renderOrder = renderOrder; 22 | this.modelViewMatrix = new Mat4(); 23 | this.normalMatrix = new Mat3(); 24 | this.beforeRenderCallbacks = []; 25 | this.afterRenderCallbacks = []; 26 | } 27 | 28 | onBeforeRender(f) { 29 | this.beforeRenderCallbacks.push(f); 30 | return this; 31 | } 32 | 33 | onAfterRender(f) { 34 | this.afterRenderCallbacks.push(f); 35 | return this; 36 | } 37 | 38 | draw({ camera } = {}) { 39 | if (camera) { 40 | // Add empty matrix uniforms to program if unset 41 | if (!this.program.uniforms.modelMatrix) { 42 | Object.assign(this.program.uniforms, { 43 | modelMatrix: { value: null }, 44 | viewMatrix: { value: null }, 45 | modelViewMatrix: { value: null }, 46 | normalMatrix: { value: null }, 47 | projectionMatrix: { value: null }, 48 | cameraPosition: { value: null }, 49 | }); 50 | } 51 | 52 | // Set the matrix uniforms 53 | this.program.uniforms.projectionMatrix.value = camera.projectionMatrix; 54 | this.program.uniforms.cameraPosition.value = camera.worldPosition; 55 | this.program.uniforms.viewMatrix.value = camera.viewMatrix; 56 | this.modelViewMatrix.multiply(camera.viewMatrix, this.worldMatrix); 57 | this.normalMatrix.getNormalMatrix(this.modelViewMatrix); 58 | this.program.uniforms.modelMatrix.value = this.worldMatrix; 59 | this.program.uniforms.modelViewMatrix.value = this.modelViewMatrix; 60 | this.program.uniforms.normalMatrix.value = this.normalMatrix; 61 | } 62 | this.beforeRenderCallbacks.forEach((f) => f && f({ mesh: this, camera })); 63 | 64 | // determine if faces need to be flipped - when mesh scaled negatively 65 | let flipFaces = this.program.cullFace && this.worldMatrix.determinant() < 0; 66 | this.program.use({ flipFaces }); 67 | this.geometry.draw({ mode: this.mode, program: this.program }); 68 | this.afterRenderCallbacks.forEach((f) => f && f({ mesh: this, camera })); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/core/Transform.js: -------------------------------------------------------------------------------- 1 | import { Vec3 } from '../math/Vec3.js'; 2 | import { Quat } from '../math/Quat.js'; 3 | import { Mat4 } from '../math/Mat4.js'; 4 | import { Euler } from '../math/Euler.js'; 5 | 6 | export class Transform { 7 | constructor() { 8 | this.parent = null; 9 | this.children = []; 10 | this.visible = true; 11 | 12 | this.matrix = new Mat4(); 13 | this.worldMatrix = new Mat4(); 14 | this.matrixAutoUpdate = true; 15 | this.worldMatrixNeedsUpdate = false; 16 | 17 | this.position = new Vec3(); 18 | this.quaternion = new Quat(); 19 | this.scale = new Vec3(1); 20 | this.rotation = new Euler(); 21 | this.up = new Vec3(0, 1, 0); 22 | 23 | this.rotation._target.onChange = () => this.quaternion.fromEuler(this.rotation, true); 24 | this.quaternion._target.onChange = () => this.rotation.fromQuaternion(this.quaternion, undefined, true); 25 | } 26 | 27 | setParent(parent, notifyParent = true) { 28 | if (this.parent && parent !== this.parent) this.parent.removeChild(this, false); 29 | this.parent = parent; 30 | if (notifyParent && parent) parent.addChild(this, false); 31 | } 32 | 33 | addChild(child, notifyChild = true) { 34 | if (!~this.children.indexOf(child)) this.children.push(child); 35 | if (notifyChild) child.setParent(this, false); 36 | } 37 | 38 | removeChild(child, notifyChild = true) { 39 | if (!!~this.children.indexOf(child)) this.children.splice(this.children.indexOf(child), 1); 40 | if (notifyChild) child.setParent(null, false); 41 | } 42 | 43 | updateMatrixWorld(force) { 44 | if (this.matrixAutoUpdate) this.updateMatrix(); 45 | if (this.worldMatrixNeedsUpdate || force) { 46 | if (this.parent === null) this.worldMatrix.copy(this.matrix); 47 | else this.worldMatrix.multiply(this.parent.worldMatrix, this.matrix); 48 | this.worldMatrixNeedsUpdate = false; 49 | force = true; 50 | } 51 | 52 | for (let i = 0, l = this.children.length; i < l; i++) { 53 | this.children[i].updateMatrixWorld(force); 54 | } 55 | } 56 | 57 | updateMatrix() { 58 | this.matrix.compose(this.quaternion, this.position, this.scale); 59 | this.worldMatrixNeedsUpdate = true; 60 | } 61 | 62 | traverse(callback) { 63 | // Return true in callback to stop traversing children 64 | if (callback(this)) return; 65 | for (let i = 0, l = this.children.length; i < l; i++) { 66 | this.children[i].traverse(callback); 67 | } 68 | } 69 | 70 | decompose() { 71 | this.matrix.decompose(this.quaternion._target, this.position, this.scale); 72 | this.rotation.fromQuaternion(this.quaternion); 73 | } 74 | 75 | lookAt(target, invert = false) { 76 | if (invert) this.matrix.lookAt(this.position, target, this.up); 77 | else this.matrix.lookAt(target, this.position, this.up); 78 | this.matrix.getRotation(this.quaternion._target); 79 | this.rotation.fromQuaternion(this.quaternion); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/extras/Animation.js: -------------------------------------------------------------------------------- 1 | import { Vec3 } from '../math/Vec3.js'; 2 | import { Quat } from '../math/Quat.js'; 3 | 4 | const prevPos = /* @__PURE__ */ new Vec3(); 5 | const prevRot = /* @__PURE__ */ new Quat(); 6 | const prevScl = /* @__PURE__ */ new Vec3(); 7 | 8 | const nextPos = /* @__PURE__ */ new Vec3(); 9 | const nextRot = /* @__PURE__ */ new Quat(); 10 | const nextScl = /* @__PURE__ */ new Vec3(); 11 | 12 | export class Animation { 13 | constructor({ objects, data }) { 14 | this.objects = objects; 15 | this.data = data; 16 | this.elapsed = 0; 17 | this.weight = 1; 18 | this.duration = data.frames.length - 1; 19 | } 20 | 21 | update(totalWeight = 1, isSet) { 22 | const weight = isSet ? 1 : this.weight / totalWeight; 23 | const elapsed = this.elapsed % this.duration; 24 | 25 | const floorFrame = Math.floor(elapsed); 26 | const blend = elapsed - floorFrame; 27 | const prevKey = this.data.frames[floorFrame]; 28 | const nextKey = this.data.frames[(floorFrame + 1) % this.duration]; 29 | 30 | this.objects.forEach((object, i) => { 31 | prevPos.fromArray(prevKey.position, i * 3); 32 | prevRot.fromArray(prevKey.quaternion, i * 4); 33 | prevScl.fromArray(prevKey.scale, i * 3); 34 | 35 | nextPos.fromArray(nextKey.position, i * 3); 36 | nextRot.fromArray(nextKey.quaternion, i * 4); 37 | nextScl.fromArray(nextKey.scale, i * 3); 38 | 39 | prevPos.lerp(nextPos, blend); 40 | prevRot.slerp(nextRot, blend); 41 | prevScl.lerp(nextScl, blend); 42 | 43 | object.position.lerp(prevPos, weight); 44 | object.quaternion.slerp(prevRot, weight); 45 | object.scale.lerp(prevScl, weight); 46 | }); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/extras/BasisManager.js: -------------------------------------------------------------------------------- 1 | let supportedFormat; 2 | let id = 0; 3 | 4 | export class BasisManager { 5 | constructor(workerSrc, gl) { 6 | if (!supportedFormat) supportedFormat = this.getSupportedFormat(gl); 7 | this.onMessage = this.onMessage.bind(this); 8 | this.queue = new Map(); 9 | this.initWorker(workerSrc); 10 | } 11 | 12 | getSupportedFormat(gl = document.createElement('canvas').getContext('webgl')) { 13 | /* if (!!gl.getExtension('WEBGL_compressed_texture_etc')) { 14 | return 'etc2'; 15 | } else */ 16 | if (!!gl.getExtension('WEBGL_compressed_texture_astc')) { 17 | return 'astc'; 18 | } else if (!!gl.getExtension('EXT_texture_compression_bptc')) { 19 | return 'bptc'; 20 | } else if (!!gl.getExtension('WEBGL_compressed_texture_s3tc')) { 21 | return 's3tc'; 22 | } else if (!!gl.getExtension('WEBGL_compressed_texture_etc1')) { 23 | return 'etc1'; 24 | } else if (!!gl.getExtension('WEBGL_compressed_texture_pvrtc') || !!gl.getExtension('WEBKIT_WEBGL_compressed_texture_pvrtc')) { 25 | return 'pvrtc'; 26 | // } else if (!!gl.getExtension('WEBGL_compressed_texture_atc')) { 27 | // return 'atc'; 28 | } 29 | return 'none'; 30 | } 31 | 32 | initWorker(workerSrc) { 33 | this.worker = new Worker(workerSrc); 34 | this.worker.onmessage = this.onMessage; 35 | } 36 | 37 | onMessage({ data }) { 38 | const { id, error, image } = data; 39 | if (error) { 40 | console.log(error, id); 41 | return; 42 | } 43 | const textureResolve = this.queue.get(id); 44 | this.queue.delete(id); 45 | image.isBasis = true; 46 | textureResolve(image); 47 | } 48 | 49 | parseTexture(buffer) { 50 | id++; 51 | this.worker.postMessage({ 52 | id, 53 | buffer, 54 | supportedFormat, 55 | }); 56 | let textureResolve; 57 | const promise = new Promise((res) => (textureResolve = res)); 58 | this.queue.set(id, textureResolve); 59 | return promise; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/extras/Box.js: -------------------------------------------------------------------------------- 1 | import { Geometry } from '../core/Geometry.js'; 2 | import { Plane } from './Plane.js'; 3 | 4 | export class Box extends Geometry { 5 | constructor(gl, { width = 1, height = 1, depth = 1, widthSegments = 1, heightSegments = 1, depthSegments = 1, attributes = {} } = {}) { 6 | const wSegs = widthSegments; 7 | const hSegs = heightSegments; 8 | const dSegs = depthSegments; 9 | 10 | const num = (wSegs + 1) * (hSegs + 1) * 2 + (wSegs + 1) * (dSegs + 1) * 2 + (hSegs + 1) * (dSegs + 1) * 2; 11 | const numIndices = (wSegs * hSegs * 2 + wSegs * dSegs * 2 + hSegs * dSegs * 2) * 6; 12 | 13 | const position = new Float32Array(num * 3); 14 | const normal = new Float32Array(num * 3); 15 | const uv = new Float32Array(num * 2); 16 | const index = num > 65536 ? new Uint32Array(numIndices) : new Uint16Array(numIndices); 17 | 18 | let i = 0; 19 | let ii = 0; 20 | 21 | // left, right 22 | Plane.buildPlane(position, normal, uv, index, depth, height, width, dSegs, hSegs, 2, 1, 0, -1, -1, i, ii); 23 | i += (dSegs + 1) * (hSegs + 1); 24 | ii += dSegs * hSegs; 25 | 26 | Plane.buildPlane(position, normal, uv, index, depth, height, -width, dSegs, hSegs, 2, 1, 0, 1, -1, i, ii); 27 | i += (dSegs + 1) * (hSegs + 1); 28 | ii += dSegs * hSegs; 29 | 30 | // top, bottom 31 | Plane.buildPlane(position, normal, uv, index, width, depth, height, dSegs, wSegs, 0, 2, 1, 1, 1, i, ii); 32 | i += (wSegs + 1) * (dSegs + 1); 33 | ii += wSegs * dSegs; 34 | 35 | Plane.buildPlane(position, normal, uv, index, width, depth, -height, dSegs, wSegs, 0, 2, 1, 1, -1, i, ii); 36 | i += (wSegs + 1) * (dSegs + 1); 37 | ii += wSegs * dSegs; 38 | 39 | // front, back 40 | Plane.buildPlane(position, normal, uv, index, width, height, -depth, wSegs, hSegs, 0, 1, 2, -1, -1, i, ii); 41 | i += (wSegs + 1) * (hSegs + 1); 42 | ii += wSegs * hSegs; 43 | 44 | Plane.buildPlane(position, normal, uv, index, width, height, depth, wSegs, hSegs, 0, 1, 2, 1, -1, i, ii); 45 | 46 | Object.assign(attributes, { 47 | position: { size: 3, data: position }, 48 | normal: { size: 3, data: normal }, 49 | uv: { size: 2, data: uv }, 50 | index: { data: index }, 51 | }); 52 | 53 | super(gl, attributes); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/extras/DracoManager.js: -------------------------------------------------------------------------------- 1 | let id = 0; 2 | 3 | export class DracoManager { 4 | constructor(workerSrc) { 5 | this.onMessage = this.onMessage.bind(this); 6 | this.queue = new Map(); 7 | this.initWorker(workerSrc); 8 | } 9 | 10 | initWorker(workerSrc) { 11 | this.worker = new Worker(workerSrc); 12 | this.worker.onmessage = this.onMessage; 13 | } 14 | 15 | onMessage({ data }) { 16 | const { id, error, geometry } = data; 17 | if (error) { 18 | console.log(error, id); 19 | return; 20 | } 21 | const geometryResolve = this.queue.get(id); 22 | this.queue.delete(id); 23 | geometryResolve(geometry); 24 | } 25 | 26 | decodeGeometry(buffer, config) { 27 | id++; 28 | this.worker.postMessage({ 29 | id, 30 | buffer, 31 | config, 32 | }); 33 | let geometryResolve; 34 | const promise = new Promise((res) => (geometryResolve = res)); 35 | this.queue.set(id, geometryResolve); 36 | return promise; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/extras/GLTFSkin.js: -------------------------------------------------------------------------------- 1 | import { Mesh } from '../core/Mesh.js'; 2 | import { Mat4 } from '../math/Mat4.js'; 3 | import { Texture } from '../core/Texture.js'; 4 | 5 | const tempMat4 = /* @__PURE__ */ new Mat4(); 6 | const identity = /* @__PURE__ */ new Mat4(); 7 | 8 | export class GLTFSkin extends Mesh { 9 | constructor(gl, { skeleton, geometry, program, mode = gl.TRIANGLES } = {}) { 10 | super(gl, { geometry, program, mode }); 11 | this.skeleton = skeleton; 12 | this.program = program; 13 | this.createBoneTexture(); 14 | } 15 | 16 | createBoneTexture() { 17 | if (!this.skeleton.joints.length) return; 18 | const size = Math.max(4, Math.pow(2, Math.ceil(Math.log(Math.sqrt(this.skeleton.joints.length * 4)) / Math.LN2))); 19 | this.boneMatrices = new Float32Array(size * size * 4); 20 | this.boneTextureSize = size; 21 | this.boneTexture = new Texture(this.gl, { 22 | image: this.boneMatrices, 23 | generateMipmaps: false, 24 | type: this.gl.FLOAT, 25 | internalFormat: this.gl.renderer.isWebgl2 ? this.gl.RGBA32F : this.gl.RGBA, 26 | minFilter: this.gl.NEAREST, 27 | magFilter: this.gl.NEAREST, 28 | flipY: false, 29 | width: size, 30 | }); 31 | } 32 | 33 | updateUniforms() { 34 | // Update bone texture 35 | this.skeleton.joints.forEach((bone, i) => { 36 | // Find difference between current and bind pose 37 | tempMat4.multiply(bone.worldMatrix, bone.bindInverse); 38 | this.boneMatrices.set(tempMat4, i * 16); 39 | }); 40 | this.boneTexture.needsUpdate = true; 41 | // Reset for programs shared between multiple skins 42 | this.program.uniforms.boneTexture.value = this.boneTexture; 43 | this.program.uniforms.boneTextureSize.value = this.boneTextureSize; 44 | } 45 | 46 | draw({ camera } = {}) { 47 | if (!this.program.uniforms.boneTexture) { 48 | Object.assign(this.program.uniforms, { 49 | boneTexture: { value: this.boneTexture }, 50 | boneTextureSize: { value: this.boneTextureSize }, 51 | }); 52 | } 53 | 54 | this.updateUniforms(); 55 | 56 | // Switch the world matrix with identity to ignore any transforms 57 | // on the mesh itself - only use skeleton's transforms 58 | const _worldMatrix = this.worldMatrix; 59 | this.worldMatrix = identity; 60 | 61 | super.draw({ camera }); 62 | 63 | // Switch back to leave identity untouched 64 | this.worldMatrix = _worldMatrix; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/extras/InstancedMesh.js: -------------------------------------------------------------------------------- 1 | import { Transform } from '../core/Transform.js'; 2 | import { Mesh } from '../core/Mesh.js'; 3 | import { Vec4 } from '../math/Vec4.js'; 4 | 5 | export class InstancedMesh extends Mesh { 6 | constructor(...args) { 7 | super(...args); 8 | 9 | // Skip renderer frustum culling 10 | this.frustumCulled = false; 11 | this.isInstancedMesh = true; 12 | } 13 | 14 | addFrustumCull() { 15 | this.instanceTransforms = null; 16 | this.instanceLightmapScaleOffset = null; 17 | this.totalInstanceCount = 0; 18 | this.frustumCullFunction = null; 19 | this.instanceRenderList = null; 20 | 21 | // Get instanced mesh 22 | if (!this.geometry.attributes.instanceMatrix) 23 | console.error(`mesh ${this.name ? `"${this.name}" ` : ``}missing instanceMatrix attribute; unable to frustum cull`); 24 | 25 | // Make list of transforms from instanceMatrix 26 | const matrixData = this.geometry.attributes.instanceMatrix.data; 27 | this.instanceTransforms = []; 28 | for (let i = 0, j = 0; i < matrixData.length; i += 16, j++) { 29 | const transform = new Transform(); 30 | transform.index = j; 31 | transform.matrix.fromArray(matrixData, i); 32 | transform.decompose(); 33 | this.instanceTransforms.push(transform); 34 | // Add transforms to parent to update world matrices 35 | transform.setParent(this.parent); 36 | } 37 | this.totalInstanceCount = this.instanceTransforms.length; 38 | 39 | // Check for lightmap attributes - attach to transform 40 | if (!!this.geometry.attributes.lightmapScaleOffset) { 41 | const lightmapData = this.geometry.attributes.lightmapScaleOffset.data; 42 | for (let i = 0, j = 0; i < lightmapData.length; i += 4, j++) { 43 | this.instanceTransforms[j].lightmapData = new Vec4().fromArray(lightmapData, i); 44 | } 45 | } 46 | 47 | this.frustumCullFunction = ({ camera }) => { 48 | // frustum cull transforms each frame - pass world matrix 49 | this.instanceRenderList = []; 50 | this.instanceTransforms.forEach((transform) => { 51 | if (!camera.frustumIntersectsMesh(this, transform.worldMatrix)) return; 52 | this.instanceRenderList.push(transform); 53 | }); 54 | 55 | // update instanceMatrix and instancedCount with visible 56 | this.instanceRenderList.forEach((transform, i) => { 57 | transform.matrix.toArray(this.geometry.attributes.instanceMatrix.data, i * 16); 58 | 59 | // Update lightmap attr 60 | if (transform.lightmapData) { 61 | transform.lightmapData.toArray(this.geometry.attributes.lightmapScaleOffset.data, i * 4); 62 | this.geometry.attributes.lightmapScaleOffset.needsUpdate = true; 63 | } 64 | }); 65 | this.geometry.instancedCount = this.instanceRenderList.length; 66 | this.geometry.attributes.instanceMatrix.needsUpdate = true; 67 | }; 68 | 69 | this.onBeforeRender(this.frustumCullFunction); 70 | } 71 | 72 | removeFrustumCull() { 73 | this.offBeforeRender(this.frustumCullFunction); 74 | this.geometry.instancedCount = this.totalInstanceCount; 75 | this.instanceTransforms.forEach((transform, i) => { 76 | transform.matrix.toArray(this.geometry.attributes.instanceMatrix.data, i * 16); 77 | 78 | // Update lightmap attr 79 | if (transform.lightmapData) { 80 | transform.lightmapData.toArray(this.geometry.attributes.lightmapScaleOffset.data, i * 4); 81 | this.geometry.attributes.lightmapScaleOffset.needsUpdate = true; 82 | } 83 | }); 84 | this.geometry.attributes.instanceMatrix.needsUpdate = true; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/extras/KTXTexture.js: -------------------------------------------------------------------------------- 1 | import { Texture } from '../core/Texture.js'; 2 | 3 | // TODO: Support cubemaps 4 | // Generate textures using https://github.com/TimvanScherpenzeel/texture-compressor 5 | 6 | export class KTXTexture extends Texture { 7 | constructor(gl, { buffer, wrapS = gl.CLAMP_TO_EDGE, wrapT = gl.CLAMP_TO_EDGE, anisotropy = 0, minFilter, magFilter } = {}) { 8 | super(gl, { 9 | generateMipmaps: false, 10 | wrapS, 11 | wrapT, 12 | anisotropy, 13 | minFilter, 14 | magFilter, 15 | }); 16 | 17 | if (buffer) return this.parseBuffer(buffer); 18 | } 19 | 20 | parseBuffer(buffer) { 21 | const ktx = new KhronosTextureContainer(buffer); 22 | ktx.mipmaps.isCompressedTexture = true; 23 | 24 | // Update texture 25 | this.image = ktx.mipmaps; 26 | this.internalFormat = ktx.glInternalFormat; 27 | if (ktx.numberOfMipmapLevels > 1) { 28 | if (this.minFilter === this.gl.LINEAR) this.minFilter = this.gl.NEAREST_MIPMAP_LINEAR; 29 | } else { 30 | if (this.minFilter === this.gl.NEAREST_MIPMAP_LINEAR) this.minFilter = this.gl.LINEAR; 31 | } 32 | 33 | // TODO: support cube maps 34 | // ktx.numberOfFaces 35 | } 36 | } 37 | 38 | function KhronosTextureContainer(buffer) { 39 | const idCheck = [0xab, 0x4b, 0x54, 0x58, 0x20, 0x31, 0x31, 0xbb, 0x0d, 0x0a, 0x1a, 0x0a]; 40 | const id = new Uint8Array(buffer, 0, 12); 41 | for (let i = 0; i < id.length; i++) if (id[i] !== idCheck[i]) return console.error('File missing KTX identifier'); 42 | 43 | // TODO: Is this always 4? Tested: [android, macos] 44 | const size = Uint32Array.BYTES_PER_ELEMENT; 45 | const head = new DataView(buffer, 12, 13 * size); 46 | const littleEndian = head.getUint32(0, true) === 0x04030201; 47 | const glType = head.getUint32(1 * size, littleEndian); 48 | if (glType !== 0) return console.warn('only compressed formats currently supported'); 49 | this.glInternalFormat = head.getUint32(4 * size, littleEndian); 50 | let width = head.getUint32(6 * size, littleEndian); 51 | let height = head.getUint32(7 * size, littleEndian); 52 | this.numberOfFaces = head.getUint32(10 * size, littleEndian); 53 | this.numberOfMipmapLevels = Math.max(1, head.getUint32(11 * size, littleEndian)); 54 | const bytesOfKeyValueData = head.getUint32(12 * size, littleEndian); 55 | 56 | this.mipmaps = []; 57 | let offset = 12 + 13 * 4 + bytesOfKeyValueData; 58 | for (let level = 0; level < this.numberOfMipmapLevels; level++) { 59 | const levelSize = new Int32Array(buffer, offset, 1)[0]; // size per face, since not supporting array cubemaps 60 | offset += 4; // levelSize field 61 | for (let face = 0; face < this.numberOfFaces; face++) { 62 | const data = new Uint8Array(buffer, offset, levelSize); 63 | this.mipmaps.push({ data, width, height }); 64 | offset += levelSize; 65 | offset += 3 - ((levelSize + 3) % 4); // add padding for odd sized image 66 | } 67 | width = width >> 1; 68 | height = height >> 1; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/extras/NormalProgram.js: -------------------------------------------------------------------------------- 1 | import { Program } from '../core/Program.js'; 2 | 3 | const vertex = /* glsl */ ` 4 | precision highp float; 5 | precision highp int; 6 | 7 | attribute vec3 position; 8 | attribute vec3 normal; 9 | 10 | uniform mat3 normalMatrix; 11 | uniform mat4 modelViewMatrix; 12 | uniform mat4 projectionMatrix; 13 | 14 | varying vec3 vNormal; 15 | 16 | void main() { 17 | vNormal = normalize(normalMatrix * normal); 18 | gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 19 | } 20 | `; 21 | 22 | const fragment = /* glsl */ ` 23 | precision highp float; 24 | precision highp int; 25 | 26 | varying vec3 vNormal; 27 | 28 | void main() { 29 | gl_FragColor.rgb = normalize(vNormal); 30 | gl_FragColor.a = 1.0; 31 | } 32 | `; 33 | 34 | export function NormalProgram(gl) { 35 | return new Program(gl, { 36 | vertex: vertex, 37 | fragment: fragment, 38 | cullFace: false, 39 | }); 40 | } 41 | -------------------------------------------------------------------------------- /src/extras/Plane.js: -------------------------------------------------------------------------------- 1 | import { Geometry } from '../core/Geometry.js'; 2 | 3 | export class Plane extends Geometry { 4 | constructor(gl, { width = 1, height = 1, widthSegments = 1, heightSegments = 1, attributes = {} } = {}) { 5 | const wSegs = widthSegments; 6 | const hSegs = heightSegments; 7 | 8 | // Determine length of arrays 9 | const num = (wSegs + 1) * (hSegs + 1); 10 | const numIndices = wSegs * hSegs * 6; 11 | 12 | // Generate empty arrays once 13 | const position = new Float32Array(num * 3); 14 | const normal = new Float32Array(num * 3); 15 | const uv = new Float32Array(num * 2); 16 | const index = numIndices > 65536 ? new Uint32Array(numIndices) : new Uint16Array(numIndices); 17 | 18 | Plane.buildPlane(position, normal, uv, index, width, height, 0, wSegs, hSegs); 19 | 20 | Object.assign(attributes, { 21 | position: { size: 3, data: position }, 22 | normal: { size: 3, data: normal }, 23 | uv: { size: 2, data: uv }, 24 | index: { data: index }, 25 | }); 26 | 27 | super(gl, attributes); 28 | } 29 | 30 | static buildPlane(position, normal, uv, index, width, height, depth, wSegs, hSegs, u = 0, v = 1, w = 2, uDir = 1, vDir = -1, i = 0, ii = 0) { 31 | const io = i; 32 | const segW = width / wSegs; 33 | const segH = height / hSegs; 34 | 35 | for (let iy = 0; iy <= hSegs; iy++) { 36 | let y = iy * segH - height / 2; 37 | for (let ix = 0; ix <= wSegs; ix++, i++) { 38 | let x = ix * segW - width / 2; 39 | 40 | position[i * 3 + u] = x * uDir; 41 | position[i * 3 + v] = y * vDir; 42 | position[i * 3 + w] = depth / 2; 43 | 44 | normal[i * 3 + u] = 0; 45 | normal[i * 3 + v] = 0; 46 | normal[i * 3 + w] = depth >= 0 ? 1 : -1; 47 | 48 | uv[i * 2] = ix / wSegs; 49 | uv[i * 2 + 1] = 1 - iy / hSegs; 50 | 51 | if (iy === hSegs || ix === wSegs) continue; 52 | let a = io + ix + iy * (wSegs + 1); 53 | let b = io + ix + (iy + 1) * (wSegs + 1); 54 | let c = io + ix + (iy + 1) * (wSegs + 1) + 1; 55 | let d = io + ix + iy * (wSegs + 1) + 1; 56 | 57 | index[ii * 6] = a; 58 | index[ii * 6 + 1] = b; 59 | index[ii * 6 + 2] = d; 60 | index[ii * 6 + 3] = b; 61 | index[ii * 6 + 4] = c; 62 | index[ii * 6 + 5] = d; 63 | ii++; 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/extras/Shadow.js: -------------------------------------------------------------------------------- 1 | import { Camera } from '../core/Camera.js'; 2 | import { Program } from '../core/Program.js'; 3 | import { RenderTarget } from '../core/RenderTarget.js'; 4 | 5 | export class Shadow { 6 | constructor(gl, { light = new Camera(gl), width = 1024, height = width }) { 7 | this.gl = gl; 8 | 9 | this.light = light; 10 | 11 | this.target = new RenderTarget(gl, { width, height }); 12 | this.targetUniform = { value: this.target.texture }; 13 | 14 | this.depthProgram = new Program(gl, { 15 | vertex: defaultVertex, 16 | fragment: defaultFragment, 17 | cullFace: false, 18 | }); 19 | 20 | this.castMeshes = []; 21 | } 22 | 23 | add({ 24 | mesh, 25 | receive = true, 26 | cast = true, 27 | vertex = defaultVertex, 28 | fragment = defaultFragment, 29 | uniformProjection = 'shadowProjectionMatrix', 30 | uniformView = 'shadowViewMatrix', 31 | uniformTexture = 'tShadow', 32 | }) { 33 | // Add uniforms to existing program 34 | if (receive && !mesh.program.uniforms[uniformProjection]) { 35 | mesh.program.uniforms[uniformProjection] = { value: this.light.projectionMatrix }; 36 | mesh.program.uniforms[uniformView] = { value: this.light.viewMatrix }; 37 | mesh.program.uniforms[uniformTexture] = this.targetUniform; 38 | } 39 | 40 | if (!cast) return; 41 | this.castMeshes.push(mesh); 42 | 43 | // Store program for when switching between depth override 44 | mesh.colorProgram = mesh.program; 45 | 46 | // Check if depth program already attached 47 | if (mesh.depthProgram) return; 48 | 49 | // Use global depth override if nothing custom passed in 50 | if (vertex === defaultVertex && fragment === defaultFragment) { 51 | mesh.depthProgram = this.depthProgram; 52 | return; 53 | } 54 | 55 | // Create custom override program 56 | mesh.depthProgram = new Program(this.gl, { 57 | vertex, 58 | fragment, 59 | cullFace: false, 60 | }); 61 | } 62 | 63 | setSize({ width = 1024, height = width }) { 64 | this.target = new RenderTarget(this.gl, { width, height }); 65 | this.targetUniform.value = this.target.texture; 66 | } 67 | 68 | render({ scene }) { 69 | // For depth render, replace program with depth override. 70 | // Hide meshes not casting shadows. 71 | scene.traverse((node) => { 72 | if (!node.draw) return; 73 | if (!!~this.castMeshes.indexOf(node)) { 74 | node.program = node.depthProgram; 75 | } else { 76 | node.isForceVisibility = node.visible; 77 | node.visible = false; 78 | } 79 | }); 80 | 81 | // Render the depth shadow map using the light as the camera 82 | this.gl.renderer.render({ 83 | scene, 84 | camera: this.light, 85 | target: this.target, 86 | }); 87 | 88 | // Then switch the program back to the normal one 89 | scene.traverse((node) => { 90 | if (!node.draw) return; 91 | if (!!~this.castMeshes.indexOf(node)) { 92 | node.program = node.colorProgram; 93 | } else { 94 | node.visible = node.isForceVisibility; 95 | } 96 | }); 97 | } 98 | } 99 | 100 | const defaultVertex = /* glsl */ ` 101 | attribute vec3 position; 102 | attribute vec2 uv; 103 | 104 | uniform mat4 modelViewMatrix; 105 | uniform mat4 projectionMatrix; 106 | 107 | void main() { 108 | gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 109 | } 110 | `; 111 | 112 | const defaultFragment = /* glsl */ ` 113 | precision highp float; 114 | 115 | vec4 packRGBA (float v) { 116 | vec4 pack = fract(vec4(1.0, 255.0, 65025.0, 16581375.0) * v); 117 | pack -= pack.yzww * vec2(1.0 / 255.0, 0.0).xxxy; 118 | return pack; 119 | } 120 | 121 | void main() { 122 | gl_FragColor = packRGBA(gl_FragCoord.z); 123 | } 124 | `; 125 | -------------------------------------------------------------------------------- /src/extras/Skin.js: -------------------------------------------------------------------------------- 1 | import { Mesh } from '../core/Mesh.js'; 2 | import { Transform } from '../core/Transform.js'; 3 | import { Mat4 } from '../math/Mat4.js'; 4 | import { Texture } from '../core/Texture.js'; 5 | import { Animation } from './Animation.js'; 6 | 7 | const tempMat4 = /* @__PURE__ */ new Mat4(); 8 | 9 | export class Skin extends Mesh { 10 | constructor(gl, { rig, geometry, program, mode = gl.TRIANGLES } = {}) { 11 | super(gl, { geometry, program, mode }); 12 | 13 | this.createBones(rig); 14 | this.createBoneTexture(); 15 | this.animations = []; 16 | 17 | Object.assign(this.program.uniforms, { 18 | boneTexture: { value: this.boneTexture }, 19 | boneTextureSize: { value: this.boneTextureSize }, 20 | }); 21 | } 22 | 23 | createBones(rig) { 24 | // Create root so that can simply update world matrix of whole skeleton 25 | this.root = new Transform(); 26 | 27 | // Create bones 28 | this.bones = []; 29 | if (!rig.bones || !rig.bones.length) return; 30 | for (let i = 0; i < rig.bones.length; i++) { 31 | const bone = new Transform(); 32 | 33 | // Set initial values (bind pose) 34 | bone.position.fromArray(rig.bindPose.position, i * 3); 35 | bone.quaternion.fromArray(rig.bindPose.quaternion, i * 4); 36 | bone.scale.fromArray(rig.bindPose.scale, i * 3); 37 | 38 | this.bones.push(bone); 39 | } 40 | 41 | // Once created, set the hierarchy 42 | rig.bones.forEach((data, i) => { 43 | this.bones[i].name = data.name; 44 | if (data.parent === -1) return this.bones[i].setParent(this.root); 45 | this.bones[i].setParent(this.bones[data.parent]); 46 | }); 47 | 48 | // Then update to calculate world matrices 49 | this.root.updateMatrixWorld(true); 50 | 51 | // Store inverse of bind pose to calculate differences 52 | this.bones.forEach((bone) => { 53 | bone.bindInverse = new Mat4(...bone.worldMatrix).inverse(); 54 | }); 55 | } 56 | 57 | createBoneTexture() { 58 | if (!this.bones.length) return; 59 | const size = Math.max(4, Math.pow(2, Math.ceil(Math.log(Math.sqrt(this.bones.length * 4)) / Math.LN2))); 60 | this.boneMatrices = new Float32Array(size * size * 4); 61 | this.boneTextureSize = size; 62 | this.boneTexture = new Texture(this.gl, { 63 | image: this.boneMatrices, 64 | generateMipmaps: false, 65 | type: this.gl.FLOAT, 66 | internalFormat: this.gl.renderer.isWebgl2 ? this.gl.RGBA32F : this.gl.RGBA, 67 | minFilter: this.gl.NEAREST, 68 | magFilter: this.gl.NEAREST, 69 | flipY: false, 70 | width: size, 71 | }); 72 | } 73 | 74 | addAnimation(data) { 75 | const animation = new Animation({ objects: this.bones, data }); 76 | this.animations.push(animation); 77 | return animation; 78 | } 79 | 80 | update() { 81 | // Calculate combined animation weight 82 | let total = 0; 83 | this.animations.forEach((animation) => (total += animation.weight)); 84 | 85 | this.animations.forEach((animation, i) => { 86 | // force first animation to set in order to reset frame 87 | animation.update(total, i === 0); 88 | }); 89 | } 90 | 91 | draw({ camera } = {}) { 92 | // Update world matrices manually, as not part of scene graph 93 | this.root.updateMatrixWorld(true); 94 | 95 | // Update bone texture 96 | this.bones.forEach((bone, i) => { 97 | // Find difference between current and bind pose 98 | tempMat4.multiply(bone.worldMatrix, bone.bindInverse); 99 | this.boneMatrices.set(tempMat4, i * 16); 100 | }); 101 | if (this.boneTexture) this.boneTexture.needsUpdate = true; 102 | 103 | super.draw({ camera }); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/extras/Sphere.js: -------------------------------------------------------------------------------- 1 | import { Geometry } from '../core/Geometry.js'; 2 | import { Vec3 } from '../math/Vec3.js'; 3 | 4 | export class Sphere extends Geometry { 5 | constructor( 6 | gl, 7 | { 8 | radius = 0.5, 9 | widthSegments = 16, 10 | heightSegments = Math.ceil(widthSegments * 0.5), 11 | phiStart = 0, 12 | phiLength = Math.PI * 2, 13 | thetaStart = 0, 14 | thetaLength = Math.PI, 15 | attributes = {}, 16 | } = {} 17 | ) { 18 | const wSegs = widthSegments; 19 | const hSegs = heightSegments; 20 | const pStart = phiStart; 21 | const pLength = phiLength; 22 | const tStart = thetaStart; 23 | const tLength = thetaLength; 24 | 25 | const num = (wSegs + 1) * (hSegs + 1); 26 | const numIndices = wSegs * hSegs * 6; 27 | 28 | const position = new Float32Array(num * 3); 29 | const normal = new Float32Array(num * 3); 30 | const uv = new Float32Array(num * 2); 31 | const index = num > 65536 ? new Uint32Array(numIndices) : new Uint16Array(numIndices); 32 | 33 | let i = 0; 34 | let iv = 0; 35 | let ii = 0; 36 | let te = tStart + tLength; 37 | const grid = []; 38 | 39 | let n = new Vec3(); 40 | 41 | for (let iy = 0; iy <= hSegs; iy++) { 42 | let vRow = []; 43 | let v = iy / hSegs; 44 | for (let ix = 0; ix <= wSegs; ix++, i++) { 45 | let u = ix / wSegs; 46 | let x = -radius * Math.cos(pStart + u * pLength) * Math.sin(tStart + v * tLength); 47 | let y = radius * Math.cos(tStart + v * tLength); 48 | let z = radius * Math.sin(pStart + u * pLength) * Math.sin(tStart + v * tLength); 49 | 50 | position[i * 3] = x; 51 | position[i * 3 + 1] = y; 52 | position[i * 3 + 2] = z; 53 | 54 | n.set(x, y, z).normalize(); 55 | normal[i * 3] = n.x; 56 | normal[i * 3 + 1] = n.y; 57 | normal[i * 3 + 2] = n.z; 58 | 59 | uv[i * 2] = u; 60 | uv[i * 2 + 1] = 1 - v; 61 | 62 | vRow.push(iv++); 63 | } 64 | 65 | grid.push(vRow); 66 | } 67 | 68 | for (let iy = 0; iy < hSegs; iy++) { 69 | for (let ix = 0; ix < wSegs; ix++) { 70 | let a = grid[iy][ix + 1]; 71 | let b = grid[iy][ix]; 72 | let c = grid[iy + 1][ix]; 73 | let d = grid[iy + 1][ix + 1]; 74 | 75 | if (iy !== 0 || tStart > 0) { 76 | index[ii * 3] = a; 77 | index[ii * 3 + 1] = b; 78 | index[ii * 3 + 2] = d; 79 | ii++; 80 | } 81 | if (iy !== hSegs - 1 || te < Math.PI) { 82 | index[ii * 3] = b; 83 | index[ii * 3 + 1] = c; 84 | index[ii * 3 + 2] = d; 85 | ii++; 86 | } 87 | } 88 | } 89 | 90 | Object.assign(attributes, { 91 | position: { size: 3, data: position }, 92 | normal: { size: 3, data: normal }, 93 | uv: { size: 2, data: uv }, 94 | index: { data: index }, 95 | }); 96 | 97 | super(gl, attributes); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/extras/Texture3D.js: -------------------------------------------------------------------------------- 1 | import { Texture } from '../core/Texture.js'; 2 | 3 | export class Texture3D extends Texture { 4 | constructor(gl, args) { 5 | super(gl, { 6 | ...args, 7 | target: gl.TEXTURE_3D, 8 | width: args.width ? args.width : 2, 9 | height: args.height ? args.height : 2, 10 | }); 11 | 12 | const image = new Image(); 13 | image.crossOrigin = '*'; 14 | image.src = args.src; 15 | 16 | image.onload = () => { 17 | let canvas = document.createElement('canvas'); 18 | canvas.width = image.width; 19 | canvas.height = image.height; 20 | 21 | let ctx = canvas.getContext('2d'); 22 | ctx.scale(1, -1); 23 | ctx.translate(0, -image.height); 24 | ctx.drawImage(image, 0, 0); 25 | const imageData = ctx.getImageData(0, 0, image.width, image.height).data; 26 | 27 | canvas = null; 28 | ctx = null; 29 | let elementCount; 30 | 31 | switch (this.format) { 32 | case gl.RED: 33 | elementCount = 1; 34 | break; 35 | case gl.RG: 36 | elementCount = 2; 37 | break; 38 | case gl.RGB: 39 | elementCount = 3; 40 | break; 41 | default: 42 | elementCount = 4; 43 | break; 44 | } 45 | 46 | const dataCount = this.width * this.height * this.length * elementCount; 47 | const data = this.type === gl.UNSIGNED_BYTE ? new Uint8Array(dataCount) : new Float32Array(dataCount); 48 | 49 | let dataIterator = 0; 50 | 51 | for (let z = 0; z < this.length; z++) { 52 | for (let y = 0; y < this.height; y++) { 53 | for (let x = 0; x < this.width; x++) { 54 | let zOffsetX = (z % args.tileCountX) * this.width; 55 | let zOffsetY = Math.floor(z / args.tileCountX) * (this.width * this.height * args.tileCountX); 56 | let index = x + zOffsetX + (y * image.width + zOffsetY); 57 | 58 | const r = imageData[index * 4]; 59 | const g = imageData[index * 4 + 1]; 60 | const b = imageData[index * 4 + 2]; 61 | const a = imageData[index * 4 + 3]; 62 | 63 | let texel = [r, g, b, a]; 64 | 65 | for (let i = 0; i < elementCount; i++) { 66 | if (this.type === this.gl.UNSIGNED_BYTE) { 67 | data[dataIterator++] = texel[i]; 68 | } else { 69 | data[dataIterator++] = texel[i] / 255; 70 | } 71 | } 72 | } 73 | } 74 | } 75 | 76 | this.image = data; 77 | this.needsUpdate = true; 78 | }; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/extras/Torus.js: -------------------------------------------------------------------------------- 1 | // https://github.com/mrdoob/three.js/blob/master/src/geometries/TorusGeometry.js 2 | 3 | import { Geometry } from '../core/Geometry.js'; 4 | import { Vec3 } from '../math/Vec3.js'; 5 | 6 | export class Torus extends Geometry { 7 | constructor(gl, { radius = 0.5, tube = 0.2, radialSegments = 8, tubularSegments = 6, arc = Math.PI * 2, attributes = {} } = {}) { 8 | const num = (radialSegments + 1) * (tubularSegments + 1); 9 | const numIndices = radialSegments * tubularSegments * 6; 10 | 11 | const vertices = new Float32Array(num * 3); 12 | const normals = new Float32Array(num * 3); 13 | const uvs = new Float32Array(num * 2); 14 | const indices = num > 65536 ? new Uint32Array(numIndices) : new Uint16Array(numIndices); 15 | 16 | const center = new Vec3(); 17 | const vertex = new Vec3(); 18 | const normal = new Vec3(); 19 | 20 | // generate vertices, normals and uvs 21 | let idx = 0; 22 | for (let j = 0; j <= radialSegments; j++) { 23 | for (let i = 0; i <= tubularSegments; i++, idx++) { 24 | const u = (i / tubularSegments) * arc; 25 | const v = (j / radialSegments) * Math.PI * 2; 26 | 27 | // vertex 28 | vertex.x = (radius + tube * Math.cos(v)) * Math.cos(u); 29 | vertex.y = (radius + tube * Math.cos(v)) * Math.sin(u); 30 | vertex.z = tube * Math.sin(v); 31 | 32 | vertices.set([vertex.x, vertex.y, vertex.z], idx * 3); 33 | 34 | // normal 35 | center.x = radius * Math.cos(u); 36 | center.y = radius * Math.sin(u); 37 | normal.sub(vertex, center).normalize(); 38 | 39 | normals.set([normal.x, normal.y, normal.z], idx * 3); 40 | 41 | // uv 42 | uvs.set([i / tubularSegments, j / radialSegments], idx * 2); 43 | } 44 | } 45 | 46 | // generate indices 47 | idx = 0; 48 | for (let j = 1; j <= radialSegments; j++) { 49 | for (let i = 1; i <= tubularSegments; i++, idx++) { 50 | // indices 51 | const a = (tubularSegments + 1) * j + i - 1; 52 | const b = (tubularSegments + 1) * (j - 1) + i - 1; 53 | const c = (tubularSegments + 1) * (j - 1) + i; 54 | const d = (tubularSegments + 1) * j + i; 55 | 56 | // faces 57 | indices.set([a, b, d, b, c, d], idx * 6); 58 | } 59 | } 60 | 61 | Object.assign(attributes, { 62 | position: { size: 3, data: vertices }, 63 | normal: { size: 3, data: normals }, 64 | uv: { size: 2, data: uvs }, 65 | index: { data: indices }, 66 | }); 67 | 68 | super(gl, attributes); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/extras/Triangle.js: -------------------------------------------------------------------------------- 1 | import { Geometry } from '../core/Geometry.js'; 2 | 3 | export class Triangle extends Geometry { 4 | constructor(gl, { attributes = {} } = {}) { 5 | Object.assign(attributes, { 6 | position: { size: 2, data: new Float32Array([-1, -1, 3, -1, -1, 3]) }, 7 | uv: { size: 2, data: new Float32Array([0, 0, 2, 0, 0, 2]) }, 8 | }); 9 | 10 | super(gl, attributes); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/extras/Tube.js: -------------------------------------------------------------------------------- 1 | import { Geometry } from '../core/Geometry.js'; 2 | import { Vec3 } from '../math/Vec3.js'; 3 | import { Vec2 } from '../math/Vec2.js'; 4 | 5 | // helper variables 6 | const vertex = /* @__PURE__ */ new Vec3(); 7 | const normal = /* @__PURE__ */ new Vec3(); 8 | const uv = /* @__PURE__ */ new Vec2(); 9 | const point = /* @__PURE__ */ new Vec3(); 10 | 11 | export class Tube extends Geometry { 12 | constructor(gl, { path, radius = 1, tubularSegments = 64, radialSegments = 8, closed = false, attributes = {} } = {}) { 13 | super(gl, attributes); 14 | 15 | this.path = path; 16 | this.radius = radius; 17 | this.tubularSegments = tubularSegments; 18 | this.radialSegments = radialSegments; 19 | this.closed = closed; 20 | 21 | this.frenetFrames = path.computeFrenetFrames(tubularSegments, closed); 22 | 23 | const numVertices = (tubularSegments + 1) * (radialSegments + 1); 24 | const numIndices = tubularSegments * radialSegments * 6; 25 | this.positions = new Float32Array(numVertices * 3); 26 | this.normals = new Float32Array(numVertices * 3); 27 | this.uvs = new Float32Array(numVertices * 2); 28 | this.indices = numVertices > 65536 ? new Uint32Array(numIndices) : new Uint16Array(numIndices); 29 | 30 | // create buffer data 31 | this._generateAttributes(); 32 | this._generateIndices(); 33 | 34 | this.addAttribute('position', { size: 3, data: this.positions }); 35 | this.addAttribute('normal', { size: 3, data: this.normals }); 36 | this.addAttribute('uv', { size: 2, data: this.uvs }); 37 | this.setIndex({ data: this.indices }); 38 | } 39 | 40 | _generateAttributes() { 41 | for (let i = 0; i <= this.tubularSegments; i++) { 42 | let ci = i; 43 | if (i === this.tubularSegments) { 44 | // if the geometry is not closed, generate the last row of vertices and normals 45 | // at the regular position on the given path 46 | // if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ) 47 | ci = this.closed ? 0 : this.tubularSegments; 48 | } 49 | 50 | this.path.getPointAt(ci / this.tubularSegments, point); 51 | // retrieve corresponding normal and binormal 52 | const N = this.frenetFrames.normals[ci]; 53 | const B = this.frenetFrames.binormals[ci]; 54 | 55 | // generate normals and vertices for the current segment 56 | for (let j = 0; j <= this.radialSegments; j++) { 57 | const v = (j / this.radialSegments) * Math.PI * 2; 58 | const sin = Math.sin(v); 59 | const cos = -Math.cos(v); 60 | 61 | const idx = i * (this.radialSegments + 1) + j; 62 | 63 | // normal 64 | normal.x = cos * N.x + sin * B.x; 65 | normal.y = cos * N.y + sin * B.y; 66 | normal.z = cos * N.z + sin * B.z; 67 | // normal.normalize(); // ??? 68 | this.normals.set(normal, idx * 3); 69 | 70 | // vertex 71 | vertex.x = point.x + this.radius * normal.x; 72 | vertex.y = point.y + this.radius * normal.y; 73 | vertex.z = point.z + this.radius * normal.z; 74 | this.positions.set(vertex, idx * 3); 75 | 76 | // uv 77 | uv.x = i / this.tubularSegments; 78 | uv.y = j / this.radialSegments; 79 | this.uvs.set(uv, idx * 2); 80 | } 81 | } 82 | } 83 | 84 | _generateIndices() { 85 | for (let j = 1; j <= this.tubularSegments; j++) { 86 | for (let i = 1; i <= this.radialSegments; i++) { 87 | const a = (this.radialSegments + 1) * (j - 1) + (i - 1); 88 | const b = (this.radialSegments + 1) * j + (i - 1); 89 | const c = (this.radialSegments + 1) * j + i; 90 | const d = (this.radialSegments + 1) * (j - 1) + i; 91 | 92 | const idx = (j - 1) * this.radialSegments + (i - 1); 93 | this.indices.set([a, b, d, b, c, d], idx * 6); 94 | } 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/extras/WireMesh.js: -------------------------------------------------------------------------------- 1 | import { Mesh } from '../core/Mesh.js'; 2 | import { Program } from '../core/Program.js'; 3 | import { Geometry } from '../core/Geometry.js'; 4 | import { Color } from '../math/Color.js'; 5 | 6 | export class WireMesh extends Mesh { 7 | constructor(gl, { geometry, wireColor = new Color(0, 0.75, 0.5), ...meshProps } = {}) { 8 | const wireProgram = new Program(gl, { 9 | vertex, 10 | fragment, 11 | uniforms: { wireColor: { value: wireColor } }, 12 | }); 13 | 14 | const positionArray = geometry.attributes.position.data; 15 | const indices = []; 16 | const hashSet = new Set(); 17 | 18 | function addUniqueIndices(idx) { 19 | for (let i = 0; i < idx.length; i += 2) { 20 | if (isUniqueEdgePosition(idx[i] * 3, idx[i + 1] * 3, positionArray, hashSet)) { 21 | indices.push(idx[i], idx[i + 1]); 22 | } 23 | } 24 | } 25 | 26 | if (geometry.attributes.index) { 27 | const idata = geometry.attributes.index.data; 28 | 29 | for (let i = 0; i < idata.length; i += 3) { 30 | // For every triangle, make three line pairs (start, end) 31 | // prettier-ignore 32 | addUniqueIndices([ 33 | idata[i], idata[i + 1], 34 | idata[i + 1], idata[i + 2], 35 | idata[i + 2], idata[i] 36 | ]); 37 | } 38 | } else { 39 | const numVertices = Math.floor(positionArray.length / 3); 40 | 41 | for (let i = 0; i < numVertices; i += 3) { 42 | addUniqueIndices([i, i + 1, i + 1, i + 2, i + 2, i]); 43 | } 44 | } 45 | 46 | const indicesTyped = indices.length > 65536 ? new Uint32Array(indices) : new Uint16Array(indices); 47 | const wireGeometry = new Geometry(gl, { 48 | position: { ...geometry.attributes.position }, 49 | index: { data: indicesTyped }, 50 | }); 51 | 52 | super(gl, { ...meshProps, mode: gl.LINES, geometry: wireGeometry, program: wireProgram }); 53 | } 54 | } 55 | 56 | // from https://github.com/mrdoob/three.js/blob/0c26bb4bb8220126447c8373154ac045588441de/src/geometries/WireframeGeometry.js#L116 57 | function isUniqueEdgePosition(start, end, pos, hashSet) { 58 | // prettier-ignore 59 | const hash1 = [ 60 | pos[start], pos[start + 1], pos[start + 2], 61 | pos[end], pos[end + 1], pos[end + 2] 62 | ].join('#'); 63 | 64 | // coincident edge 65 | // prettier-ignore 66 | const hash2 = [ 67 | pos[end], pos[end + 1], pos[end + 2], 68 | pos[start], pos[start + 1], pos[start + 2] 69 | ].join('#'); 70 | 71 | const oldSize = hashSet.size; 72 | hashSet.add(hash1); 73 | hashSet.add(hash2); 74 | return hashSet.size - oldSize === 2; 75 | } 76 | 77 | const vertex = /* glsl */ ` 78 | attribute vec3 position; 79 | uniform mat4 modelViewMatrix; 80 | uniform mat4 projectionMatrix; 81 | 82 | void main() { 83 | gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 84 | } 85 | `; 86 | 87 | const fragment = /* glsl */ ` 88 | precision highp float; 89 | uniform vec3 wireColor; 90 | 91 | void main() { 92 | gl_FragColor = vec4(wireColor, 1.0); 93 | } 94 | `; 95 | -------------------------------------------------------------------------------- /src/extras/helpers/AxesHelper.js: -------------------------------------------------------------------------------- 1 | import { Mesh } from '../../core/Mesh.js'; 2 | import { Program } from '../../core/Program.js'; 3 | import { Geometry } from '../../core/Geometry.js'; 4 | import { Vec3 } from '../../math/Vec3.js'; 5 | 6 | export class AxesHelper extends Mesh { 7 | constructor( 8 | gl, 9 | { 10 | size = 1, 11 | symmetric = false, 12 | xColor = new Vec3(0.96, 0.21, 0.32), 13 | yColor = new Vec3(0.44, 0.64, 0.11), 14 | zColor = new Vec3(0.18, 0.52, 0.89), 15 | ...meshProps 16 | } = {} 17 | ) { 18 | const a = symmetric ? -size : 0; 19 | const b = size; 20 | 21 | // prettier-ignore 22 | const vertices = new Float32Array([ 23 | a, 0, 0, b, 0, 0, 24 | 0, a, 0, 0, b, 0, 25 | 0, 0, a, 0, 0, b 26 | ]); 27 | 28 | // prettier-ignore 29 | const colors = new Float32Array([ 30 | ...xColor, ...xColor, 31 | ...yColor, ...yColor, 32 | ...zColor, ...zColor 33 | ]); 34 | 35 | const geometry = new Geometry(gl, { 36 | position: { size: 3, data: vertices }, 37 | color: { size: 3, data: colors }, 38 | }); 39 | 40 | const program = new Program(gl, { vertex, fragment }); 41 | 42 | super(gl, { ...meshProps, mode: gl.LINES, geometry, program }); 43 | } 44 | } 45 | 46 | const vertex = /* glsl */ ` 47 | attribute vec3 position; 48 | attribute vec3 color; 49 | uniform mat4 modelViewMatrix; 50 | uniform mat4 projectionMatrix; 51 | 52 | varying vec3 vColor; 53 | 54 | void main() { 55 | vColor = color; 56 | gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 57 | } 58 | `; 59 | 60 | const fragment = /* glsl */ ` 61 | precision highp float; 62 | varying vec3 vColor; 63 | 64 | void main() { 65 | gl_FragColor = vec4(vColor, 1.0); 66 | } 67 | `; 68 | -------------------------------------------------------------------------------- /src/extras/helpers/FaceNormalsHelper.js: -------------------------------------------------------------------------------- 1 | import { Mesh } from '../../core/Mesh.js'; 2 | import { Program } from '../../core/Program.js'; 3 | import { Geometry } from '../../core/Geometry.js'; 4 | import { Vec3 } from '../../math/Vec3.js'; 5 | import { Mat3 } from '../../math/Mat3.js'; 6 | 7 | const vA = /* @__PURE__ */ new Vec3(); 8 | const vB = /* @__PURE__ */ new Vec3(); 9 | const vC = /* @__PURE__ */ new Vec3(); 10 | const vCenter = /* @__PURE__ */ new Vec3(); 11 | const vNormal = /* @__PURE__ */ new Vec3(); 12 | 13 | export class FaceNormalsHelper extends Mesh { 14 | constructor(object, { size = 0.1, color = new Vec3(0.15, 0.86, 0.86), ...meshProps } = {}) { 15 | const gl = object.gl; 16 | 17 | const positionData = object.geometry.attributes.position.data; 18 | const sizeData = new Float32Array([0, size]); 19 | 20 | const indexAttr = object.geometry.attributes.index; 21 | const getIndex = indexAttr ? (i) => indexAttr.data[i] : (i) => i; 22 | const numVertices = indexAttr ? indexAttr.data.length : Math.floor(positionData.length / 3); 23 | 24 | const nNormals = Math.floor(numVertices / 3); 25 | const positionsArray = new Float32Array(nNormals * 2 * 3); 26 | const normalsArray = new Float32Array(nNormals * 2 * 3); 27 | const sizeArray = new Float32Array(nNormals * 2); 28 | 29 | for (let i = 0; i < numVertices; i += 3) { 30 | vA.fromArray(positionData, getIndex(i + 0) * 3); 31 | vB.fromArray(positionData, getIndex(i + 1) * 3); 32 | vC.fromArray(positionData, getIndex(i + 2) * 3); 33 | 34 | vCenter 35 | .add(vA, vB) 36 | .add(vC) 37 | .multiply(1 / 3); 38 | 39 | vA.sub(vA, vB); 40 | vC.sub(vC, vB); 41 | vNormal.cross(vC, vA).normalize(); 42 | 43 | // duplicate position and normal for line start and end point 44 | const i2 = i * 2; 45 | positionsArray.set(vCenter, i2); 46 | positionsArray.set(vCenter, i2 + 3); 47 | 48 | normalsArray.set(vNormal, i2); 49 | normalsArray.set(vNormal, i2 + 3); 50 | sizeArray.set(sizeData, (i / 3) * 2); 51 | } 52 | 53 | const geometry = new Geometry(gl, { 54 | position: { size: 3, data: positionsArray }, 55 | normal: { size: 3, data: normalsArray }, 56 | size: { size: 1, data: sizeArray }, 57 | }); 58 | 59 | const program = new Program(gl, { 60 | vertex, 61 | fragment, 62 | uniforms: { 63 | color: { value: color }, 64 | worldNormalMatrix: { value: new Mat3() }, 65 | objectWorldMatrix: { value: object.worldMatrix }, 66 | }, 67 | }); 68 | 69 | super(gl, { ...meshProps, mode: gl.LINES, geometry, program }); 70 | 71 | this.object = object; 72 | } 73 | 74 | draw(arg) { 75 | this.program.uniforms.worldNormalMatrix.value.getNormalMatrix(this.object.worldMatrix); 76 | super.draw(arg); 77 | } 78 | } 79 | 80 | const vertex = /* glsl */ ` 81 | attribute vec3 position; 82 | attribute vec3 normal; 83 | attribute float size; 84 | 85 | uniform mat4 viewMatrix; 86 | uniform mat4 projectionMatrix; 87 | uniform mat4 objectWorldMatrix; 88 | uniform mat3 worldNormalMatrix; 89 | 90 | void main() { 91 | vec3 n = normalize(worldNormalMatrix * normal) * size; 92 | vec3 p = (objectWorldMatrix * vec4(position, 1.0)).xyz; 93 | gl_Position = projectionMatrix * viewMatrix * vec4(p + n, 1.0); 94 | } 95 | `; 96 | 97 | const fragment = /* glsl */ ` 98 | precision highp float; 99 | uniform vec3 color; 100 | 101 | void main() { 102 | gl_FragColor = vec4(color, 1.0); 103 | } 104 | `; 105 | -------------------------------------------------------------------------------- /src/extras/helpers/GridHelper.js: -------------------------------------------------------------------------------- 1 | import { Mesh } from '../../core/Mesh.js'; 2 | import { Program } from '../../core/Program.js'; 3 | import { Geometry } from '../../core/Geometry.js'; 4 | import { Vec3 } from '../../math/Vec3.js'; 5 | 6 | export class GridHelper extends Mesh { 7 | constructor(gl, { size = 10, divisions = 10, color = new Vec3(0.75, 0.75, 0.75), ...meshProps } = {}) { 8 | const numVertices = (size + 1) * 2 * 2; 9 | const vertices = new Float32Array(numVertices * 3); 10 | 11 | const hs = size / 2; 12 | for (let i = 0; i <= divisions; i++) { 13 | const t = i / divisions; 14 | const o = t * size - hs; 15 | 16 | vertices.set([o, 0, -hs, o, 0, hs], i * 12); 17 | vertices.set([-hs, 0, o, hs, 0, o], i * 12 + 6); 18 | } 19 | 20 | const geometry = new Geometry(gl, { 21 | position: { size: 3, data: vertices }, 22 | }); 23 | 24 | const program = new Program(gl, { 25 | vertex, 26 | fragment, 27 | uniforms: { 28 | color: { value: color }, 29 | }, 30 | }); 31 | super(gl, { ...meshProps, mode: gl.LINES, geometry, program }); 32 | } 33 | } 34 | 35 | const vertex = /* glsl */ ` 36 | attribute vec3 position; 37 | uniform mat4 modelViewMatrix; 38 | uniform mat4 projectionMatrix; 39 | 40 | void main() { 41 | gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 42 | } 43 | `; 44 | 45 | const fragment = /* glsl */ ` 46 | precision highp float; 47 | uniform vec3 color; 48 | 49 | void main() { 50 | gl_FragColor = vec4(color, 1.0); 51 | } 52 | `; 53 | -------------------------------------------------------------------------------- /src/extras/helpers/VertexNormalsHelper.js: -------------------------------------------------------------------------------- 1 | import { Mesh } from '../../core/Mesh.js'; 2 | import { Program } from '../../core/Program.js'; 3 | import { Geometry } from '../../core/Geometry.js'; 4 | import { Vec3 } from '../../math/Vec3.js'; 5 | import { Mat3 } from '../../math/Mat3.js'; 6 | 7 | export class VertexNormalsHelper extends Mesh { 8 | constructor(object, { size = 0.1, color = new Vec3(0.86, 0.16, 0.86), ...meshProps } = {}) { 9 | const gl = object.gl; 10 | const nNormals = object.geometry.attributes.normal.count; 11 | const positionsArray = new Float32Array(nNormals * 2 * 3); 12 | const normalsArray = new Float32Array(nNormals * 2 * 3); 13 | const sizeArray = new Float32Array(nNormals * 2); 14 | 15 | const normalData = object.geometry.attributes.normal.data; 16 | const positionData = object.geometry.attributes.position.data; 17 | const sizeData = new Float32Array([0, size]); 18 | 19 | for (let i = 0; i < nNormals; i++) { 20 | const i6 = i * 6; 21 | const i3 = i * 3; 22 | 23 | // duplicate position and normal for line start and end point 24 | const pSub = positionData.subarray(i3, i3 + 3); 25 | positionsArray.set(pSub, i6); 26 | positionsArray.set(pSub, i6 + 3); 27 | 28 | const nSub = normalData.subarray(i3, i3 + 3); 29 | normalsArray.set(nSub, i6); 30 | normalsArray.set(nSub, i6 + 3); 31 | 32 | sizeArray.set(sizeData, i * 2); 33 | } 34 | 35 | const geometry = new Geometry(gl, { 36 | position: { size: 3, data: positionsArray }, 37 | normal: { size: 3, data: normalsArray }, 38 | size: { size: 1, data: sizeArray }, 39 | }); 40 | 41 | const program = new Program(gl, { 42 | vertex, 43 | fragment, 44 | uniforms: { 45 | color: { value: color }, 46 | worldNormalMatrix: { value: new Mat3() }, 47 | objectWorldMatrix: { value: object.worldMatrix }, 48 | }, 49 | }); 50 | 51 | super(gl, { ...meshProps, mode: gl.LINES, geometry, program }); 52 | 53 | this.object = object; 54 | } 55 | 56 | draw(arg) { 57 | this.program.uniforms.worldNormalMatrix.value.getNormalMatrix(this.object.worldMatrix); 58 | super.draw(arg); 59 | } 60 | } 61 | 62 | const vertex = /* glsl */ ` 63 | attribute vec3 position; 64 | attribute vec3 normal; 65 | attribute float size; 66 | 67 | uniform mat4 viewMatrix; 68 | uniform mat4 projectionMatrix; 69 | uniform mat4 objectWorldMatrix; 70 | uniform mat3 worldNormalMatrix; 71 | 72 | void main() { 73 | vec3 n = normalize(worldNormalMatrix * normal) * size; 74 | vec3 p = (objectWorldMatrix * vec4(position, 1.0)).xyz; 75 | gl_Position = projectionMatrix * viewMatrix * vec4(p + n, 1.0); 76 | } 77 | `; 78 | 79 | const fragment = /* glsl */ ` 80 | precision highp float; 81 | uniform vec3 color; 82 | 83 | void main() { 84 | gl_FragColor = vec4(color, 1.0); 85 | } 86 | `; 87 | -------------------------------------------------------------------------------- /src/extras/path/BaseSegment.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Abstract base class for path segments. 3 | * This class contains common methods for all segments types. 4 | */ 5 | export default class BaseSegment { 6 | constructor() { 7 | this._len = -1; 8 | this.tiltStart = 0; 9 | this.tiltEnd = 0; 10 | } 11 | 12 | /** 13 | * Get segment length. 14 | * @returns {number} segment length 15 | */ 16 | getLength() { 17 | if (this._len < 0) { 18 | this.updateLength(); 19 | } 20 | 21 | return this._len; 22 | } 23 | 24 | /** 25 | * Get tilt angle at t 26 | * @param {number} t Distance at time t in range [0 .. 1] 27 | * @returns {number} Tilt angle at t 28 | */ 29 | getTiltAt(t) { 30 | return this.tiltStart * (1 - t) * this.tiltEnd * t; 31 | } 32 | 33 | /** 34 | * Creates a clone of this instance 35 | * @returns {BaseSegment} cloned instance 36 | */ 37 | clone() { 38 | return new this.constructor().copy(this); 39 | } 40 | 41 | /** 42 | * Copies another segment object to this instance. 43 | * @param {BaseSegment} source reference object 44 | * @returns {BaseSegment} copy of source object 45 | */ 46 | copy(source) { 47 | this._len = source._len; 48 | this.tiltStart = source.tiltStart; 49 | this.tiltEnd = source.tiltEnd; 50 | return this; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/extras/path/CubicBezierSegment.js: -------------------------------------------------------------------------------- 1 | import BaseSegment from './BaseSegment.js'; 2 | import { Vec3 } from '../../math/Vec3.js'; 3 | import { T_VALUES, C_VALUES } from './utils.js'; 4 | 5 | const tempVec3 = /* @__PURE__ */ new Vec3(); 6 | 7 | function cubicBezier(t, p0, p1, p2, p3) { 8 | const k = 1 - t; 9 | // prettier-ignore 10 | return ( 11 | (k * k * k * p0) + 12 | (3 * k * k * t * p1) + 13 | (3 * k * t * t * p2) + 14 | (t * t * t * p3) 15 | ); 16 | } 17 | 18 | function cubicBezierDeriv(t, p0, p1, p2, p3) { 19 | const k = 1 - t; 20 | // prettier-ignore 21 | return ( 22 | (3 * k * k * (p1 - p0)) + 23 | (6 * k * t * (p2 - p1)) + 24 | (3 * t * t * (p3 - p2)) 25 | ); 26 | } 27 | 28 | export default class CubicBezierSegment extends BaseSegment { 29 | constructor(p0, p1, p2, p3, tiltStart = 0, tiltEnd = 0) { 30 | super(); 31 | this.p0 = p0; 32 | this.p1 = p1; 33 | this.p2 = p2; 34 | this.p3 = p3; 35 | 36 | this.tiltStart = tiltStart; 37 | this.tiltEnd = tiltEnd; 38 | 39 | this._len = -1; 40 | } 41 | 42 | /** 43 | * Updates the segment length. You must call this method every time you change the curve's control points. 44 | */ 45 | updateLength() { 46 | // from https://github.com/Pomax/bezierjs/blob/d19695f3cc3ce383cf38ce4643f467deca7edb92/src/utils.js#L265 47 | const z = 0.5; 48 | const len = T_VALUES.length; 49 | 50 | let sum = 0; 51 | for (let i = 0, t; i < len; i++) { 52 | t = z * T_VALUES[i] + z; 53 | sum += C_VALUES[i] * this.getDerivativeAt(t, tempVec3).len(); 54 | } 55 | 56 | this._len = z * sum; 57 | } 58 | 59 | /** 60 | * Get point at relative position in curve according to segment length. 61 | * @param {number} t Distance at time t in range [0 .. 1] 62 | * @param {Vec3} out Optional Vec3 to output 63 | * @returns {Vec3} Point at relative position 64 | */ 65 | getPointAt(t, out = new Vec3()) { 66 | out.x = cubicBezier(t, this.p0.x, this.p1.x, this.p2.x, this.p3.x); 67 | out.y = cubicBezier(t, this.p0.y, this.p1.y, this.p2.y, this.p3.y); 68 | out.z = cubicBezier(t, this.p0.z, this.p1.z, this.p2.z, this.p3.z); 69 | return out; 70 | } 71 | 72 | getDerivativeAt(t, out = new Vec3()) { 73 | out.x = cubicBezierDeriv(t, this.p0.x, this.p1.x, this.p2.x, this.p3.x); 74 | out.y = cubicBezierDeriv(t, this.p0.y, this.p1.y, this.p2.y, this.p3.y); 75 | out.z = cubicBezierDeriv(t, this.p0.z, this.p1.z, this.p2.z, this.p3.z); 76 | return out; 77 | } 78 | 79 | /** 80 | * Returns a unit vector tangent at t 81 | * @param {number} t Distance at time t in range [0 .. 1] 82 | * @param {Vec3} out Optional Vec3 to output 83 | * @returns {Vec3} A unit vector 84 | */ 85 | getTangentAt(t, out = new Vec3()) { 86 | return this.getDerivativeAt(t, out).normalize(); 87 | } 88 | 89 | lastPoint() { 90 | return this.p3; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/extras/path/LineSegment.js: -------------------------------------------------------------------------------- 1 | import BaseSegment from './BaseSegment.js'; 2 | import { Vec3 } from '../../math/Vec3.js'; 3 | import { lerp as lerp3 } from '../../math/functions/Vec3Func.js'; 4 | 5 | const tempVec3 = /* @__PURE__ */ new Vec3(); 6 | 7 | export default class LineSegment extends BaseSegment { 8 | constructor(p0, p1, tiltStart = 0, tiltEnd = 0) { 9 | super(); 10 | this.p0 = p0; 11 | this.p1 = p1; 12 | 13 | this.tiltStart = tiltStart; 14 | this.tiltEnd = tiltEnd; 15 | 16 | this._len = -1; 17 | } 18 | 19 | /** 20 | * Updates the segment length. You must call this method every time you change the curve's control points. 21 | */ 22 | updateLength() { 23 | this._len = tempVec3.sub(this.p1, this.p0).len(); 24 | } 25 | 26 | /** 27 | * Get point at relative position in curve according to segment length. 28 | * @param {number} t Distance at time t in range [0 .. 1] 29 | * @param {Vec3} out Optional Vec3 to output 30 | * @returns {Vec3} Point at relative position 31 | */ 32 | getPointAt(t, out = new Vec3()) { 33 | lerp3(out, this.p0, this.p1, t); 34 | return out; 35 | } 36 | 37 | /** 38 | * Returns a unit vector tangent at t 39 | * @param {number} t Distance at time t in range [0 .. 1] 40 | * @param {Vec3} out Optional Vec3 to output 41 | * @returns {Vec3} A unit vector 42 | */ 43 | getTangentAt(t, out = new Vec3()) { 44 | return out.sub(this.p1, this.p0).normalize(); 45 | } 46 | 47 | lastPoint() { 48 | return this.p1; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/extras/path/QuadraticBezierSegment.js: -------------------------------------------------------------------------------- 1 | import BaseSegment from './BaseSegment.js'; 2 | import { Vec3 } from '../../math/Vec3.js'; 3 | import { T_VALUES, C_VALUES } from './utils.js'; 4 | 5 | const tempVec3 = /* @__PURE__ */ new Vec3(); 6 | 7 | function quadraticBezier(t, p0, p1, p2) { 8 | const k = 1 - t; 9 | return k * k * p0 + 2 * k * t * p1 + t * t * p2; 10 | } 11 | 12 | function quadraticBezierDeriv(t, p0, p1, p2) { 13 | const k = 1 - t; 14 | return 2 * k * (p1 - p0) + 2 * t * (p2 - p1); 15 | } 16 | 17 | export default class QuadraticBezierSegment extends BaseSegment { 18 | constructor(p0, p1, p2, tiltStart = 0, tiltEnd = 0) { 19 | super(); 20 | this.p0 = p0; 21 | this.p1 = p1; 22 | this.p2 = p2; 23 | 24 | this.tiltStart = tiltStart; 25 | this.tiltEnd = tiltEnd; 26 | 27 | this._len = -1; 28 | } 29 | 30 | /** 31 | * Updates the segment length. You must call this method every time you change the curve's control points. 32 | */ 33 | updateLength() { 34 | // from https://github.com/Pomax/bezierjs/blob/d19695f3cc3ce383cf38ce4643f467deca7edb92/src/utils.js#L265 35 | const z = 0.5; 36 | const len = T_VALUES.length; 37 | 38 | let sum = 0; 39 | for (let i = 0, t; i < len; i++) { 40 | t = z * T_VALUES[i] + z; 41 | sum += C_VALUES[i] * this.getDerivativeAt(t, tempVec3).len(); 42 | } 43 | 44 | this._len = z * sum; 45 | } 46 | 47 | /** 48 | * Get point at relative position in curve according to segment length. 49 | * @param {number} t Distance at time t in range [0 .. 1] 50 | * @param {Vec3} out Optional Vec3 to output 51 | * @returns {Vec3} Point at relative position 52 | */ 53 | getPointAt(t, out = new Vec3()) { 54 | out.x = quadraticBezier(t, this.p0.x, this.p1.x, this.p2.x); 55 | out.y = quadraticBezier(t, this.p0.y, this.p1.y, this.p2.y); 56 | out.z = quadraticBezier(t, this.p0.z, this.p1.z, this.p2.z); 57 | return out; 58 | } 59 | 60 | getDerivativeAt(t, out = new Vec3()) { 61 | out.x = quadraticBezierDeriv(t, this.p0.x, this.p1.x, this.p2.x); 62 | out.y = quadraticBezierDeriv(t, this.p0.y, this.p1.y, this.p2.y); 63 | out.z = quadraticBezierDeriv(t, this.p0.z, this.p1.z, this.p2.z); 64 | return out; 65 | } 66 | 67 | /** 68 | * Returns a unit vector tangent at t 69 | * @param {number} t Distance at time t in range [0 .. 1] 70 | * @param {Vec3} out Optional Vec3 to output 71 | * @returns {Vec3} A unit vector 72 | */ 73 | getTangentAt(t, out = new Vec3()) { 74 | return this.getDerivativeAt(t, out).normalize(); 75 | } 76 | 77 | lastPoint() { 78 | return this.p2; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | // Core 2 | export { Geometry } from './core/Geometry.js'; 3 | export { Program } from './core/Program.js'; 4 | export { Renderer } from './core/Renderer.js'; 5 | export { Camera } from './core/Camera.js'; 6 | export { Transform } from './core/Transform.js'; 7 | export { Mesh } from './core/Mesh.js'; 8 | export { Texture } from './core/Texture.js'; 9 | export { RenderTarget } from './core/RenderTarget.js'; 10 | 11 | // Maths 12 | export { Color } from './math/Color.js'; 13 | export { Euler } from './math/Euler.js'; 14 | export { Mat3 } from './math/Mat3.js'; 15 | export { Mat4 } from './math/Mat4.js'; 16 | export { Quat } from './math/Quat.js'; 17 | export { Vec2 } from './math/Vec2.js'; 18 | export { Vec3 } from './math/Vec3.js'; 19 | export { Vec4 } from './math/Vec4.js'; 20 | 21 | // Extras 22 | export { Plane } from './extras/Plane.js'; 23 | export { Box } from './extras/Box.js'; 24 | export { Sphere } from './extras/Sphere.js'; 25 | export { Cylinder } from './extras/Cylinder.js'; 26 | export { Triangle } from './extras/Triangle.js'; 27 | export { Torus } from './extras/Torus.js'; 28 | export { Orbit } from './extras/Orbit.js'; 29 | export { Raycast } from './extras/Raycast.js'; 30 | export { Curve } from './extras/Curve.js'; 31 | export { Path } from './extras/path/Path.js'; 32 | export { Tube } from './extras/Tube.js'; 33 | export { Post } from './extras/Post.js'; 34 | export { Skin } from './extras/Skin.js'; 35 | export { Animation } from './extras/Animation.js'; 36 | export { Text } from './extras/Text.js'; 37 | export { NormalProgram } from './extras/NormalProgram.js'; 38 | export { Flowmap } from './extras/Flowmap.js'; 39 | export { GPGPU } from './extras/GPGPU.js'; 40 | export { Polyline } from './extras/Polyline.js'; 41 | export { Shadow } from './extras/Shadow.js'; 42 | export { KTXTexture } from './extras/KTXTexture.js'; 43 | export { TextureLoader } from './extras/TextureLoader.js'; 44 | export { GLTFLoader } from './extras/GLTFLoader.js'; 45 | export { GLTFSkin } from './extras/GLTFSkin.js'; 46 | export { GLTFAnimation } from './extras/GLTFAnimation.js'; 47 | export { DracoManager } from './extras/DracoManager.js'; 48 | export { BasisManager } from './extras/BasisManager.js'; 49 | export { WireMesh } from './extras/WireMesh.js'; 50 | export { AxesHelper } from './extras/helpers/AxesHelper.js'; 51 | export { GridHelper } from './extras/helpers/GridHelper.js'; 52 | export { VertexNormalsHelper } from './extras/helpers/VertexNormalsHelper.js'; 53 | export { FaceNormalsHelper } from './extras/helpers/FaceNormalsHelper.js'; 54 | export { InstancedMesh } from './extras/InstancedMesh.js'; 55 | export { Texture3D } from './extras/Texture3D.js'; 56 | -------------------------------------------------------------------------------- /src/math/Color.js: -------------------------------------------------------------------------------- 1 | import * as ColorFunc from './functions/ColorFunc.js'; 2 | 3 | // Color stored as an array of RGB decimal values (between 0 > 1) 4 | // Constructor and set method accept following formats: 5 | // new Color() - Empty (defaults to black) 6 | // new Color([0.2, 0.4, 1.0]) - Decimal Array (or another Color instance) 7 | // new Color(0.7, 0.0, 0.1) - Decimal RGB values 8 | // new Color('#ff0000') - Hex string 9 | // new Color('#ccc') - Short-hand Hex string 10 | // new Color(0x4f27e8) - Number 11 | // new Color('red') - Color name string (short list in ColorFunc.js) 12 | 13 | export class Color extends Array { 14 | constructor(color) { 15 | if (Array.isArray(color)) return super(...color); 16 | return super(...ColorFunc.parseColor(...arguments)); 17 | } 18 | 19 | get r() { 20 | return this[0]; 21 | } 22 | 23 | get g() { 24 | return this[1]; 25 | } 26 | 27 | get b() { 28 | return this[2]; 29 | } 30 | 31 | set r(v) { 32 | this[0] = v; 33 | } 34 | 35 | set g(v) { 36 | this[1] = v; 37 | } 38 | 39 | set b(v) { 40 | this[2] = v; 41 | } 42 | 43 | set(color) { 44 | if (Array.isArray(color)) return this.copy(color); 45 | return this.copy(ColorFunc.parseColor(...arguments)); 46 | } 47 | 48 | copy(v) { 49 | this[0] = v[0]; 50 | this[1] = v[1]; 51 | this[2] = v[2]; 52 | return this; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/math/Euler.js: -------------------------------------------------------------------------------- 1 | import * as EulerFunc from './functions/EulerFunc.js'; 2 | import { Mat4 } from './Mat4.js'; 3 | 4 | const tmpMat4 = /* @__PURE__ */ new Mat4(); 5 | 6 | export class Euler extends Array { 7 | constructor(x = 0, y = x, z = x, order = 'YXZ') { 8 | super(x, y, z); 9 | this.order = order; 10 | this.onChange = () => {}; 11 | 12 | // Keep reference to proxy target to avoid triggering onChange internally 13 | this._target = this; 14 | 15 | // Return a proxy to trigger onChange when array elements are edited directly 16 | const triggerProps = ['0', '1', '2']; 17 | return new Proxy(this, { 18 | set(target, property) { 19 | const success = Reflect.set(...arguments); 20 | if (success && triggerProps.includes(property)) target.onChange(); 21 | return success; 22 | }, 23 | }); 24 | } 25 | 26 | get x() { 27 | return this[0]; 28 | } 29 | 30 | get y() { 31 | return this[1]; 32 | } 33 | 34 | get z() { 35 | return this[2]; 36 | } 37 | 38 | set x(v) { 39 | this._target[0] = v; 40 | this.onChange(); 41 | } 42 | 43 | set y(v) { 44 | this._target[1] = v; 45 | this.onChange(); 46 | } 47 | 48 | set z(v) { 49 | this._target[2] = v; 50 | this.onChange(); 51 | } 52 | 53 | set(x, y = x, z = x) { 54 | if (x.length) return this.copy(x); 55 | this._target[0] = x; 56 | this._target[1] = y; 57 | this._target[2] = z; 58 | this.onChange(); 59 | return this; 60 | } 61 | 62 | copy(v) { 63 | this._target[0] = v[0]; 64 | this._target[1] = v[1]; 65 | this._target[2] = v[2]; 66 | this.onChange(); 67 | return this; 68 | } 69 | 70 | reorder(order) { 71 | this._target.order = order; 72 | this.onChange(); 73 | return this; 74 | } 75 | 76 | fromRotationMatrix(m, order = this.order) { 77 | EulerFunc.fromRotationMatrix(this._target, m, order); 78 | this.onChange(); 79 | return this; 80 | } 81 | 82 | fromQuaternion(q, order = this.order, isInternal) { 83 | tmpMat4.fromQuaternion(q); 84 | this._target.fromRotationMatrix(tmpMat4, order); 85 | // Avoid infinite recursion 86 | if (!isInternal) this.onChange(); 87 | return this; 88 | } 89 | 90 | fromArray(a, o = 0) { 91 | this._target[0] = a[o]; 92 | this._target[1] = a[o + 1]; 93 | this._target[2] = a[o + 2]; 94 | return this; 95 | } 96 | 97 | toArray(a = [], o = 0) { 98 | a[o] = this[0]; 99 | a[o + 1] = this[1]; 100 | a[o + 2] = this[2]; 101 | return a; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/math/Mat3.js: -------------------------------------------------------------------------------- 1 | import * as Mat3Func from './functions/Mat3Func.js'; 2 | 3 | export class Mat3 extends Array { 4 | constructor(m00 = 1, m01 = 0, m02 = 0, m10 = 0, m11 = 1, m12 = 0, m20 = 0, m21 = 0, m22 = 1) { 5 | super(m00, m01, m02, m10, m11, m12, m20, m21, m22); 6 | return this; 7 | } 8 | 9 | set(m00, m01, m02, m10, m11, m12, m20, m21, m22) { 10 | if (m00.length) return this.copy(m00); 11 | Mat3Func.set(this, m00, m01, m02, m10, m11, m12, m20, m21, m22); 12 | return this; 13 | } 14 | 15 | translate(v, m = this) { 16 | Mat3Func.translate(this, m, v); 17 | return this; 18 | } 19 | 20 | rotate(v, m = this) { 21 | Mat3Func.rotate(this, m, v); 22 | return this; 23 | } 24 | 25 | scale(v, m = this) { 26 | Mat3Func.scale(this, m, v); 27 | return this; 28 | } 29 | 30 | multiply(ma, mb) { 31 | if (mb) { 32 | Mat3Func.multiply(this, ma, mb); 33 | } else { 34 | Mat3Func.multiply(this, this, ma); 35 | } 36 | return this; 37 | } 38 | 39 | identity() { 40 | Mat3Func.identity(this); 41 | return this; 42 | } 43 | 44 | copy(m) { 45 | Mat3Func.copy(this, m); 46 | return this; 47 | } 48 | 49 | fromMatrix4(m) { 50 | Mat3Func.fromMat4(this, m); 51 | return this; 52 | } 53 | 54 | fromQuaternion(q) { 55 | Mat3Func.fromQuat(this, q); 56 | return this; 57 | } 58 | 59 | fromBasis(vec3a, vec3b, vec3c) { 60 | this.set(vec3a[0], vec3a[1], vec3a[2], vec3b[0], vec3b[1], vec3b[2], vec3c[0], vec3c[1], vec3c[2]); 61 | return this; 62 | } 63 | 64 | inverse(m = this) { 65 | Mat3Func.invert(this, m); 66 | return this; 67 | } 68 | 69 | getNormalMatrix(m) { 70 | Mat3Func.normalFromMat4(this, m); 71 | return this; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/math/Quat.js: -------------------------------------------------------------------------------- 1 | import * as QuatFunc from './functions/QuatFunc.js'; 2 | 3 | export class Quat extends Array { 4 | constructor(x = 0, y = 0, z = 0, w = 1) { 5 | super(x, y, z, w); 6 | this.onChange = () => {}; 7 | 8 | // Keep reference to proxy target to avoid triggering onChange internally 9 | this._target = this; 10 | 11 | // Return a proxy to trigger onChange when array elements are edited directly 12 | const triggerProps = ['0', '1', '2', '3']; 13 | return new Proxy(this, { 14 | set(target, property) { 15 | const success = Reflect.set(...arguments); 16 | if (success && triggerProps.includes(property)) target.onChange(); 17 | return success; 18 | }, 19 | }); 20 | } 21 | 22 | get x() { 23 | return this[0]; 24 | } 25 | 26 | get y() { 27 | return this[1]; 28 | } 29 | 30 | get z() { 31 | return this[2]; 32 | } 33 | 34 | get w() { 35 | return this[3]; 36 | } 37 | 38 | set x(v) { 39 | this._target[0] = v; 40 | this.onChange(); 41 | } 42 | 43 | set y(v) { 44 | this._target[1] = v; 45 | this.onChange(); 46 | } 47 | 48 | set z(v) { 49 | this._target[2] = v; 50 | this.onChange(); 51 | } 52 | 53 | set w(v) { 54 | this._target[3] = v; 55 | this.onChange(); 56 | } 57 | 58 | identity() { 59 | QuatFunc.identity(this._target); 60 | this.onChange(); 61 | return this; 62 | } 63 | 64 | set(x, y, z, w) { 65 | if (x.length) return this.copy(x); 66 | QuatFunc.set(this._target, x, y, z, w); 67 | this.onChange(); 68 | return this; 69 | } 70 | 71 | rotateX(a) { 72 | QuatFunc.rotateX(this._target, this._target, a); 73 | this.onChange(); 74 | return this; 75 | } 76 | 77 | rotateY(a) { 78 | QuatFunc.rotateY(this._target, this._target, a); 79 | this.onChange(); 80 | return this; 81 | } 82 | 83 | rotateZ(a) { 84 | QuatFunc.rotateZ(this._target, this._target, a); 85 | this.onChange(); 86 | return this; 87 | } 88 | 89 | inverse(q = this._target) { 90 | QuatFunc.invert(this._target, q); 91 | this.onChange(); 92 | return this; 93 | } 94 | 95 | conjugate(q = this._target) { 96 | QuatFunc.conjugate(this._target, q); 97 | this.onChange(); 98 | return this; 99 | } 100 | 101 | copy(q) { 102 | QuatFunc.copy(this._target, q); 103 | this.onChange(); 104 | return this; 105 | } 106 | 107 | normalize(q = this._target) { 108 | QuatFunc.normalize(this._target, q); 109 | this.onChange(); 110 | return this; 111 | } 112 | 113 | multiply(qA, qB) { 114 | if (qB) { 115 | QuatFunc.multiply(this._target, qA, qB); 116 | } else { 117 | QuatFunc.multiply(this._target, this._target, qA); 118 | } 119 | this.onChange(); 120 | return this; 121 | } 122 | 123 | dot(v) { 124 | return QuatFunc.dot(this._target, v); 125 | } 126 | 127 | fromMatrix3(matrix3) { 128 | QuatFunc.fromMat3(this._target, matrix3); 129 | this.onChange(); 130 | return this; 131 | } 132 | 133 | fromEuler(euler, isInternal) { 134 | QuatFunc.fromEuler(this._target, euler, euler.order); 135 | // Avoid infinite recursion 136 | if (!isInternal) this.onChange(); 137 | return this; 138 | } 139 | 140 | fromAxisAngle(axis, a) { 141 | QuatFunc.setAxisAngle(this._target, axis, a); 142 | this.onChange(); 143 | return this; 144 | } 145 | 146 | slerp(q, t) { 147 | QuatFunc.slerp(this._target, this._target, q, t); 148 | this.onChange(); 149 | return this; 150 | } 151 | 152 | fromArray(a, o = 0) { 153 | this._target[0] = a[o]; 154 | this._target[1] = a[o + 1]; 155 | this._target[2] = a[o + 2]; 156 | this._target[3] = a[o + 3]; 157 | this.onChange(); 158 | return this; 159 | } 160 | 161 | toArray(a = [], o = 0) { 162 | a[o] = this[0]; 163 | a[o + 1] = this[1]; 164 | a[o + 2] = this[2]; 165 | a[o + 3] = this[3]; 166 | return a; 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/math/Vec2.js: -------------------------------------------------------------------------------- 1 | import * as Vec2Func from './functions/Vec2Func.js'; 2 | 3 | export class Vec2 extends Array { 4 | constructor(x = 0, y = x) { 5 | super(x, y); 6 | return this; 7 | } 8 | 9 | get x() { 10 | return this[0]; 11 | } 12 | 13 | get y() { 14 | return this[1]; 15 | } 16 | 17 | set x(v) { 18 | this[0] = v; 19 | } 20 | 21 | set y(v) { 22 | this[1] = v; 23 | } 24 | 25 | set(x, y = x) { 26 | if (x.length) return this.copy(x); 27 | Vec2Func.set(this, x, y); 28 | return this; 29 | } 30 | 31 | copy(v) { 32 | Vec2Func.copy(this, v); 33 | return this; 34 | } 35 | 36 | add(va, vb) { 37 | if (vb) Vec2Func.add(this, va, vb); 38 | else Vec2Func.add(this, this, va); 39 | return this; 40 | } 41 | 42 | sub(va, vb) { 43 | if (vb) Vec2Func.subtract(this, va, vb); 44 | else Vec2Func.subtract(this, this, va); 45 | return this; 46 | } 47 | 48 | multiply(v) { 49 | if (v.length) Vec2Func.multiply(this, this, v); 50 | else Vec2Func.scale(this, this, v); 51 | return this; 52 | } 53 | 54 | divide(v) { 55 | if (v.length) Vec2Func.divide(this, this, v); 56 | else Vec2Func.scale(this, this, 1 / v); 57 | return this; 58 | } 59 | 60 | inverse(v = this) { 61 | Vec2Func.inverse(this, v); 62 | return this; 63 | } 64 | 65 | // Can't use 'length' as Array.prototype uses it 66 | len() { 67 | return Vec2Func.length(this); 68 | } 69 | 70 | distance(v) { 71 | if (v) return Vec2Func.distance(this, v); 72 | else return Vec2Func.length(this); 73 | } 74 | 75 | squaredLen() { 76 | return this.squaredDistance(); 77 | } 78 | 79 | squaredDistance(v) { 80 | if (v) return Vec2Func.squaredDistance(this, v); 81 | else return Vec2Func.squaredLength(this); 82 | } 83 | 84 | negate(v = this) { 85 | Vec2Func.negate(this, v); 86 | return this; 87 | } 88 | 89 | cross(va, vb) { 90 | if (vb) return Vec2Func.cross(va, vb); 91 | return Vec2Func.cross(this, va); 92 | } 93 | 94 | scale(v) { 95 | Vec2Func.scale(this, this, v); 96 | return this; 97 | } 98 | 99 | normalize() { 100 | Vec2Func.normalize(this, this); 101 | return this; 102 | } 103 | 104 | dot(v) { 105 | return Vec2Func.dot(this, v); 106 | } 107 | 108 | equals(v) { 109 | return Vec2Func.exactEquals(this, v); 110 | } 111 | 112 | applyMatrix3(mat3) { 113 | Vec2Func.transformMat3(this, this, mat3); 114 | return this; 115 | } 116 | 117 | applyMatrix4(mat4) { 118 | Vec2Func.transformMat4(this, this, mat4); 119 | return this; 120 | } 121 | 122 | lerp(v, a) { 123 | Vec2Func.lerp(this, this, v, a); 124 | return this; 125 | } 126 | 127 | smoothLerp(v, decay, dt) { 128 | Vec2Func.smoothLerp(this, this, v, decay, dt); 129 | return this; 130 | } 131 | 132 | clone() { 133 | return new Vec2(this[0], this[1]); 134 | } 135 | 136 | fromArray(a, o = 0) { 137 | this[0] = a[o]; 138 | this[1] = a[o + 1]; 139 | return this; 140 | } 141 | 142 | toArray(a = [], o = 0) { 143 | a[o] = this[0]; 144 | a[o + 1] = this[1]; 145 | return a; 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/math/Vec3.js: -------------------------------------------------------------------------------- 1 | import * as Vec3Func from './functions/Vec3Func.js'; 2 | 3 | export class Vec3 extends Array { 4 | constructor(x = 0, y = x, z = x) { 5 | super(x, y, z); 6 | return this; 7 | } 8 | 9 | get x() { 10 | return this[0]; 11 | } 12 | 13 | get y() { 14 | return this[1]; 15 | } 16 | 17 | get z() { 18 | return this[2]; 19 | } 20 | 21 | set x(v) { 22 | this[0] = v; 23 | } 24 | 25 | set y(v) { 26 | this[1] = v; 27 | } 28 | 29 | set z(v) { 30 | this[2] = v; 31 | } 32 | 33 | set(x, y = x, z = x) { 34 | if (x.length) return this.copy(x); 35 | Vec3Func.set(this, x, y, z); 36 | return this; 37 | } 38 | 39 | copy(v) { 40 | Vec3Func.copy(this, v); 41 | return this; 42 | } 43 | 44 | add(va, vb) { 45 | if (vb) Vec3Func.add(this, va, vb); 46 | else Vec3Func.add(this, this, va); 47 | return this; 48 | } 49 | 50 | sub(va, vb) { 51 | if (vb) Vec3Func.subtract(this, va, vb); 52 | else Vec3Func.subtract(this, this, va); 53 | return this; 54 | } 55 | 56 | multiply(v) { 57 | if (v.length) Vec3Func.multiply(this, this, v); 58 | else Vec3Func.scale(this, this, v); 59 | return this; 60 | } 61 | 62 | divide(v) { 63 | if (v.length) Vec3Func.divide(this, this, v); 64 | else Vec3Func.scale(this, this, 1 / v); 65 | return this; 66 | } 67 | 68 | inverse(v = this) { 69 | Vec3Func.inverse(this, v); 70 | return this; 71 | } 72 | 73 | // Can't use 'length' as Array.prototype uses it 74 | len() { 75 | return Vec3Func.length(this); 76 | } 77 | 78 | distance(v) { 79 | if (v) return Vec3Func.distance(this, v); 80 | else return Vec3Func.length(this); 81 | } 82 | 83 | squaredLen() { 84 | return Vec3Func.squaredLength(this); 85 | } 86 | 87 | squaredDistance(v) { 88 | if (v) return Vec3Func.squaredDistance(this, v); 89 | else return Vec3Func.squaredLength(this); 90 | } 91 | 92 | negate(v = this) { 93 | Vec3Func.negate(this, v); 94 | return this; 95 | } 96 | 97 | cross(va, vb) { 98 | if (vb) Vec3Func.cross(this, va, vb); 99 | else Vec3Func.cross(this, this, va); 100 | return this; 101 | } 102 | 103 | scale(v) { 104 | Vec3Func.scale(this, this, v); 105 | return this; 106 | } 107 | 108 | normalize() { 109 | Vec3Func.normalize(this, this); 110 | return this; 111 | } 112 | 113 | dot(v) { 114 | return Vec3Func.dot(this, v); 115 | } 116 | 117 | equals(v) { 118 | return Vec3Func.exactEquals(this, v); 119 | } 120 | 121 | applyMatrix3(mat3) { 122 | Vec3Func.transformMat3(this, this, mat3); 123 | return this; 124 | } 125 | 126 | applyMatrix4(mat4) { 127 | Vec3Func.transformMat4(this, this, mat4); 128 | return this; 129 | } 130 | 131 | scaleRotateMatrix4(mat4) { 132 | Vec3Func.scaleRotateMat4(this, this, mat4); 133 | return this; 134 | } 135 | 136 | applyQuaternion(q) { 137 | Vec3Func.transformQuat(this, this, q); 138 | return this; 139 | } 140 | 141 | angle(v) { 142 | return Vec3Func.angle(this, v); 143 | } 144 | 145 | lerp(v, t) { 146 | Vec3Func.lerp(this, this, v, t); 147 | return this; 148 | } 149 | 150 | smoothLerp(v, decay, dt) { 151 | Vec3Func.smoothLerp(this, this, v, decay, dt); 152 | return this; 153 | } 154 | 155 | clone() { 156 | return new Vec3(this[0], this[1], this[2]); 157 | } 158 | 159 | fromArray(a, o = 0) { 160 | this[0] = a[o]; 161 | this[1] = a[o + 1]; 162 | this[2] = a[o + 2]; 163 | return this; 164 | } 165 | 166 | toArray(a = [], o = 0) { 167 | a[o] = this[0]; 168 | a[o + 1] = this[1]; 169 | a[o + 2] = this[2]; 170 | return a; 171 | } 172 | 173 | transformDirection(mat4) { 174 | const x = this[0]; 175 | const y = this[1]; 176 | const z = this[2]; 177 | 178 | this[0] = mat4[0] * x + mat4[4] * y + mat4[8] * z; 179 | this[1] = mat4[1] * x + mat4[5] * y + mat4[9] * z; 180 | this[2] = mat4[2] * x + mat4[6] * y + mat4[10] * z; 181 | 182 | return this.normalize(); 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /src/math/Vec4.js: -------------------------------------------------------------------------------- 1 | import * as Vec4Func from './functions/Vec4Func.js'; 2 | 3 | export class Vec4 extends Array { 4 | constructor(x = 0, y = x, z = x, w = x) { 5 | super(x, y, z, w); 6 | return this; 7 | } 8 | 9 | get x() { 10 | return this[0]; 11 | } 12 | 13 | get y() { 14 | return this[1]; 15 | } 16 | 17 | get z() { 18 | return this[2]; 19 | } 20 | 21 | get w() { 22 | return this[3]; 23 | } 24 | 25 | set x(v) { 26 | this[0] = v; 27 | } 28 | 29 | set y(v) { 30 | this[1] = v; 31 | } 32 | 33 | set z(v) { 34 | this[2] = v; 35 | } 36 | 37 | set w(v) { 38 | this[3] = v; 39 | } 40 | 41 | set(x, y = x, z = x, w = x) { 42 | if (x.length) return this.copy(x); 43 | Vec4Func.set(this, x, y, z, w); 44 | return this; 45 | } 46 | 47 | copy(v) { 48 | Vec4Func.copy(this, v); 49 | return this; 50 | } 51 | 52 | normalize() { 53 | Vec4Func.normalize(this, this); 54 | return this; 55 | } 56 | 57 | multiply(v) { 58 | Vec4Func.scale(this, this, v); 59 | return this; 60 | } 61 | 62 | dot(v) { 63 | return Vec4Func.dot(this, v); 64 | } 65 | 66 | fromArray(a, o = 0) { 67 | this[0] = a[o]; 68 | this[1] = a[o + 1]; 69 | this[2] = a[o + 2]; 70 | this[3] = a[o + 3]; 71 | return this; 72 | } 73 | 74 | toArray(a = [], o = 0) { 75 | a[o] = this[0]; 76 | a[o + 1] = this[1]; 77 | a[o + 2] = this[2]; 78 | a[o + 3] = this[3]; 79 | return a; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/math/functions/ColorFunc.js: -------------------------------------------------------------------------------- 1 | const NAMES = { 2 | black: '#000000', 3 | white: '#ffffff', 4 | red: '#ff0000', 5 | green: '#00ff00', 6 | blue: '#0000ff', 7 | fuchsia: '#ff00ff', 8 | cyan: '#00ffff', 9 | yellow: '#ffff00', 10 | orange: '#ff8000', 11 | }; 12 | 13 | export function hexToRGB(hex) { 14 | if (hex.length === 4) hex = hex[0] + hex[1] + hex[1] + hex[2] + hex[2] + hex[3] + hex[3]; 15 | const rgb = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 16 | if (!rgb) console.warn(`Unable to convert hex string ${hex} to rgb values`); 17 | return [parseInt(rgb[1], 16) / 255, parseInt(rgb[2], 16) / 255, parseInt(rgb[3], 16) / 255]; 18 | } 19 | 20 | export function numberToRGB(num) { 21 | num = parseInt(num); 22 | return [((num >> 16) & 255) / 255, ((num >> 8) & 255) / 255, (num & 255) / 255]; 23 | } 24 | 25 | export function parseColor(color) { 26 | // Empty 27 | if (color === undefined) return [0, 0, 0]; 28 | 29 | // Decimal 30 | if (arguments.length === 3) return arguments; 31 | 32 | // Number 33 | if (!isNaN(color)) return numberToRGB(color); 34 | 35 | // Hex 36 | if (color[0] === '#') return hexToRGB(color); 37 | 38 | // Names 39 | if (NAMES[color.toLowerCase()]) return hexToRGB(NAMES[color.toLowerCase()]); 40 | 41 | console.warn('Color format not recognised'); 42 | return [0, 0, 0]; 43 | } 44 | -------------------------------------------------------------------------------- /src/math/functions/EulerFunc.js: -------------------------------------------------------------------------------- 1 | // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) 2 | export function fromRotationMatrix(out, m, order = 'YXZ') { 3 | if (order === 'XYZ') { 4 | out[1] = Math.asin(Math.min(Math.max(m[8], -1), 1)); 5 | if (Math.abs(m[8]) < 0.99999) { 6 | out[0] = Math.atan2(-m[9], m[10]); 7 | out[2] = Math.atan2(-m[4], m[0]); 8 | } else { 9 | out[0] = Math.atan2(m[6], m[5]); 10 | out[2] = 0; 11 | } 12 | } else if (order === 'YXZ') { 13 | out[0] = Math.asin(-Math.min(Math.max(m[9], -1), 1)); 14 | if (Math.abs(m[9]) < 0.99999) { 15 | out[1] = Math.atan2(m[8], m[10]); 16 | out[2] = Math.atan2(m[1], m[5]); 17 | } else { 18 | out[1] = Math.atan2(-m[2], m[0]); 19 | out[2] = 0; 20 | } 21 | } else if (order === 'ZXY') { 22 | out[0] = Math.asin(Math.min(Math.max(m[6], -1), 1)); 23 | if (Math.abs(m[6]) < 0.99999) { 24 | out[1] = Math.atan2(-m[2], m[10]); 25 | out[2] = Math.atan2(-m[4], m[5]); 26 | } else { 27 | out[1] = 0; 28 | out[2] = Math.atan2(m[1], m[0]); 29 | } 30 | } else if (order === 'ZYX') { 31 | out[1] = Math.asin(-Math.min(Math.max(m[2], -1), 1)); 32 | if (Math.abs(m[2]) < 0.99999) { 33 | out[0] = Math.atan2(m[6], m[10]); 34 | out[2] = Math.atan2(m[1], m[0]); 35 | } else { 36 | out[0] = 0; 37 | out[2] = Math.atan2(-m[4], m[5]); 38 | } 39 | } else if (order === 'YZX') { 40 | out[2] = Math.asin(Math.min(Math.max(m[1], -1), 1)); 41 | if (Math.abs(m[1]) < 0.99999) { 42 | out[0] = Math.atan2(-m[9], m[5]); 43 | out[1] = Math.atan2(-m[2], m[0]); 44 | } else { 45 | out[0] = 0; 46 | out[1] = Math.atan2(m[8], m[10]); 47 | } 48 | } else if (order === 'XZY') { 49 | out[2] = Math.asin(-Math.min(Math.max(m[4], -1), 1)); 50 | if (Math.abs(m[4]) < 0.99999) { 51 | out[0] = Math.atan2(m[6], m[5]); 52 | out[1] = Math.atan2(m[8], m[0]); 53 | } else { 54 | out[0] = Math.atan2(-m[9], m[10]); 55 | out[1] = 0; 56 | } 57 | } 58 | 59 | return out; 60 | } 61 | -------------------------------------------------------------------------------- /src/math/functions/Vec4Func.js: -------------------------------------------------------------------------------- 1 | const EPSILON = 0.000001; 2 | 3 | /** 4 | * Copy the values from one vec4 to another 5 | * 6 | * @param {vec4} out the receiving vector 7 | * @param {vec4} a the source vector 8 | * @returns {vec4} out 9 | */ 10 | export function copy(out, a) { 11 | out[0] = a[0]; 12 | out[1] = a[1]; 13 | out[2] = a[2]; 14 | out[3] = a[3]; 15 | return out; 16 | } 17 | 18 | /** 19 | * Set the components of a vec4 to the given values 20 | * 21 | * @param {vec4} out the receiving vector 22 | * @param {Number} x X component 23 | * @param {Number} y Y component 24 | * @param {Number} z Z component 25 | * @param {Number} w W component 26 | * @returns {vec4} out 27 | */ 28 | export function set(out, x, y, z, w) { 29 | out[0] = x; 30 | out[1] = y; 31 | out[2] = z; 32 | out[3] = w; 33 | return out; 34 | } 35 | 36 | /** 37 | * Adds two vec4's 38 | * 39 | * @param {vec4} out the receiving vector 40 | * @param {vec4} a the first operand 41 | * @param {vec4} b the second operand 42 | * @returns {vec4} out 43 | */ 44 | export function add(out, a, b) { 45 | out[0] = a[0] + b[0]; 46 | out[1] = a[1] + b[1]; 47 | out[2] = a[2] + b[2]; 48 | out[3] = a[3] + b[3]; 49 | return out; 50 | } 51 | 52 | /** 53 | * Scales a vec4 by a scalar number 54 | * 55 | * @param {vec4} out the receiving vector 56 | * @param {vec4} a the vector to scale 57 | * @param {Number} b amount to scale the vector by 58 | * @returns {vec4} out 59 | */ 60 | export function scale(out, a, b) { 61 | out[0] = a[0] * b; 62 | out[1] = a[1] * b; 63 | out[2] = a[2] * b; 64 | out[3] = a[3] * b; 65 | return out; 66 | } 67 | 68 | /** 69 | * Calculates the length of a vec4 70 | * 71 | * @param {vec4} a vector to calculate length of 72 | * @returns {Number} length of a 73 | */ 74 | export function length(a) { 75 | let x = a[0]; 76 | let y = a[1]; 77 | let z = a[2]; 78 | let w = a[3]; 79 | return Math.sqrt(x * x + y * y + z * z + w * w); 80 | } 81 | 82 | /** 83 | * Normalize a vec4 84 | * 85 | * @param {vec4} out the receiving vector 86 | * @param {vec4} a vector to normalize 87 | * @returns {vec4} out 88 | */ 89 | export function normalize(out, a) { 90 | let x = a[0]; 91 | let y = a[1]; 92 | let z = a[2]; 93 | let w = a[3]; 94 | let len = x * x + y * y + z * z + w * w; 95 | if (len > 0) { 96 | len = 1 / Math.sqrt(len); 97 | } 98 | out[0] = x * len; 99 | out[1] = y * len; 100 | out[2] = z * len; 101 | out[3] = w * len; 102 | return out; 103 | } 104 | 105 | /** 106 | * Calculates the dot product of two vec4's 107 | * 108 | * @param {vec4} a the first operand 109 | * @param {vec4} b the second operand 110 | * @returns {Number} dot product of a and b 111 | */ 112 | export function dot(a, b) { 113 | return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; 114 | } 115 | 116 | /** 117 | * Performs a linear interpolation between two vec4's 118 | * 119 | * @param {vec4} out the receiving vector 120 | * @param {vec4} a the first operand 121 | * @param {vec4} b the second operand 122 | * @param {Number} t interpolation amount between the two inputs 123 | * @returns {vec4} out 124 | */ 125 | export function lerp(out, a, b, t) { 126 | let ax = a[0]; 127 | let ay = a[1]; 128 | let az = a[2]; 129 | let aw = a[3]; 130 | out[0] = ax + t * (b[0] - ax); 131 | out[1] = ay + t * (b[1] - ay); 132 | out[2] = az + t * (b[2] - az); 133 | out[3] = aw + t * (b[3] - aw); 134 | return out; 135 | } 136 | -------------------------------------------------------------------------------- /types/core/Camera.d.ts: -------------------------------------------------------------------------------- 1 | import { Transform } from './Transform.js'; 2 | import { Mat4 } from '../math/Mat4.js'; 3 | import { Vec3 } from '../math/Vec3.js'; 4 | 5 | import type { OGLRenderingContext } from './Renderer.js'; 6 | import type { Vec3Tuple } from '../math/Vec3.js'; 7 | import type { Mesh } from './Mesh.js'; 8 | 9 | export interface CameraOptions { 10 | near: number; 11 | far: number; 12 | fov: number; 13 | aspect: number; 14 | left: number; 15 | right: number; 16 | bottom: number; 17 | top: number; 18 | zoom: number; 19 | } 20 | 21 | export interface PerspectiveOptions extends Pick {} 22 | 23 | export interface OrthographicOptions extends Pick {} 24 | 25 | export type CameraType = 'perspective' | 'orthographic'; 26 | 27 | /** 28 | * A perspective or orthographic camera. 29 | * @see {@link https://github.com/oframe/ogl/blob/master/src/core/Camera.js | Source} 30 | */ 31 | export class Camera extends Transform { 32 | projectionMatrix: Mat4; 33 | viewMatrix: Mat4; 34 | projectionViewMatrix: Mat4; 35 | worldPosition: Vec3; 36 | 37 | type: CameraType; 38 | 39 | near: number; 40 | far: number; 41 | fov: number; 42 | aspect: number; 43 | left: number; 44 | right: number; 45 | bottom: number; 46 | top: number; 47 | zoom: number; 48 | 49 | frustum: (Vec3 & { 50 | constant: number; 51 | })[]; 52 | 53 | constructor(gl: OGLRenderingContext, options?: Partial); 54 | 55 | perspective(options?: Partial): this; 56 | 57 | orthographic(options?: Partial): this; 58 | 59 | updateMatrixWorld(): this; 60 | 61 | updateProjectionMatrix(): this; 62 | 63 | lookAt(target: Vec3 | Vec3Tuple): this; 64 | 65 | project(v: Vec3): this; 66 | 67 | unproject(v: Vec3): this; 68 | 69 | updateFrustum(): void; 70 | 71 | frustumIntersectsMesh(node: Mesh, worldMatrix?: Mat4): boolean; 72 | 73 | frustumIntersectsSphere(center: Vec3, radius: number): boolean; 74 | } 75 | -------------------------------------------------------------------------------- /types/core/Geometry.d.ts: -------------------------------------------------------------------------------- 1 | import { Vec3 } from '../math/Vec3.js'; 2 | 3 | import type { OGLRenderingContext, RenderState } from './Renderer.js'; 4 | import type { Program } from './Program.js'; 5 | 6 | export type AttributeMap = Record>; 7 | 8 | export type AttributeData = 9 | | Float32Array 10 | | Uint32Array 11 | | Uint16Array 12 | | Int16Array 13 | | Uint8Array 14 | | Int8Array; 15 | 16 | export interface Attribute { 17 | data: AttributeData; 18 | size: number; 19 | instanced: null | number | boolean; 20 | type: GLenum; 21 | normalized: boolean; 22 | 23 | buffer: WebGLBuffer; 24 | stride: number; 25 | offset: number; 26 | count: number; 27 | target: number; 28 | id: number; 29 | divisor: number; 30 | needsUpdate: boolean; 31 | usage: number; 32 | } 33 | 34 | export interface Bounds { 35 | min: Vec3; 36 | max: Vec3; 37 | center: Vec3; 38 | scale: Vec3; 39 | radius: number; 40 | } 41 | 42 | export type GeometryRaycast = 'sphere' | 'box'; 43 | 44 | /** 45 | * A mesh, line, or point geometry. 46 | * @see {@link https://github.com/oframe/ogl/blob/master/src/core/Geometry.js | Source} 47 | */ 48 | export class Geometry { 49 | gl: OGLRenderingContext; 50 | attributes: AttributeMap; 51 | id: number; 52 | 53 | VAOs: { 54 | [programKey: string]: WebGLVertexArrayObject; 55 | }; 56 | 57 | drawRange: { 58 | start: number; 59 | count: number; 60 | }; 61 | instancedCount: number; 62 | 63 | glState: RenderState; 64 | 65 | isInstanced: boolean; 66 | bounds: Bounds; 67 | 68 | // Set from gltf loader 69 | extras?: Record; 70 | extensions?: Record; 71 | 72 | raycast?: GeometryRaycast; // User defined 73 | 74 | constructor(gl: OGLRenderingContext, attributes?: AttributeMap); 75 | 76 | addAttribute(key: string, attr: Partial): number | undefined; 77 | 78 | updateAttribute(attr: Partial): void; 79 | 80 | setIndex(attr: Partial): void; 81 | 82 | setDrawRange(start: number, count: number): void; 83 | 84 | setInstancedCount(value: number): void; 85 | 86 | createVAO(program: Program): void; 87 | 88 | bindAttributes(program: Program): void; 89 | 90 | draw(options: { program: Program; mode?: number }): void; 91 | 92 | getPosition(): Partial; 93 | 94 | computeBoundingBox(attr?: Partial): void; 95 | 96 | computeBoundingSphere(attr?: Partial): void; 97 | 98 | remove(): void; 99 | } 100 | -------------------------------------------------------------------------------- /types/core/Mesh.d.ts: -------------------------------------------------------------------------------- 1 | import { Transform } from './Transform.js'; 2 | import { Mat3 } from '../math/Mat3.js'; 3 | import { Mat4 } from '../math/Mat4.js'; 4 | 5 | import type { OGLRenderingContext } from './Renderer.js'; 6 | import type { Vec2 } from '../math/Vec2.js'; 7 | import type { Vec3 } from '../math/Vec3.js'; 8 | import type { Geometry } from './Geometry.js'; 9 | import type { Program } from './Program.js'; 10 | import type { Camera } from './Camera.js'; 11 | 12 | export interface MeshOptions< 13 | TGeometry extends Geometry = Geometry, 14 | TProgram extends Program = Program, 15 | > { 16 | geometry: TGeometry; 17 | program: TProgram; 18 | mode: GLenum; 19 | frustumCulled: boolean; 20 | renderOrder: number; 21 | } 22 | 23 | export type MeshRenderCallback = (renderInfo: { mesh: Mesh; camera?: Camera }) => any; 24 | 25 | export interface RaycastHit { 26 | localPoint: Vec3; 27 | distance: number; 28 | point: Vec3; 29 | faceNormal: Vec3; 30 | localFaceNormal: Vec3; 31 | uv: Vec2; 32 | localNormal: Vec3; 33 | normal: Vec3; 34 | } 35 | 36 | /** 37 | * Represents a {@link https://en.wikipedia.org/wiki/Polygon_mesh | polygon mesh}. 38 | * @see {@link https://github.com/oframe/ogl/blob/master/src/core/Mesh.js | Source} 39 | */ 40 | export class Mesh< 41 | TGeometry extends Geometry = Geometry, 42 | TProgram extends Program = Program, 43 | > extends Transform { 44 | gl: OGLRenderingContext; 45 | id: number; 46 | geometry: TGeometry; 47 | program: TProgram; 48 | mode: GLenum; 49 | 50 | frustumCulled: boolean; 51 | 52 | renderOrder: number; 53 | modelViewMatrix: Mat4; 54 | normalMatrix: Mat3; 55 | beforeRenderCallbacks: MeshRenderCallback[]; 56 | afterRenderCallbacks: MeshRenderCallback[]; 57 | 58 | hit?: Partial; // Set from raycaster 59 | 60 | constructor(gl: OGLRenderingContext, options?: Partial); 61 | 62 | onBeforeRender(f: MeshRenderCallback): this; 63 | 64 | onAfterRender(f: MeshRenderCallback): this; 65 | 66 | draw(options?: { camera?: Camera }): void; 67 | } 68 | -------------------------------------------------------------------------------- /types/core/Program.d.ts: -------------------------------------------------------------------------------- 1 | import type { OGLRenderingContext, BlendFunc, BlendEquation, StencilFunc, StencilOp } from './Renderer'; 2 | 3 | export interface ProgramOptions { 4 | vertex: string; 5 | fragment: string; 6 | uniforms: Record; 7 | 8 | transparent: boolean; 9 | cullFace: GLenum | false | null; 10 | frontFace: GLenum; 11 | depthTest: boolean; 12 | depthWrite: boolean; 13 | depthFunc: GLenum; 14 | } 15 | 16 | export interface UniformInfo extends WebGLActiveInfo { 17 | uniformName: string; 18 | nameComponents: string[]; 19 | isStruct: boolean; 20 | isStructArray: boolean; 21 | structIndex: number; 22 | structProperty: string; 23 | } 24 | 25 | /** 26 | * A WebGL program. 27 | * @see {@link https://github.com/oframe/ogl/blob/master/src/core/Program.js | Source} 28 | */ 29 | export class Program { 30 | gl: OGLRenderingContext; 31 | uniforms: Record; 32 | id: number; 33 | 34 | transparent: boolean; 35 | cullFace: GLenum | false | null; 36 | frontFace: GLenum; 37 | depthTest: boolean; 38 | depthWrite: boolean; 39 | depthFunc: GLenum; 40 | blendFunc: BlendFunc; 41 | blendEquation: BlendEquation; 42 | stencilRef: GLint; 43 | stencilFunc: StencilFunc; 44 | stencilOp: StencilOp; 45 | 46 | vertexShader: WebGLShader; 47 | fragmentShader: WebGLShader; 48 | program: WebGLProgram; 49 | uniformLocations: Map; 50 | attributeLocations: Map; 51 | attributeOrder: string; 52 | 53 | constructor(gl: OGLRenderingContext, options?: Partial); 54 | 55 | setShaders(options: { vertex: string; fragment: string }): void; 56 | 57 | setBlendFunc(src: GLenum, dst: GLenum, srcAlpha?: GLenum, dstAlpha?: GLenum): void; 58 | 59 | setBlendEquation(modeRGB: GLenum, modeAlpha: GLenum): void; 60 | 61 | setStencilFunc(func: GLenum, ref: GLint, mask: GLuint): void; 62 | 63 | setStencilOp(stencilFail: GLenum, depthFail: GLenum, depthPass: GLenum): void; 64 | 65 | applyState(): void; 66 | 67 | use(options?: { flipFaces?: boolean }): void; 68 | 69 | remove(): void; 70 | } 71 | -------------------------------------------------------------------------------- /types/core/RenderTarget.d.ts: -------------------------------------------------------------------------------- 1 | import { Texture } from './Texture.js'; 2 | 3 | import type { OGLRenderingContext } from './Renderer.js'; 4 | 5 | export interface RenderTargetOptions { 6 | width: number; 7 | height: number; 8 | target: GLenum; 9 | color: number; 10 | depth: boolean; 11 | stencil: boolean; 12 | depthTexture: boolean; 13 | wrapS: GLenum; 14 | wrapT: GLenum; 15 | wrapR: GLenum; 16 | minFilter: GLenum; 17 | magFilter: GLenum; 18 | type: GLenum; 19 | format: GLenum; 20 | internalFormat: GLenum; 21 | unpackAlignment: number; 22 | premultiplyAlpha: boolean; 23 | } 24 | 25 | /** 26 | * A render target. 27 | * @see {@link https://github.com/oframe/ogl/blob/master/src/core/RenderTarget.js | Source} 28 | */ 29 | export class RenderTarget { 30 | gl: OGLRenderingContext; 31 | width: number; 32 | height: number; 33 | depth: boolean; 34 | stencil: boolean; 35 | buffer: WebGLFramebuffer; 36 | target: number; 37 | 38 | textures: Texture[]; 39 | texture: Texture; 40 | depthTexture: Texture; 41 | depthBuffer: WebGLRenderbuffer; 42 | stencilBuffer: WebGLRenderbuffer; 43 | depthStencilBuffer: WebGLRenderbuffer; 44 | 45 | constructor(gl: OGLRenderingContext, options?: Partial); 46 | 47 | setSize(width: number, height: number): void; 48 | } 49 | -------------------------------------------------------------------------------- /types/core/Texture.d.ts: -------------------------------------------------------------------------------- 1 | import type { OGLRenderingContext, RenderState } from './Renderer'; 2 | 3 | export type CompressedImage = { 4 | isCompressedTexture?: boolean; 5 | data: Uint8Array; 6 | width: number; 7 | height: number; 8 | }[]; 9 | 10 | export type ImageRepresentation = 11 | | HTMLImageElement 12 | | HTMLCanvasElement 13 | | HTMLVideoElement 14 | | HTMLImageElement[] 15 | | HTMLCanvasElement[] 16 | | ArrayBufferView 17 | | CompressedImage; 18 | 19 | export interface TextureOptions { 20 | image: ImageRepresentation; 21 | target: number; 22 | type: number; 23 | format: number; 24 | internalFormat: number; 25 | wrapS: number; 26 | wrapT: number; 27 | wrapR: number; 28 | generateMipmaps: boolean; 29 | minFilter: number; 30 | magFilter: number; 31 | premultiplyAlpha: boolean; 32 | unpackAlignment: number; 33 | flipY: boolean; 34 | anisotropy: number; 35 | level: number; 36 | width: number; 37 | height: number; 38 | length: number; 39 | } 40 | 41 | /** 42 | * A surface, reflection, or refraction map. 43 | * @see {@link https://github.com/oframe/ogl/blob/master/src/core/Texture.js | Source} 44 | */ 45 | export class Texture { 46 | gl: OGLRenderingContext; 47 | id: number; 48 | 49 | image?: ImageRepresentation; 50 | target: number; 51 | type: number; 52 | format: number; 53 | internalFormat: number; 54 | minFilter: number; 55 | magFilter: number; 56 | wrapS: number; 57 | wrapT: number; 58 | wrapR: number; 59 | generateMipmaps: boolean; 60 | premultiplyAlpha: boolean; 61 | unpackAlignment: number; 62 | flipY: boolean; 63 | anisotropy: number; 64 | level: number; 65 | width: number; 66 | height: number; 67 | length: number; 68 | texture: WebGLTexture; 69 | 70 | store: { 71 | image?: ImageRepresentation | null; 72 | }; 73 | 74 | glState: RenderState; 75 | 76 | state: { 77 | minFilter: number; 78 | magFilter: number; 79 | wrapS: number; 80 | wrapT: number; 81 | anisotropy: number; 82 | }; 83 | 84 | needsUpdate: boolean; 85 | 86 | // Set from texture loader 87 | onUpdate?: () => void | null; 88 | ext?: string; 89 | name?: string; 90 | loaded?: Promise; 91 | 92 | constructor(gl: OGLRenderingContext, options?: Partial); 93 | 94 | bind(): void; 95 | 96 | update(textureUnit?: number): void; 97 | } 98 | -------------------------------------------------------------------------------- /types/core/Transform.d.ts: -------------------------------------------------------------------------------- 1 | import type { Euler } from '../math/Euler.js'; 2 | import type { Mat4 } from '../math/Mat4.js'; 3 | import type { Quat } from '../math/Quat.js'; 4 | import type { Vec3, Vec3Tuple } from '../math/Vec3.js'; 5 | import type { GLTFLoader } from '../extras/GLTFLoader.d.js'; 6 | 7 | /** 8 | * The base class for most objects and provides a set of properties and methods for manipulating 9 | * objects in 3D space. 10 | * @see {@link https://github.com/oframe/ogl/blob/master/src/core/Transform.js | Source} 11 | */ 12 | export class Transform { 13 | /** 14 | * The parent. 15 | * @see {@link https://en.wikipedia.org/wiki/Scene_graph | scene graph}. 16 | */ 17 | parent: Transform | null; 18 | 19 | /** 20 | * An array with the children. 21 | */ 22 | children: Transform[]; 23 | 24 | /** 25 | * The visibility. 26 | */ 27 | visible: boolean; 28 | 29 | /** 30 | * The local transform matrix. 31 | */ 32 | matrix: Mat4; 33 | 34 | /** 35 | * The world transform matrix. 36 | */ 37 | worldMatrix: Mat4; 38 | 39 | /** 40 | * When set, it updates the local transform matrix every frame and also updates the worldMatrix 41 | * property. 42 | * @defaultValue `true` 43 | */ 44 | matrixAutoUpdate: boolean; 45 | 46 | /** 47 | * When set, it updates the world transform matrix in that frame and resets this property to 48 | * false. 49 | * @defaultValue `false` 50 | */ 51 | worldMatrixNeedsUpdate: boolean; 52 | 53 | /** 54 | * The local position. 55 | */ 56 | position: Vec3; 57 | 58 | /** 59 | * The local rotation as a {@link Quat | Quaternion}. 60 | */ 61 | quaternion: Quat; 62 | 63 | /** 64 | * The local scale. 65 | * @defaultValue `new Vec3(1)` 66 | */ 67 | scale: Vec3; 68 | 69 | /** 70 | * The local rotation as {@link Euler | Euler angles}. 71 | */ 72 | rotation: Euler; 73 | 74 | /** 75 | * Up vector used by the {@link lookAt | lookAt} method. 76 | * @defaultValue `new Vec3(0, 1, 0)` 77 | */ 78 | up: Vec3; 79 | 80 | /** 81 | * Set from {@link GLTFLoader | GLTF Loader}. 82 | */ 83 | name?: string; 84 | extras?: Record; 85 | extensions?: Record; 86 | 87 | /** 88 | * Creates a new transform object. 89 | */ 90 | constructor(); 91 | 92 | /** 93 | * Sets the parent. 94 | * @param {Transform | null} parent The parent. 95 | * @param {boolean} [notifyParent=true] Adds this as a child of the parent. 96 | */ 97 | setParent(parent: Transform | null, notifyParent?: boolean): void; 98 | 99 | /** 100 | * Adds a child. 101 | * @param {Transform} child The child. 102 | * @param {boolean} [notifyChild=true] Sets the parent of the child to this. 103 | */ 104 | addChild(child: Transform, notifyChild?: boolean): void; 105 | 106 | /** 107 | * Removes a child. 108 | * @param {Transform} child The child. 109 | * @param {boolean} [notifyChild=true] Sets the parent of the child to null. 110 | */ 111 | removeChild(child: Transform, notifyChild?: boolean): void; 112 | 113 | /** 114 | * Updates the world transform matrix. 115 | */ 116 | updateMatrixWorld(force?: boolean): void; 117 | 118 | /** 119 | * Updates the local transform matrix. 120 | */ 121 | updateMatrix(): void; 122 | 123 | /** 124 | * Executes the callback on this transform object and all descendants. 125 | * @param {Function} callback The callback. 126 | */ 127 | traverse(callback: (node: Transform) => boolean | void): void; 128 | 129 | /** 130 | * Decomposes this transform object into it's position, quaternion and scale components. 131 | */ 132 | decompose(): void; 133 | 134 | /** 135 | * Rotates this transform object to face a target vector. 136 | * @param {Vec3 | Vec3Tuple} target A target vector to look at. 137 | * @param {boolean} [invert=false] Invert the local position and target vector. 138 | */ 139 | lookAt(target: Vec3 | Vec3Tuple, invert?: boolean): void; 140 | } 141 | -------------------------------------------------------------------------------- /types/extras/Animation.d.ts: -------------------------------------------------------------------------------- 1 | import { Vec3 } from '../math/Vec3.js'; 2 | import { Quat } from '../math/Quat.js'; 3 | 4 | import type { OGLRenderingContext } from '../core/Renderer.js'; 5 | import type { BoneTransform } from './Skin.js'; 6 | 7 | export interface AnimationFrame { 8 | position: Vec3; 9 | quaternion: Quat; 10 | scale: Vec3; 11 | } 12 | 13 | export interface AnimationData { 14 | frames: AnimationFrame[]; 15 | } 16 | 17 | export interface AnimationOptions { 18 | objects: BoneTransform[]; 19 | data: AnimationData; 20 | } 21 | 22 | /** 23 | * A class for animation. 24 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Animation.js | Source} 25 | */ 26 | export class Animation { 27 | objects: BoneTransform[]; 28 | data: AnimationData; 29 | elapsed: number; 30 | weight: number; 31 | duration: number; 32 | 33 | constructor(gl: OGLRenderingContext, options?: Partial); 34 | 35 | update(totalWeight?: number, isSet?: boolean): void; 36 | } 37 | -------------------------------------------------------------------------------- /types/extras/BasisManager.d.ts: -------------------------------------------------------------------------------- 1 | import type { OGLRenderingContext } from '../core/Renderer.js'; 2 | 3 | export type BasisManagerFormat = 'astc' | 'bptc' | 's3tc' | 'etc1' | 'pvrtc' | 'none'; 4 | 5 | export type BasisImage = (Uint8Array | Uint16Array) & { 6 | width: number; 7 | height: number; 8 | isCompressedTexture: boolean; 9 | internalFormat: number; 10 | isBasis: boolean; 11 | }; 12 | 13 | /** 14 | * A {@link https://github.com/BinomialLLC/basis_universal | Basis Universal GPU Texture} loader. 15 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/BasisManager.js | Source} 16 | */ 17 | export class BasisManager { 18 | constructor(workerSrc: string | URL, gl?: OGLRenderingContext); 19 | 20 | getSupportedFormat(gl?: OGLRenderingContext): BasisManagerFormat; 21 | 22 | initWorker(workerSrc: string | URL): void; 23 | 24 | onMessage(event: { data: { id: number; error: string; image: BasisImage } }): void; 25 | 26 | parseTexture(buffer: ArrayBuffer): Promise; 27 | } 28 | -------------------------------------------------------------------------------- /types/extras/Box.d.ts: -------------------------------------------------------------------------------- 1 | import { Geometry } from '../core/Geometry.js'; 2 | 3 | import type { OGLRenderingContext } from '../core/Renderer.js'; 4 | import type { AttributeMap } from '../core/Geometry.js'; 5 | 6 | export interface BoxOptions { 7 | width: number; 8 | height: number; 9 | depth: number; 10 | widthSegments: number; 11 | heightSegments: number; 12 | depthSegments: number; 13 | attributes: AttributeMap; 14 | } 15 | 16 | /** 17 | * A box geometry. 18 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Box.js | Source} 19 | */ 20 | export class Box extends Geometry { 21 | constructor(gl: OGLRenderingContext, options?: Partial); 22 | } 23 | -------------------------------------------------------------------------------- /types/extras/Curve.d.ts: -------------------------------------------------------------------------------- 1 | import { Vec3 } from '../math/Vec3.js'; 2 | 3 | export type CurveType = 'catmullrom' | 'cubicbezier' | 'quadraticbezier'; 4 | 5 | export interface CurveOptions { 6 | points: Vec3[]; 7 | divisions: number; 8 | type: CurveType; 9 | } 10 | 11 | /** 12 | * A class for creating curves. 13 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Curve.js | Source} 14 | */ 15 | export class Curve { 16 | static CATMULLROM: 'catmullrom'; 17 | static CUBICBEZIER: 'cubicbezier'; 18 | static QUADRATICBEZIER: 'quadraticbezier'; 19 | 20 | points: Vec3[]; 21 | divisions: number; 22 | type: CurveType; 23 | 24 | constructor(options?: Partial); 25 | 26 | getPoints(divisions?: number, a?: number, b?: number): Vec3[]; 27 | } 28 | -------------------------------------------------------------------------------- /types/extras/Cylinder.d.ts: -------------------------------------------------------------------------------- 1 | import { Geometry } from '../core/Geometry.js'; 2 | 3 | import type { OGLRenderingContext } from '../core/Renderer.js'; 4 | import type { AttributeMap } from '../core/Geometry.js'; 5 | 6 | export interface CylinderOptions { 7 | radiusTop: number; 8 | radiusBottom: number; 9 | height: number; 10 | radialSegments: number; 11 | heightSegments: number; 12 | openEnded: boolean; 13 | thetaStart: number; 14 | thetaLength: number; 15 | attributes: AttributeMap; 16 | } 17 | 18 | /** 19 | * A cylinder geometry. 20 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Cylinder.js | Source} 21 | */ 22 | export class Cylinder extends Geometry { 23 | constructor(gl: OGLRenderingContext, options?: Partial); 24 | } 25 | -------------------------------------------------------------------------------- /types/extras/DracoManager.d.ts: -------------------------------------------------------------------------------- 1 | import type { AttributeData } from '../core/Geometry.js'; 2 | 3 | export type AttributeIds = Record; 4 | 5 | export type AttributeTypes = Record; 13 | 14 | export interface DecodeGeometryConfig { 15 | attributeIds: AttributeIds; 16 | attributeTypes: AttributeTypes; 17 | } 18 | 19 | export interface IndexResult { 20 | array: Uint32Array; 21 | itemSize: number; 22 | } 23 | 24 | export interface AttributeResult { 25 | name: string; 26 | array: AttributeData; 27 | itemSize: number; 28 | normalized?: boolean; 29 | } 30 | 31 | export interface GeometryData { 32 | index: IndexResult; 33 | attributes: AttributeResult[]; 34 | } 35 | 36 | /** 37 | * A {@link https://github.com/google/draco | Draco 3D Data Compression} loader. 38 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/DracoManager.js | Source} 39 | */ 40 | export class DracoManager { 41 | constructor(workerSrc: string | URL); 42 | 43 | initWorker(workerSrc: string | URL): void; 44 | 45 | onMessage(event: { data: { id: number; error: string; geometry: GeometryData } }): void; 46 | 47 | decodeGeometry(buffer: ArrayBuffer, config: DecodeGeometryConfig): Promise; 48 | } 49 | -------------------------------------------------------------------------------- /types/extras/Flowmap.d.ts: -------------------------------------------------------------------------------- 1 | import { RenderTarget } from '../core/RenderTarget.js'; 2 | import { Mesh } from '../core/Mesh.js'; 3 | import { Vec2 } from '../math/Vec2.js'; 4 | 5 | import type { OGLRenderingContext } from '../core/Renderer.js'; 6 | 7 | export interface FlowmapOptions { 8 | size: number; 9 | falloff: number; 10 | alpha: number; 11 | dissipation: number; 12 | type: number; 13 | } 14 | 15 | /** 16 | * Mouse flowmap. 17 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Flowmap.js | Source} 18 | */ 19 | export class Flowmap { 20 | gl: OGLRenderingContext; 21 | 22 | uniform: { value: RenderTarget['texture'] | null }; 23 | 24 | mask: { 25 | read: RenderTarget; 26 | write: RenderTarget; 27 | swap: () => void; 28 | }; 29 | 30 | aspect: number; 31 | mouse: Vec2; 32 | velocity: Vec2; 33 | 34 | mesh: Mesh; 35 | 36 | constructor(gl: OGLRenderingContext, options?: Partial); 37 | 38 | update(): void; 39 | } 40 | -------------------------------------------------------------------------------- /types/extras/GLTFAnimation.d.ts: -------------------------------------------------------------------------------- 1 | export interface GLTFAnimationData { 2 | node: any; 3 | transform: any; 4 | interpolation: any; 5 | times: any; 6 | values: any; 7 | } 8 | 9 | /** 10 | * A class for animation. 11 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/GLTFAnimation.js | Source} 12 | */ 13 | export class GLTFAnimation { 14 | data: GLTFAnimationData[]; 15 | elapsed: number; 16 | weight: number; 17 | loop: boolean; 18 | startTime: number; 19 | endTime: number; 20 | duration: number; 21 | 22 | constructor(data: GLTFAnimationData[], weight?: number); 23 | 24 | update(totalWeight?: number, isSet?: boolean): void; 25 | 26 | cubicSplineInterpolate(t: number, prevVal: any, prevTan: any, nextTan: any, nextVal: any): any; 27 | } 28 | -------------------------------------------------------------------------------- /types/extras/GLTFSkin.d.ts: -------------------------------------------------------------------------------- 1 | import { Mesh } from '../core/Mesh.js'; 2 | import { Mat4 } from '../math/Mat4.js'; 3 | import { Texture } from '../core/Texture.js'; 4 | 5 | import type { OGLRenderingContext } from '../core/Renderer.js'; 6 | import type { Geometry } from '../core/Geometry.js'; 7 | import type { Program } from '../core/Program.js'; 8 | import type { Camera } from '../core/Camera.js'; 9 | 10 | export interface GLTFSkinSkeleton { 11 | joints: { worldMatrix: Mat4; bindInverse: Mat4 }[]; 12 | } 13 | 14 | export interface GLTFSkinOptions { 15 | skeleton: GLTFSkinSkeleton; 16 | geometry: Geometry; 17 | program: Program; 18 | mode: GLenum; 19 | } 20 | 21 | /** 22 | * A mesh with a skeleton and bones for animation. 23 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/GLTFSkin.js | Source} 24 | */ 25 | export class GLTFSkin extends Mesh { 26 | skeleton: GLTFSkinSkeleton; 27 | program: TProgram; 28 | 29 | boneMatrices: Float32Array; 30 | boneTextureSize: number; 31 | boneTexture: Texture; 32 | 33 | constructor(gl: OGLRenderingContext, options?: Partial); 34 | 35 | createBoneTexture(): void; 36 | 37 | updateUniforms(): void; 38 | 39 | override draw(options?: { camera?: Camera }): void; 40 | } 41 | -------------------------------------------------------------------------------- /types/extras/GPGPU.d.ts: -------------------------------------------------------------------------------- 1 | import { Program } from '../core/Program.js'; 2 | import { Mesh } from '../core/Mesh.js'; 3 | import { Texture } from '../core/Texture.js'; 4 | import { RenderTarget } from '../core/RenderTarget.js'; 5 | import { Triangle } from './Triangle.js'; 6 | 7 | import type { OGLRenderingContext } from '../core/Renderer.js'; 8 | 9 | export interface GPGPUOptions { 10 | data: Float32Array; 11 | geometry: Triangle; 12 | type: Texture['type']; 13 | } 14 | 15 | export interface GPGPUPass { 16 | mesh: Mesh; 17 | program: Program; 18 | uniforms: Record; 19 | enabled: boolean; 20 | textureUniform: string; 21 | vertex: string; 22 | fragment: string; 23 | } 24 | 25 | /** 26 | * A class for {@link https://en.wikipedia.org/wiki/General-purpose_computing_on_graphics_processing_units | GPGPU (General Purpose GPU)} calculations. 27 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/GPGPU.js | Source} 28 | */ 29 | export class GPGPU { 30 | gl: OGLRenderingContext; 31 | passes: GPGPUPass[]; 32 | geometry: Triangle; 33 | dataLength: number; 34 | size: number; 35 | coords: Float32Array; 36 | uniform: { value: any }; 37 | 38 | fbo: { 39 | read: RenderTarget; 40 | write: RenderTarget; 41 | swap: () => void; 42 | }; 43 | 44 | constructor(gl: OGLRenderingContext, options?: Partial); 45 | 46 | addPass(options?: Partial): GPGPUPass; 47 | 48 | render(): void; 49 | } 50 | -------------------------------------------------------------------------------- /types/extras/InstancedMesh.d.ts: -------------------------------------------------------------------------------- 1 | import { Mesh } from '../core/Mesh.js'; 2 | 3 | /** 4 | * A special version of {@link Mesh | Mesh} with instanced frustum culling. 5 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/InstancedMesh.js | Source} 6 | */ 7 | export class InstancedMesh extends Mesh { 8 | readonly isInstancedMesh: true; 9 | 10 | addFrustumCull(): void; 11 | 12 | removeFrustumCull(): void; 13 | } 14 | -------------------------------------------------------------------------------- /types/extras/KTXTexture.d.ts: -------------------------------------------------------------------------------- 1 | import { Texture } from '../core/Texture.js'; 2 | 3 | import type { OGLRenderingContext } from '../core/Renderer.js'; 4 | 5 | export interface KTXTextureOptions { 6 | buffer: ArrayBuffer; 7 | src: string; 8 | wrapS: number; 9 | wrapT: number; 10 | anisotropy: number; 11 | minFilter: number; 12 | magFilter: number; 13 | } 14 | 15 | /** 16 | * A {@link https://github.com/KhronosGroup/KTX-Specification | KTX 2.0 GPU Texture} container. 17 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/KTXTexture.js | Source} 18 | */ 19 | export class KTXTexture extends Texture { 20 | constructor(gl: OGLRenderingContext, options?: Partial); 21 | 22 | parseBuffer(buffer: ArrayBuffer): void; 23 | } 24 | -------------------------------------------------------------------------------- /types/extras/NormalProgram.d.ts: -------------------------------------------------------------------------------- 1 | import { Program } from '../core/Program.js'; 2 | 3 | import type { OGLRenderingContext } from '../core/Renderer.js'; 4 | import type { ProgramOptions } from '../core/Program.js'; 5 | 6 | /** 7 | * A normal program. 8 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/NormalProgram.js | Source} 9 | */ 10 | export class NormalProgram extends Program { 11 | constructor(gl: OGLRenderingContext, options?: Partial); 12 | } 13 | -------------------------------------------------------------------------------- /types/extras/Orbit.d.ts: -------------------------------------------------------------------------------- 1 | import { Vec3 } from '../math/Vec3.js'; 2 | 3 | import type { Camera } from '../core/Camera.js'; 4 | 5 | export type ZoomStyle = 'dolly' | 'fov'; 6 | 7 | export interface OrbitOptions { 8 | element: HTMLElement; 9 | enabled: boolean; 10 | target: Vec3; 11 | ease: number; 12 | inertia: number; 13 | enableRotate: boolean; 14 | rotateSpeed: number; 15 | autoRotate: boolean; 16 | autoRotateSpeed: number; 17 | enableZoom: boolean; 18 | zoomSpeed: number; 19 | zoomStyle: ZoomStyle; 20 | enablePan: boolean; 21 | panSpeed: number; 22 | minPolarAngle: number; 23 | maxPolarAngle: number; 24 | minAzimuthAngle: number; 25 | maxAzimuthAngle: number; 26 | minDistance: number; 27 | maxDistance: number; 28 | } 29 | 30 | /** 31 | * Orbit controls based on the three.js `OrbitControls` class, rewritten using ES6 with some 32 | * additions and subtractions. 33 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Orbit.js | Source} 34 | * @see {@link https://github.com/mrdoob/three.js/blob/master/examples/jsm/controls/OrbitControls.js | `OrbitControls` Source} 35 | */ 36 | export class Orbit { 37 | enabled: boolean; 38 | target: Vec3; 39 | zoomStyle: ZoomStyle; 40 | 41 | minDistance: number; 42 | maxDistance: number; 43 | 44 | offset: Vec3; 45 | 46 | constructor(object: Camera, options?: Partial); 47 | 48 | update(): void; 49 | 50 | forcePosition(): void; 51 | 52 | remove(): void; 53 | } 54 | -------------------------------------------------------------------------------- /types/extras/Plane.d.ts: -------------------------------------------------------------------------------- 1 | import { Geometry } from '../core/Geometry.js'; 2 | 3 | import type { OGLRenderingContext } from '../core/Renderer.js'; 4 | import type { AttributeMap } from '../core/Geometry.js'; 5 | 6 | export interface PlaneOptions { 7 | width: number; 8 | height: number; 9 | widthSegments: number; 10 | heightSegments: number; 11 | attributes: AttributeMap; 12 | } 13 | 14 | /** 15 | * A plane geometry. 16 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Plane.js | Source} 17 | */ 18 | export class Plane extends Geometry { 19 | constructor(gl: OGLRenderingContext, options?: Partial); 20 | 21 | static buildPlane( 22 | position: Float32Array, 23 | normal: Float32Array, 24 | uv: Float32Array, 25 | index: Uint32Array | Uint16Array, 26 | width: number, 27 | height: number, 28 | depth: number, 29 | wSegs: number, 30 | hSegs: number, 31 | u: number, 32 | v: number, 33 | w: number, 34 | uDir: number, 35 | vDir: number, 36 | i: number, 37 | ii: number, 38 | ): void; 39 | } 40 | -------------------------------------------------------------------------------- /types/extras/Polyline.d.ts: -------------------------------------------------------------------------------- 1 | import { Geometry } from '../core/Geometry.js'; 2 | import { Program } from '../core/Program.js'; 3 | import { Mesh } from '../core/Mesh.js'; 4 | import { Vec2 } from '../math/Vec2.js'; 5 | import { Vec3 } from '../math/Vec3.js'; 6 | import { Color } from '../math/Color.js'; 7 | 8 | import type { OGLRenderingContext } from '../core/Renderer.js'; 9 | import type { AttributeMap } from '../core/Geometry.js'; 10 | 11 | export interface PolylineOptions { 12 | points: Vec3[]; 13 | vertex: string; 14 | fragment: string; 15 | uniforms: Record; 16 | attributes: AttributeMap; 17 | } 18 | 19 | /** 20 | * A polyline mesh. 21 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Polyline.js | Source} 22 | */ 23 | export class Polyline { 24 | gl: OGLRenderingContext; 25 | points: Vec3[]; 26 | count: number; 27 | 28 | position: Float32Array; 29 | prev: Float32Array; 30 | next: Float32Array; 31 | 32 | geometry: Geometry; 33 | 34 | resolution: { value: Vec2 }; 35 | dpr: { value: number }; 36 | thickness: { value: number }; 37 | color: { value: Color }; 38 | miter: { value: number }; 39 | 40 | program: Program; 41 | 42 | mesh: Mesh; 43 | 44 | constructor(gl: OGLRenderingContext, options?: Partial); 45 | 46 | updateGeometry(): void; 47 | 48 | resize(): void; 49 | } 50 | -------------------------------------------------------------------------------- /types/extras/Post.d.ts: -------------------------------------------------------------------------------- 1 | import { Program } from '../core/Program.js'; 2 | import { Mesh } from '../core/Mesh.js'; 3 | import { RenderTarget } from '../core/RenderTarget.js'; 4 | import { Triangle } from './Triangle.js'; 5 | 6 | import type { OGLRenderingContext } from '../core/Renderer.js'; 7 | import type { Camera } from '../core/Camera.js'; 8 | import type { Transform } from '../core/Transform.js'; 9 | import type { Texture } from '../core/Texture.js'; 10 | 11 | export interface PostOptions { 12 | width: number; 13 | height: number; 14 | dpr: number; 15 | wrapS: GLenum; 16 | wrapT: GLenum; 17 | minFilter: GLenum; 18 | magFilter: GLenum; 19 | geometry: Triangle; 20 | targetOnly: boolean; 21 | depth: boolean; 22 | } 23 | 24 | export interface Pass { 25 | mesh: Mesh; 26 | program: Program; 27 | uniforms: Record; 28 | enabled: boolean; 29 | textureUniform: string; 30 | vertex: string; 31 | fragment: string; 32 | } 33 | 34 | /** 35 | * A class for managing post-processing shader passes. 36 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Post.js | Source} 37 | */ 38 | export class Post { 39 | gl: OGLRenderingContext; 40 | 41 | passes: Pass[]; 42 | 43 | geometry: Triangle; 44 | 45 | uniform: { value: any }; 46 | targetOnly: boolean; 47 | 48 | dpr: number; 49 | width: number; 50 | height: number; 51 | 52 | resolutionWidth: number; 53 | resolutionHeight: number; 54 | 55 | fbo: { 56 | read: RenderTarget; 57 | write: RenderTarget; 58 | swap: () => void; 59 | }; 60 | 61 | constructor(gl: OGLRenderingContext, options?: Partial); 62 | 63 | addPass(options?: Partial): Pass; 64 | 65 | resize( 66 | options?: Partial<{ 67 | width: number; 68 | height: number; 69 | dpr: number; 70 | }>, 71 | ): void; 72 | 73 | render( 74 | options: Partial<{ 75 | scene: Transform; 76 | camera: Camera; 77 | texture: Texture; 78 | target: RenderTarget; 79 | update: boolean; 80 | sort: boolean; 81 | frustumCull: boolean; 82 | beforePostCallbacks: Function[]; 83 | }>, 84 | ): void; 85 | } 86 | -------------------------------------------------------------------------------- /types/extras/Raycast.d.ts: -------------------------------------------------------------------------------- 1 | import { Vec2 } from '../math/Vec2.js'; 2 | import { Vec3 } from '../math/Vec3.js'; 3 | 4 | import type { Vec2Tuple } from '../math/Vec2.js'; 5 | import type { Bounds } from '../core/Geometry.js'; 6 | import type { Camera } from '../core/Camera.js'; 7 | import type { Mesh } from '../core/Mesh.js'; 8 | 9 | /** 10 | * A class to assist with {@link https://en.wikipedia.org/wiki/Ray_casting | raycasting}. 11 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Raycast.js | Source} 12 | */ 13 | export class Raycast { 14 | origin: Vec3; 15 | direction: Vec3; 16 | 17 | constructor(); 18 | 19 | castMouse(camera: Camera, mouse?: Vec2 | Vec2Tuple): void; 20 | 21 | intersectBounds(meshes: Mesh | Mesh[], options?: { maxDistance?: number; output?: Mesh[] }): Mesh[]; 22 | 23 | intersectMeshes( 24 | meshes: Mesh[], 25 | options?: { 26 | cullFace?: boolean; 27 | maxDistance?: number; 28 | includeUV?: boolean; 29 | includeNormal?: boolean; 30 | output?: Mesh[]; 31 | }, 32 | ): Mesh[]; 33 | 34 | intersectPlane(plane: { origin: Vec3; normal: Vec3 }, origin?: Vec3, direction?: Vec3): Vec3; 35 | 36 | intersectSphere(sphere: Bounds, origin?: Vec3, direction?: Vec3): number; 37 | 38 | intersectBox(box: Bounds, origin?: Vec3, direction?: Vec3): number; 39 | 40 | intersectTriangle(a: Vec3, b: Vec3, c: Vec3, backfaceCulling?: boolean, origin?: Vec3, direction?: Vec3, normal?: Vec3): number; 41 | 42 | getBarycoord(point: Vec3, a: Vec3, b: Vec3, c: Vec3, target?: Vec3): Vec3; 43 | } 44 | -------------------------------------------------------------------------------- /types/extras/Shadow.d.ts: -------------------------------------------------------------------------------- 1 | import { Camera } from '../core/Camera.js'; 2 | import { Program } from '../core/Program.js'; 3 | import { RenderTarget } from '../core/RenderTarget.js'; 4 | 5 | import type { OGLRenderingContext } from '../core/Renderer.js'; 6 | import type { Transform } from '../core/Transform.js'; 7 | import type { Mesh } from '../core/Mesh.js'; 8 | 9 | export interface ShadowOptions { 10 | light: Camera; 11 | width: number; 12 | height: number; 13 | } 14 | 15 | /** 16 | * Shadow map. 17 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Shadow.js | Source} 18 | */ 19 | export class Shadow { 20 | gl: OGLRenderingContext; 21 | 22 | light: Camera; 23 | 24 | target: RenderTarget; 25 | targetUniform: { value: RenderTarget['texture'] | null }; 26 | 27 | depthProgram: Program; 28 | 29 | castMeshes: Mesh[]; 30 | 31 | constructor(gl: OGLRenderingContext, options?: Partial); 32 | 33 | add(options: { 34 | mesh: Mesh; 35 | receive?: boolean; 36 | cast?: boolean; 37 | vertex?: string; 38 | fragment?: string; 39 | uniformProjection?: string; 40 | uniformView?: string; 41 | uniformTexture?: string; 42 | }): void; 43 | 44 | setSize(options: { width?: number; height?: number }): void; 45 | 46 | render(options: { scene: Transform }): void; 47 | } 48 | -------------------------------------------------------------------------------- /types/extras/Skin.d.ts: -------------------------------------------------------------------------------- 1 | import { Mesh } from '../core/Mesh.js'; 2 | import { Transform } from '../core/Transform.js'; 3 | import { Mat4 } from '../math/Mat4.js'; 4 | import { Texture } from '../core/Texture.js'; 5 | import { Animation } from './Animation.js'; 6 | 7 | import type { OGLRenderingContext } from '../core/Renderer.js'; 8 | import type { Quat } from '../math/Quat.js'; 9 | import type { Vec3 } from '../math/Vec3.js'; 10 | import type { Geometry } from '../core/Geometry.js'; 11 | import type { Program } from '../core/Program.js'; 12 | import type { Camera } from '../core/Camera.js'; 13 | 14 | export interface SkinRig { 15 | bindPose: { position: Vec3; quaternion: Quat; scale: Vec3 }; 16 | bones: { name: string; parent: Transform }[]; 17 | } 18 | 19 | export interface SkinOptions { 20 | rig: SkinRig; 21 | geometry: Geometry; 22 | program: Program; 23 | mode: GLenum; 24 | } 25 | 26 | export interface BoneTransform extends Transform { 27 | name: string; 28 | bindInverse: Mat4; 29 | } 30 | 31 | /** 32 | * A mesh with a skeleton and bones for animation. 33 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Skin.js | Source} 34 | */ 35 | export class Skin extends Mesh { 36 | root: Transform; 37 | 38 | bones: Transform[]; 39 | 40 | boneMatrices: Float32Array; 41 | boneTextureSize: number; 42 | boneTexture: Texture; 43 | animations: Animation[]; 44 | 45 | constructor(gl: OGLRenderingContext, options?: Partial); 46 | 47 | createBones(rig: SkinRig): void; 48 | 49 | createBoneTexture(): void; 50 | 51 | addAnimation(data: Animation['data']): Animation; 52 | 53 | update(): void; 54 | 55 | override draw(options?: { camera?: Camera }): void; 56 | } 57 | -------------------------------------------------------------------------------- /types/extras/Sphere.d.ts: -------------------------------------------------------------------------------- 1 | import { Geometry } from '../core/Geometry.js'; 2 | 3 | import type { OGLRenderingContext } from '../core/Renderer.js'; 4 | import type { AttributeMap } from '../core/Geometry.js'; 5 | 6 | export interface SphereOptions { 7 | radius: number; 8 | widthSegments: number; 9 | heightSegments: number; 10 | phiStart: number; 11 | phiLength: number; 12 | thetaStart: number; 13 | thetaLength: number; 14 | attributes: AttributeMap; 15 | } 16 | 17 | /** 18 | * A sphere geometry. 19 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Sphere.js | Source} 20 | */ 21 | export class Sphere extends Geometry { 22 | constructor(gl: OGLRenderingContext, options?: Partial); 23 | } 24 | -------------------------------------------------------------------------------- /types/extras/Text.d.ts: -------------------------------------------------------------------------------- 1 | export type TextAlign = 'left' | 'right' | 'center'; 2 | 3 | export interface TextOptions { 4 | font: object; 5 | text: string; 6 | width: number; 7 | align: TextAlign; 8 | size: number; 9 | letterSpacing: number; 10 | lineHeight: number; 11 | wordSpacing: number; 12 | wordBreak: boolean; 13 | } 14 | 15 | /** 16 | * A text geometry. 17 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Text.js | Source} 18 | */ 19 | export class Text { 20 | buffers: { 21 | position: Float32Array; 22 | uv: Float32Array; 23 | id: Float32Array; 24 | index: Uint32Array | Uint16Array; 25 | }; 26 | numLines: number; 27 | height: number; 28 | width: number; 29 | 30 | constructor(options?: Partial); 31 | 32 | resize(options: { width: number }): void; 33 | 34 | update(options: { text: string }): void; 35 | } 36 | -------------------------------------------------------------------------------- /types/extras/Texture3D.d.ts: -------------------------------------------------------------------------------- 1 | import { Texture } from '../core/Texture.js'; 2 | 3 | import type { OGLRenderingContext } from '../core/Renderer.js'; 4 | import type { TextureOptions } from '../core/Texture.js'; 5 | 6 | export interface Texture3DOptions extends TextureOptions { 7 | src: string; 8 | tileCountX: number; 9 | } 10 | 11 | /** 12 | * A class for rearranging a flat 3D texture from software like Houdini. 13 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Texture3D.js | Source} 14 | */ 15 | export class Texture3D extends Texture { 16 | constructor(gl: OGLRenderingContext, options?: Partial); 17 | } 18 | -------------------------------------------------------------------------------- /types/extras/TextureLoader.d.ts: -------------------------------------------------------------------------------- 1 | import { Texture } from '../core/Texture.js'; 2 | 3 | import type { OGLRenderingContext } from '../core/Renderer.js'; 4 | 5 | /** 6 | * The texture loader. 7 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/TextureLoader.js | Source} 8 | */ 9 | export class TextureLoader { 10 | static load(gl: OGLRenderingContext, options?: object): Texture; 11 | 12 | static getSupportedExtensions(gl: OGLRenderingContext): string[]; 13 | 14 | static loadKTX(src: string, texture: Texture): Promise; 15 | 16 | static loadImage(gl: OGLRenderingContext, src: string, texture: Texture, flipY: boolean): Promise; 17 | 18 | static clearCache(): void; 19 | } 20 | -------------------------------------------------------------------------------- /types/extras/Torus.d.ts: -------------------------------------------------------------------------------- 1 | import { Geometry } from '../core/Geometry.js'; 2 | 3 | import type { OGLRenderingContext } from '../core/Renderer.js'; 4 | import type { AttributeMap } from '../core/Geometry.js'; 5 | 6 | export interface TorusOptions { 7 | radius: number; 8 | tube: number; 9 | radialSegments: number; 10 | tubularSegments: number; 11 | arc: number; 12 | attributes: AttributeMap; 13 | } 14 | 15 | /** 16 | * A torus geometry. 17 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Torus.js | Source} 18 | */ 19 | export class Torus extends Geometry { 20 | constructor(gl: OGLRenderingContext, options?: Partial); 21 | } 22 | -------------------------------------------------------------------------------- /types/extras/Triangle.d.ts: -------------------------------------------------------------------------------- 1 | import { Geometry } from '../core/Geometry.js'; 2 | 3 | /** 4 | * A triangle geometry. 5 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Triangle.js | Source} 6 | */ 7 | export class Triangle extends Geometry {} 8 | -------------------------------------------------------------------------------- /types/extras/Tube.d.ts: -------------------------------------------------------------------------------- 1 | import { Geometry } from '../core/Geometry.js'; 2 | 3 | import type { OGLRenderingContext } from '../core/Renderer.js'; 4 | import type { AttributeMap } from '../core/Geometry.js'; 5 | import type { Path } from './path/Path.js'; 6 | 7 | export interface TubeOptions { 8 | path: Path; 9 | radius: number; 10 | tubularSegments: number; 11 | radialSegments: number; 12 | closed: boolean; 13 | attributes: AttributeMap; 14 | } 15 | 16 | /** 17 | * A tube geometry. 18 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Tube.js | Source} 19 | */ 20 | export class Tube extends Geometry { 21 | path: Path; 22 | radius: number; 23 | tubularSegments: number; 24 | radialSegments: number; 25 | closed: boolean; 26 | 27 | frenetFrames: object; 28 | 29 | positions: Float32Array; 30 | normals: Float32Array; 31 | uvs: Float32Array; 32 | indices: Uint32Array | Uint16Array; 33 | 34 | constructor(gl: OGLRenderingContext, options?: Partial); 35 | } 36 | -------------------------------------------------------------------------------- /types/extras/WireMesh.d.ts: -------------------------------------------------------------------------------- 1 | import { Mesh } from '../core/Mesh.js'; 2 | 3 | import type { OGLRenderingContext } from '../core/Renderer.js'; 4 | import type { Color } from '../math/Color.js'; 5 | import type { MeshOptions } from '../core/Mesh.js'; 6 | 7 | export interface WireMeshOptions extends MeshOptions { 8 | wireColor: Color; 9 | } 10 | 11 | /** 12 | * A wireframe mesh. 13 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/WireMesh.js | Source} 14 | */ 15 | export class WireMesh extends Mesh { 16 | constructor(gl: OGLRenderingContext, options?: Partial); 17 | } 18 | -------------------------------------------------------------------------------- /types/extras/helpers/AxesHelper.d.ts: -------------------------------------------------------------------------------- 1 | import { Mesh } from '../../core/Mesh.js'; 2 | 3 | import type { OGLRenderingContext } from '../../core/Renderer.js'; 4 | import type { Color } from '../../math/Color.js'; 5 | 6 | export interface AxesHelperOptions { 7 | size: number; 8 | symmetric: boolean; 9 | xColor: Color; 10 | yColor: Color; 11 | zColor: Color; 12 | } 13 | 14 | /** 15 | * Axes helper. 16 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/helpers/AxesHelper.js | Source} 17 | */ 18 | export class AxesHelper extends Mesh { 19 | constructor(gl: OGLRenderingContext, options?: Partial); 20 | } 21 | -------------------------------------------------------------------------------- /types/extras/helpers/FaceNormalsHelper.d.ts: -------------------------------------------------------------------------------- 1 | import { Mesh } from '../../core/Mesh.js'; 2 | 3 | import type { Color } from '../../math/Color.js'; 4 | 5 | export interface FaceNormalsHelperOptions { 6 | size: number; 7 | color: Color; 8 | } 9 | 10 | /** 11 | * Face normals helper. 12 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/helpers/FaceNormalsHelper.js | Source} 13 | */ 14 | export class FaceNormalsHelper extends Mesh { 15 | constructor(object: Mesh, options?: Partial); 16 | } 17 | -------------------------------------------------------------------------------- /types/extras/helpers/GridHelper.d.ts: -------------------------------------------------------------------------------- 1 | import { Mesh } from '../../core/Mesh.js'; 2 | 3 | import type { OGLRenderingContext } from '../../core/Renderer.js'; 4 | import type { Color } from '../../math/Color.js'; 5 | 6 | export interface GridHelperOptions { 7 | size: number; 8 | divisions: number; 9 | color: Color; 10 | } 11 | 12 | /** 13 | * Grid helper. 14 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/helpers/GridHelper.js | Source} 15 | */ 16 | export class GridHelper extends Mesh { 17 | constructor(gl: OGLRenderingContext, options?: Partial); 18 | } 19 | -------------------------------------------------------------------------------- /types/extras/helpers/VertexNormalsHelper.d.ts: -------------------------------------------------------------------------------- 1 | import { Mesh } from '../../core/Mesh.js'; 2 | 3 | import type { Color } from '../../math/Color.js'; 4 | 5 | export interface VertexNormalsHelperOptions { 6 | size: number; 7 | color: Color; 8 | } 9 | 10 | /** 11 | * Vertex normals helper. 12 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/helpers/VertexNormalsHelper.js | Source} 13 | */ 14 | export class VertexNormalsHelper extends Mesh { 15 | constructor(object: Mesh, options?: Partial); 16 | } 17 | -------------------------------------------------------------------------------- /types/extras/path/BaseSegment.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Abstract base class for path segments. 3 | * This class contains common methods for all segments types. 4 | */ 5 | export default class BaseSegment {} 6 | -------------------------------------------------------------------------------- /types/extras/path/CubicBezierSegment.d.ts: -------------------------------------------------------------------------------- 1 | import BaseSegment from './BaseSegment.js'; 2 | 3 | export default class CubicBezierSegment extends BaseSegment {} 4 | -------------------------------------------------------------------------------- /types/extras/path/LineSegment.d.ts: -------------------------------------------------------------------------------- 1 | import BaseSegment from './BaseSegment.js'; 2 | 3 | export default class LineSegment extends BaseSegment {} 4 | -------------------------------------------------------------------------------- /types/extras/path/Path.d.ts: -------------------------------------------------------------------------------- 1 | import { Vec3 } from '../../math/Vec3.js'; 2 | 3 | /** 4 | * Path builder. 5 | * @see {@link https://github.com/oframe/ogl/blob/master/src/extras/path/Path.js | Source} 6 | */ 7 | export class Path { 8 | tiltFunction: Function | null; 9 | 10 | constructor(); 11 | 12 | moveTo(p: Vec3, tilt?: number): void; 13 | 14 | bezierCurveTo(cp1: Vec3, cp2: Vec3, p: Vec3, tilt?: number): this; 15 | 16 | quadraticCurveTo(cp: Vec3, p: Vec3, tilt?: number): this; 17 | 18 | lineTo(p: Vec3, tilt?: number): this; 19 | 20 | addSegment(segment: object): this; 21 | 22 | getSegments(): object[]; 23 | 24 | updateLength(): void; 25 | 26 | getLength(): number; 27 | 28 | findSegmentIndexAtLength(len: number): [number, number]; 29 | 30 | getPointAtLength(len: number, out?: Vec3): Vec3; 31 | 32 | getPointAt(t: number, out?: Vec3): Vec3; 33 | 34 | getTangentAtLength(len: number, out?: Vec3): number; 35 | 36 | getTangentAt(t: number, out?: Vec3): number; 37 | 38 | getTiltAtLength(len: number): number; 39 | 40 | getTiltAt(t: number): number; 41 | 42 | getPoints(divisions?: number): Vec3[]; 43 | 44 | computeFrenetFrames(divisions?: number, closed?: boolean): { tangents: Vec3[]; normals: Vec3[]; binormals: Vec3[] }; 45 | } 46 | -------------------------------------------------------------------------------- /types/extras/path/QuadraticBezierSegment.d.ts: -------------------------------------------------------------------------------- 1 | import BaseSegment from './BaseSegment.js'; 2 | 3 | export default class QuadraticBezierSegment extends BaseSegment {} 4 | -------------------------------------------------------------------------------- /types/index.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for ogl 1.0.0 2 | // Project: https://github.com/oframe/ogl 3 | // Definitions by: Xin Chen 4 | // Cody Bennett 5 | // Patrick Schroen 6 | // Definitions: https://github.com/oframe/ogl 7 | 8 | // Core 9 | export * from './core/Geometry'; 10 | export * from './core/Program'; 11 | export * from './core/Renderer'; 12 | export * from './core/Camera'; 13 | export * from './core/Transform'; 14 | export * from './core/Mesh'; 15 | export * from './core/Texture'; 16 | export * from './core/RenderTarget'; 17 | 18 | // Maths 19 | export * from './math/Color'; 20 | export * from './math/Euler'; 21 | export * from './math/Mat3'; 22 | export * from './math/Mat4'; 23 | export * from './math/Quat'; 24 | export * from './math/Vec2'; 25 | export * from './math/Vec3'; 26 | export * from './math/Vec4'; 27 | 28 | // Extras 29 | export * from './extras/Plane'; 30 | export * from './extras/Box'; 31 | export * from './extras/Sphere'; 32 | export * from './extras/Cylinder'; 33 | export * from './extras/Triangle'; 34 | export * from './extras/Torus'; 35 | export * from './extras/Orbit'; 36 | export * from './extras/Raycast'; 37 | export * from './extras/Curve'; 38 | export * from './extras/path/Path'; 39 | export * from './extras/Tube'; 40 | export * from './extras/Post'; 41 | export * from './extras/Skin'; 42 | export * from './extras/Animation'; 43 | export * from './extras/Text'; 44 | export * from './extras/NormalProgram'; 45 | export * from './extras/Flowmap'; 46 | export * from './extras/GPGPU'; 47 | export * from './extras/Polyline'; 48 | export * from './extras/Shadow'; 49 | export * from './extras/KTXTexture'; 50 | export * from './extras/TextureLoader'; 51 | export * from './extras/GLTFLoader'; 52 | export * from './extras/GLTFSkin'; 53 | export * from './extras/GLTFAnimation'; 54 | export * from './extras/DracoManager'; 55 | export * from './extras/BasisManager'; 56 | export * from './extras/WireMesh'; 57 | export * from './extras/helpers/AxesHelper'; 58 | export * from './extras/helpers/GridHelper'; 59 | export * from './extras/helpers/VertexNormalsHelper'; 60 | export * from './extras/helpers/FaceNormalsHelper'; 61 | export * from './extras/InstancedMesh'; 62 | export * from './extras/Texture3D.js'; 63 | -------------------------------------------------------------------------------- /types/math/Color.d.ts: -------------------------------------------------------------------------------- 1 | export type ColorTuple = [r: number, g: number, b: number]; 2 | 3 | export type ColorRepresentation = 4 | | ColorTuple 5 | | Color 6 | | 'black' 7 | | 'white' 8 | | 'red' 9 | | 'green' 10 | | 'blue' 11 | | 'fuchsia' 12 | | 'cyan' 13 | | 'yellow' 14 | | 'orange' 15 | | string 16 | | number; 17 | 18 | /** 19 | * Represents a color. 20 | * @see {@link https://github.com/oframe/ogl/blob/master/src/math/Color.js | Source} 21 | */ 22 | export class Color extends Array { 23 | constructor(color?: ColorRepresentation, g?: number, b?: number); 24 | 25 | get r(): number; 26 | 27 | get g(): number; 28 | 29 | get b(): number; 30 | 31 | set r(v: number); 32 | 33 | set g(v: number); 34 | 35 | set b(v: number); 36 | 37 | set(color?: ColorRepresentation, g?: number, b?: number): this; 38 | 39 | copy(v: Color): this; 40 | } 41 | -------------------------------------------------------------------------------- /types/math/Euler.d.ts: -------------------------------------------------------------------------------- 1 | import { Mat4 } from './Mat4.js'; 2 | 3 | import type { Quat } from './Quat.js'; 4 | import type { AttributeData } from '../core/Geometry.js'; 5 | 6 | export type EulerTuple = [x: number, y: number, z: number]; 7 | 8 | export type EulerOrder = 'XYZ' | 'XZY' | 'YXZ' | 'YZX' | 'ZXY' | 'ZYX'; 9 | 10 | /** 11 | * Implementation of {@link https://en.wikipedia.org/wiki/Euler_angles | Euler angles}. 12 | * @see {@link https://github.com/oframe/ogl/blob/master/src/math/Euler.js | Source} 13 | */ 14 | export class Euler extends Array { 15 | order: EulerOrder; 16 | onChange: () => void; 17 | 18 | constructor(x?: number, y?: number, z?: number, order?: EulerOrder); 19 | 20 | get x(): number; 21 | 22 | get y(): number; 23 | 24 | get z(): number; 25 | 26 | set x(v: number); 27 | 28 | set y(v: number); 29 | 30 | set z(v: number); 31 | 32 | set(x: number | Euler | EulerTuple, y?: number, z?: number): this; 33 | 34 | copy(v: Euler): this; 35 | 36 | reorder(order: EulerOrder): this; 37 | 38 | fromRotationMatrix(m: Mat4, order?: EulerOrder): this; 39 | 40 | fromQuaternion(q: Quat, order?: EulerOrder): this; 41 | 42 | fromArray(a: number[] | AttributeData, o?: number): this; 43 | 44 | toArray(a?: T, o?: number): T; 45 | } 46 | -------------------------------------------------------------------------------- /types/math/Mat3.d.ts: -------------------------------------------------------------------------------- 1 | import type { Mat4 } from './Mat4.js'; 2 | import type { Quat } from './Quat.js'; 3 | import type { Vec2 } from './Vec2.js'; 4 | import type { Vec3 } from './Vec3.js'; 5 | 6 | export type Mat3Tuple = [ 7 | m00: number, 8 | m01: number, 9 | m02: number, 10 | m10: number, 11 | m11: number, 12 | m12: number, 13 | m20: number, 14 | m21: number, 15 | m22: number, 16 | ]; 17 | 18 | /** 19 | * 3x3 matrix. 20 | * @see {@link https://github.com/oframe/ogl/blob/master/src/math/Mat3.js | Source} 21 | */ 22 | export class Mat3 extends Array { 23 | constructor( 24 | m00?: number, 25 | m01?: number, 26 | m02?: number, 27 | m10?: number, 28 | m11?: number, 29 | m12?: number, 30 | m20?: number, 31 | m21?: number, 32 | m22?: number, 33 | ); 34 | 35 | set( 36 | m00: number | Mat3 | Mat3Tuple, 37 | m01: number, 38 | m02: number, 39 | m10: number, 40 | m11: number, 41 | m12: number, 42 | m20: number, 43 | m21: number, 44 | m22: number, 45 | ): this; 46 | 47 | translate(v: Vec2, m?: Mat3): this; 48 | 49 | rotate(v: number, m?: Mat3): this; 50 | 51 | scale(v: Vec2, m?: Mat3): this; 52 | 53 | multiply(ma: Mat3, mb?: Mat3): this; 54 | 55 | identity(): this; 56 | 57 | copy(m: Mat3): this; 58 | 59 | fromMatrix4(m: Mat4): this; 60 | 61 | fromQuaternion(q: Quat): this; 62 | 63 | fromBasis(vec3a: Vec3, vec3b: Vec3, vec3c: Vec3): this; 64 | 65 | inverse(m?: Mat3): this; 66 | 67 | getNormalMatrix(m: Mat4): this; 68 | } 69 | -------------------------------------------------------------------------------- /types/math/Mat4.d.ts: -------------------------------------------------------------------------------- 1 | import type { Quat } from './Quat.js'; 2 | import type { Vec3 } from './Vec3.js'; 3 | import type { AttributeData } from '../core/Geometry.js'; 4 | 5 | export type Mat4Tuple = [ 6 | m00: number, 7 | m01: number, 8 | m02: number, 9 | m03: number, 10 | m10: number, 11 | m11: number, 12 | m12: number, 13 | m13: number, 14 | m20: number, 15 | m21: number, 16 | m22: number, 17 | m23: number, 18 | m30: number, 19 | m31: number, 20 | m32: number, 21 | m33: number, 22 | ]; 23 | 24 | /** 25 | * 4x4 matrix. 26 | * @see {@link https://github.com/oframe/ogl/blob/master/src/math/Mat4.js | Source} 27 | */ 28 | export class Mat4 extends Array { 29 | constructor( 30 | m00?: number, 31 | m01?: number, 32 | m02?: number, 33 | m03?: number, 34 | m10?: number, 35 | m11?: number, 36 | m12?: number, 37 | m13?: number, 38 | m20?: number, 39 | m21?: number, 40 | m22?: number, 41 | m23?: number, 42 | m30?: number, 43 | m31?: number, 44 | m32?: number, 45 | m33?: number, 46 | ); 47 | 48 | get x(): number; 49 | 50 | get y(): number; 51 | 52 | get z(): number; 53 | 54 | get w(): number; 55 | 56 | set x(v: number); 57 | 58 | set y(v: number); 59 | 60 | set z(v: number); 61 | 62 | set w(v: number); 63 | 64 | set( 65 | m00: number | Mat4 | Mat4Tuple, 66 | m01: number, 67 | m02: number, 68 | m03: number, 69 | m10: number, 70 | m11: number, 71 | m12: number, 72 | m13: number, 73 | m20: number, 74 | m21: number, 75 | m22: number, 76 | m23: number, 77 | m30: number, 78 | m31: number, 79 | m32: number, 80 | m33: number, 81 | ): this; 82 | 83 | translate(v: Vec3, m?: Mat4): this; 84 | 85 | rotate(v: number, axis: Vec3, m?: Mat4): this; 86 | 87 | scale(v: Vec3 | number, m?: Mat4): this; 88 | 89 | add(ma: Mat4, mb?: Mat4): this; 90 | 91 | sub(ma: Mat4, mb?: Mat4): this; 92 | 93 | multiply(ma: Mat4 | number, mb?: Mat4): this; 94 | 95 | identity(): this; 96 | 97 | copy(m: Mat4): this; 98 | 99 | fromPerspective(options: { fov: number; aspect: number; near: number; far: number }): this; 100 | 101 | fromOrthogonal(options: { left: number; right: number; bottom: number; top: number; near: number; far: number }): this; 102 | 103 | fromQuaternion(q: Quat): this; 104 | 105 | setPosition(v: Vec3): this; 106 | 107 | inverse(m?: Mat4): this; 108 | 109 | compose(q: Quat, pos: Vec3, scale: Vec3): this; 110 | 111 | getRotation(q: Quat): this; 112 | 113 | getTranslation(pos: Vec3): this; 114 | 115 | getScaling(scale: Vec3): this; 116 | 117 | getMaxScaleOnAxis(): number; 118 | 119 | lookAt(eye: Vec3, target: Vec3, up: Vec3): this; 120 | 121 | determinant(): number; 122 | 123 | fromArray(a: number[] | AttributeData, o?: number): this; 124 | 125 | toArray(a?: T, o?: number): T; 126 | } 127 | -------------------------------------------------------------------------------- /types/math/Quat.d.ts: -------------------------------------------------------------------------------- 1 | import type { Euler } from './Euler.js'; 2 | import type { Mat3 } from './Mat3.js'; 3 | import type { Vec3 } from './Vec3.js'; 4 | import type { AttributeData } from '../core/Geometry.js'; 5 | 6 | export type QuatTuple = [x: number, y: number, z: number, w: number]; 7 | 8 | /** 9 | * Implementation of a quaternion. 10 | * @see {@link https://github.com/oframe/ogl/blob/master/src/math/Quat.js | Source} 11 | */ 12 | export class Quat extends Array { 13 | onChange: () => void; 14 | 15 | constructor(x?: number, y?: number, z?: number, w?: number); 16 | 17 | get x(): number; 18 | 19 | get y(): number; 20 | 21 | get z(): number; 22 | 23 | get w(): number; 24 | 25 | set x(v: number); 26 | 27 | set y(v: number); 28 | 29 | set z(v: number); 30 | 31 | set w(v: number); 32 | 33 | identity(): this; 34 | 35 | set(x: number | Quat | QuatTuple, y: number, z: number, w: number): this; 36 | 37 | rotateX(a: number): this; 38 | 39 | rotateY(a: number): this; 40 | 41 | rotateZ(a: number): this; 42 | 43 | inverse(q?: Quat): this; 44 | 45 | conjugate(q?: Quat): this; 46 | 47 | copy(q: Quat): this; 48 | 49 | normalize(q?: Quat): this; 50 | 51 | multiply(qA: Quat, qB?: Quat): this; 52 | 53 | dot(v: Quat): number; 54 | 55 | fromMatrix3(matrix3: Mat3): this; 56 | 57 | fromEuler(euler: Euler): this; 58 | 59 | fromAxisAngle(axis: Vec3, a: number): this; 60 | 61 | slerp(q: Quat, t: number): this; 62 | 63 | fromArray(a: number[] | AttributeData, o?: number): this; 64 | 65 | toArray(a?: T, o?: number): T; 66 | } 67 | -------------------------------------------------------------------------------- /types/math/Vec2.d.ts: -------------------------------------------------------------------------------- 1 | import type { Mat3 } from './Mat3.js'; 2 | import type { Mat4 } from './Mat4.js'; 3 | import type { AttributeData } from '../core/Geometry.js'; 4 | 5 | export type Vec2Tuple = [x: number, y: number]; 6 | 7 | /** 8 | * 2D vector. 9 | * @see {@link https://github.com/oframe/ogl/blob/master/src/math/Vec2.js | Source} 10 | */ 11 | export class Vec2 extends Array { 12 | constructor(x?: number, y?: number); 13 | 14 | get x(): number; 15 | 16 | get y(): number; 17 | 18 | set x(v: number); 19 | 20 | set y(v: number); 21 | 22 | set(x: number | Vec2 | Vec2Tuple, y?: number): this; 23 | 24 | copy(v: Vec2): this; 25 | 26 | add(va: Vec2, vb?: Vec2): this; 27 | 28 | sub(va: Vec2, vb?: Vec2): this; 29 | 30 | multiply(v: Vec2 | number): this; 31 | 32 | divide(v: Vec2 | number): this; 33 | 34 | inverse(v?: Vec2): this; 35 | 36 | len(): number; 37 | 38 | distance(v?: Vec2): number; 39 | 40 | squaredLen(): number; 41 | 42 | squaredDistance(v?: Vec2): number; 43 | 44 | negate(v?: Vec2): this; 45 | 46 | cross(va: Vec2, vb?: Vec2): number; 47 | 48 | scale(v: number): this; 49 | 50 | normalize(): this; 51 | 52 | dot(v: Vec2): number; 53 | 54 | equals(v: Vec2): boolean; 55 | 56 | applyMatrix3(mat3: Mat3): this; 57 | 58 | applyMatrix4(mat4: Mat4): this; 59 | 60 | lerp(v: Vec2, a: number): this; 61 | 62 | smoothLerp(v: Vec2, decay: number, dt: number): this; 63 | 64 | clone(): Vec2; 65 | 66 | fromArray(a: number[] | AttributeData, o?: number): this; 67 | 68 | toArray(a?: T, o?: number): T; 69 | } 70 | -------------------------------------------------------------------------------- /types/math/Vec3.d.ts: -------------------------------------------------------------------------------- 1 | import type { Mat3 } from './Mat3.js'; 2 | import type { Mat4 } from './Mat4.js'; 3 | import type { Quat } from './Quat.js'; 4 | import type { AttributeData } from '../core/Geometry.js'; 5 | 6 | export type Vec3Tuple = [x: number, y: number, z: number]; 7 | 8 | /** 9 | * 3D vector. 10 | * @see {@link https://github.com/oframe/ogl/blob/master/src/math/Vec3.js | Source} 11 | */ 12 | export class Vec3 extends Array { 13 | constructor(x?: number, y?: number, z?: number); 14 | 15 | get x(): number; 16 | 17 | get y(): number; 18 | 19 | get z(): number; 20 | 21 | set x(v: number); 22 | 23 | set y(v: number); 24 | 25 | set z(v: number); 26 | 27 | set(x: number | Vec3 | Vec3Tuple, y?: number, z?: number): this; 28 | 29 | copy(v: Vec3): this; 30 | 31 | add(va: Vec3, vb?: Vec3): this; 32 | 33 | sub(va: Vec3, vb?: Vec3): this; 34 | 35 | multiply(v: Vec3 | number): this; 36 | 37 | divide(v: Vec3 | number): this; 38 | 39 | inverse(v?: Vec3): this; 40 | 41 | len(): number; 42 | 43 | distance(v?: Vec3): number; 44 | 45 | squaredLen(): number; 46 | 47 | squaredDistance(v?: Vec3): number; 48 | 49 | negate(v?: Vec3): this; 50 | 51 | cross(va: Vec3, vb?: Vec3): this; 52 | 53 | scale(v: number): this; 54 | 55 | normalize(): this; 56 | 57 | dot(v: Vec3): number; 58 | 59 | equals(v: Vec3): boolean; 60 | 61 | applyMatrix3(mat3: Mat3): this; 62 | 63 | applyMatrix4(mat4: Mat4): this; 64 | 65 | scaleRotateMatrix4(mat4: Mat4): this; 66 | 67 | applyQuaternion(q: Quat): this; 68 | 69 | angle(v: Vec3): number; 70 | 71 | lerp(v: Vec3, t: number): this; 72 | 73 | smoothLerp(v: Vec3, decay: number, dt: number): this; 74 | 75 | clone(): Vec3; 76 | 77 | fromArray(a: number[] | AttributeData, o?: number): this; 78 | 79 | toArray(a?: T, o?: number): T; 80 | 81 | transformDirection(mat4: Mat4): this; 82 | } 83 | -------------------------------------------------------------------------------- /types/math/Vec4.d.ts: -------------------------------------------------------------------------------- 1 | import type { AttributeData } from '../core/Geometry'; 2 | 3 | export type Vec4Tuple = [x: number, y: number, z: number, w: number]; 4 | 5 | /** 6 | * 4D vector. 7 | * @see {@link https://github.com/oframe/ogl/blob/master/src/math/Vec4.js | Source} 8 | */ 9 | export class Vec4 extends Array { 10 | constructor(x?: number, y?: number, z?: number, w?: number); 11 | 12 | get x(): number; 13 | 14 | get y(): number; 15 | 16 | get z(): number; 17 | 18 | get w(): number; 19 | 20 | set x(v: number); 21 | 22 | set y(v: number); 23 | 24 | set z(v: number); 25 | 26 | set w(v: number); 27 | 28 | set(x: number | Vec4 | Vec4Tuple, y?: number, z?: number, w?: number): this; 29 | 30 | copy(v: Vec4): this; 31 | 32 | normalize(): this; 33 | 34 | multiply(v: number): this; 35 | 36 | dot(v: Vec4): number; 37 | 38 | fromArray(a: number[] | AttributeData, o?: number): this; 39 | 40 | toArray(a?: T, o?: number): T; 41 | } 42 | --------------------------------------------------------------------------------