├── .eslintignore ├── .eslintrc ├── .gitignore ├── .prettierignore ├── .prettierrc ├── CHANGELOG.md ├── dist ├── @types │ ├── camera │ │ ├── camera-controller.d.ts │ │ ├── orthographic-camera.d.ts │ │ └── perspective-camera.d.ts │ ├── core │ │ ├── cube-texture.d.ts │ │ ├── framebuffer.d.ts │ │ ├── geometry.d.ts │ │ ├── instanced-mesh.d.ts │ │ ├── mesh.d.ts │ │ ├── program.d.ts │ │ ├── scene-object.d.ts │ │ ├── texture.d.ts │ │ └── transform.d.ts │ ├── extra │ │ └── swap-renderer.d.ts │ ├── geometry-utils │ │ ├── build-plane.d.ts │ │ ├── create-box-separate-faces.d.ts │ │ ├── create-box.d.ts │ │ ├── create-circle.d.ts │ │ ├── create-plane.d.ts │ │ ├── create-rounded-box-separate-faces.d.ts │ │ ├── create-rounded-box.d.ts │ │ ├── create-sphere.d.ts │ │ ├── create-torus.d.ts │ │ └── index.d.ts │ ├── index.d.ts │ └── utils │ │ ├── gl-constants.d.ts │ │ ├── gl-utils.d.ts │ │ ├── math.d.ts │ │ └── shader-snippets.d.ts ├── cjs │ ├── index.js │ └── index.js.map └── esm │ ├── index.js │ └── index.js.map ├── docs ├── README.md ├── docs │ ├── assets │ │ ├── css │ │ │ └── main.css │ │ ├── images │ │ │ ├── icons.png │ │ │ ├── icons@2x.png │ │ │ ├── widgets.png │ │ │ └── widgets@2x.png │ │ └── js │ │ │ ├── main.js │ │ │ └── search.js │ ├── classes │ │ ├── camera_camera_controller.cameracontroller.html │ │ ├── camera_orthographic_camera.orthographiccamera.html │ │ ├── camera_perspective_camera.perspectivecamera.html │ │ ├── core_cube_texture.cubetexture.html │ │ ├── core_framebuffer.framebuffer.html │ │ ├── core_geometry.geometry.html │ │ ├── core_instanced_mesh.instancedmesh.html │ │ ├── core_mesh.mesh.html │ │ ├── core_program.program.html │ │ ├── core_scene_object.sceneobject.html │ │ ├── core_texture.texture.html │ │ ├── core_transform.transform.html │ │ ├── extra_swap_renderer.swaprenderer.html │ │ └── geometry_utils_create_rounded_box.vrot90.html │ ├── index.html │ ├── interfaces │ │ ├── core_mesh.meshinterface.html │ │ ├── core_program.programinterface.html │ │ ├── core_texture.textureinterface.html │ │ ├── geometry_utils_create_box.box.html │ │ ├── geometry_utils_create_box_separate_faces.box.html │ │ └── geometry_utils_create_sphere.sphere.html │ ├── modules.html │ └── modules │ │ ├── camera_camera_controller.html │ │ ├── camera_orthographic_camera.html │ │ ├── camera_perspective_camera.html │ │ ├── core_cube_texture.html │ │ ├── core_framebuffer.html │ │ ├── core_geometry.html │ │ ├── core_instanced_mesh.html │ │ ├── core_mesh.html │ │ ├── core_program.html │ │ ├── core_scene_object.html │ │ ├── core_texture.html │ │ ├── core_transform.html │ │ ├── extra_swap_renderer.html │ │ ├── geometry_utils.html │ │ ├── geometry_utils_build_plane.html │ │ ├── geometry_utils_create_box.html │ │ ├── geometry_utils_create_box_separate_faces.html │ │ ├── geometry_utils_create_circle.html │ │ ├── geometry_utils_create_plane.html │ │ ├── geometry_utils_create_rounded_box.html │ │ ├── geometry_utils_create_rounded_box_separate_faces.html │ │ ├── geometry_utils_create_sphere.html │ │ ├── geometry_utils_create_torus.html │ │ ├── index.html │ │ ├── utils_gl_constants.html │ │ ├── utils_gl_utils.html │ │ ├── utils_math.html │ │ └── utils_shader_snippets.html ├── examples │ ├── EXAMPLES.json │ ├── assets │ │ ├── models │ │ │ ├── Suzanne.bin │ │ │ └── Suzanne.gltf │ │ └── textures │ │ │ ├── Suzanne_BaseColor.png │ │ │ ├── Suzanne_MetallicRoughness.png │ │ │ ├── UV_Grid_Sm.jpeg │ │ │ ├── UV_Grid_Sm.png │ │ │ ├── box.jpeg │ │ │ ├── debug_uv_01.png │ │ │ ├── hwoa-rang-gl-preview.png │ │ │ ├── social-preview-hwoa-rang-gl.png │ │ │ ├── texture04.jpeg │ │ │ ├── webgl-logo.png │ │ │ ├── zhang-kaiyv-44yxPSPmtjg-unsplash.png │ │ │ ├── zhang-kaiyv-G7oFLe-OW74-unsplash.jpeg │ │ │ ├── zhang-kaiyv-Jt5a-wTJR1Q-unsplash.jpeg │ │ │ ├── zhang-kaiyv-MheaLsLj1to-unsplash.jpeg │ │ │ ├── zhang-kaiyv-X9GKFnHy_WA-unsplash.jpeg │ │ │ └── zhang-kaiyv-mh2o8DuHaMM-unsplash.png │ ├── dist │ │ ├── assets │ │ │ ├── models │ │ │ │ ├── Suzanne.bin │ │ │ │ └── Suzanne.gltf │ │ │ └── textures │ │ │ │ ├── Suzanne_BaseColor.png │ │ │ │ ├── Suzanne_MetallicRoughness.png │ │ │ │ ├── UV_Grid_Sm.jpeg │ │ │ │ ├── UV_Grid_Sm.png │ │ │ │ ├── box.jpeg │ │ │ │ ├── debug_uv_01.png │ │ │ │ ├── hwoa-rang-gl-preview.png │ │ │ │ ├── social-preview-hwoa-rang-gl.png │ │ │ │ ├── texture04.jpeg │ │ │ │ ├── webgl-logo.png │ │ │ │ ├── zhang-kaiyv-44yxPSPmtjg-unsplash.png │ │ │ │ ├── zhang-kaiyv-G7oFLe-OW74-unsplash.jpeg │ │ │ │ ├── zhang-kaiyv-Jt5a-wTJR1Q-unsplash.jpeg │ │ │ │ ├── zhang-kaiyv-MheaLsLj1to-unsplash.jpeg │ │ │ │ ├── zhang-kaiyv-X9GKFnHy_WA-unsplash.jpeg │ │ │ │ └── zhang-kaiyv-mh2o8DuHaMM-unsplash.png │ │ ├── deferred-shading │ │ │ ├── index.html │ │ │ └── index.js │ │ ├── directional-light │ │ │ ├── index.html │ │ │ └── index.js │ │ ├── fog │ │ │ ├── index.html │ │ │ └── index.js │ │ ├── geometry │ │ │ ├── index.html │ │ │ └── index.js │ │ ├── gltf │ │ │ ├── index.html │ │ │ └── index.js │ │ ├── godrays │ │ │ ├── index.html │ │ │ └── index.js │ │ ├── gpgpu-particles │ │ │ ├── index.html │ │ │ └── index.js │ │ ├── index.html │ │ ├── index.js │ │ ├── instanced-geometry │ │ │ ├── index.html │ │ │ └── index.js │ │ ├── mouse-picking │ │ │ ├── index.html │ │ │ └── index.js │ │ ├── multi-texture │ │ │ ├── index.html │ │ │ └── index.js │ │ ├── particles-01 │ │ │ ├── index.html │ │ │ └── index.js │ │ ├── particles-02 │ │ │ ├── index.html │ │ │ └── index.js │ │ ├── persistence │ │ │ ├── index.html │ │ │ └── index.js │ │ ├── point-light │ │ │ ├── index.html │ │ │ └── index.js │ │ ├── projection-mapping │ │ │ ├── index.html │ │ │ └── index.js │ │ ├── shadow │ │ │ ├── index.html │ │ │ └── index.js │ │ ├── spot-light │ │ │ ├── index.html │ │ │ └── index.js │ │ ├── swaprenderer-fluid │ │ │ ├── index.html │ │ │ └── index.js │ │ ├── swaprenderer-image │ │ │ ├── index.html │ │ │ └── index.js │ │ ├── swaprenderer-noise-texture │ │ │ ├── index.html │ │ │ └── index.js │ │ ├── text │ │ │ ├── index.html │ │ │ └── index.js │ │ └── texture │ │ │ ├── index.html │ │ │ └── index.js │ ├── examples-src │ │ └── gpgpu-fluid │ │ │ ├── index.html │ │ │ └── index.js │ ├── index.html │ ├── index.js │ ├── package-lock.json │ ├── package.json │ ├── rollup.config.js │ └── src │ │ ├── deferred-shading │ │ ├── base.frag │ │ ├── base.vert │ │ ├── directional-lighting.frag │ │ ├── gbuffer.frag │ │ ├── gbuffer.vert │ │ ├── index.html │ │ ├── index.js │ │ └── point-lighting.frag │ │ ├── directional-light │ │ ├── index.html │ │ └── index.js │ │ ├── environment-map │ │ ├── index.html │ │ └── index.js │ │ ├── fog │ │ ├── GLTFLoader.js │ │ ├── index.html │ │ └── index.js │ │ ├── geometry │ │ ├── index.html │ │ └── index.js │ │ ├── gltf │ │ ├── GLTFLoader.js │ │ ├── index.html │ │ └── index.js │ │ ├── godrays │ │ ├── index.html │ │ └── index.js │ │ ├── gpgpu-fluid │ │ ├── index.html │ │ └── index.js │ │ ├── gpgpu-particles │ │ ├── index.html │ │ └── index.js │ │ ├── images │ │ ├── cubemap │ │ │ ├── negx.jpg │ │ │ ├── negy.jpg │ │ │ ├── negz.jpg │ │ │ ├── posx.jpg │ │ │ ├── posy.jpg │ │ │ └── posz.jpg │ │ ├── tekken2-cover.jpg │ │ ├── texture-example.jpg │ │ └── webgl-logo-pot.png │ │ ├── instanced-geometry │ │ ├── index.html │ │ └── index.js │ │ ├── mouse-picking │ │ ├── index.html │ │ └── index.js │ │ ├── multi-texture │ │ ├── index.html │ │ └── index.js │ │ ├── particles-01 │ │ ├── index.html │ │ └── index.js │ │ ├── particles-02 │ │ ├── index.html │ │ └── index.js │ │ ├── persistence │ │ ├── index.html │ │ └── index.js │ │ ├── point-light │ │ ├── index.html │ │ └── index.js │ │ ├── projection-mapping │ │ ├── index.html │ │ └── index.js │ │ ├── shadow │ │ ├── base.frag │ │ ├── base.vert │ │ ├── debug-depth.frag │ │ ├── index.html │ │ ├── index.js │ │ ├── shaded.frag │ │ └── shaded.vert │ │ ├── spot-light │ │ ├── index.html │ │ └── index.js │ │ ├── swaprenderer-fluid │ │ ├── add-force.frag │ │ ├── advect.frag │ │ ├── base.vert │ │ ├── clear.frag │ │ ├── curl.frag │ │ ├── cursor.vert │ │ ├── divergence.frag │ │ ├── index.html │ │ ├── index.js │ │ ├── jacobi.frag │ │ ├── subtract-pressure-gradient.frag │ │ ├── visualise.frag │ │ └── vorticity.frag │ │ ├── swaprenderer-image │ │ ├── index.html │ │ └── index.js │ │ ├── swaprenderer-noise-texture │ │ ├── index.html │ │ └── index.js │ │ ├── text │ │ ├── index.html │ │ └── index.js │ │ └── texture │ │ ├── index.html │ │ └── index.js └── index.html ├── package-lock.json ├── package.json ├── rollup.config.js ├── src ├── camera │ ├── camera-controller.ts │ ├── orthographic-camera.ts │ └── perspective-camera.ts ├── core │ ├── cube-texture.ts │ ├── framebuffer.ts │ ├── geometry.ts │ ├── instanced-mesh.ts │ ├── mesh.ts │ ├── program.ts │ ├── scene-object.ts │ ├── texture.ts │ └── transform.ts ├── extra │ └── swap-renderer.ts ├── geometry-utils │ ├── build-plane.ts │ ├── create-box-separate-faces.ts │ ├── create-box.ts │ ├── create-circle.ts │ ├── create-interleaved-plane.ts │ ├── create-plane.ts │ ├── create-rounded-box-separate-faces.ts │ ├── create-rounded-box.ts │ ├── create-sphere.ts │ ├── create-torus.ts │ └── index.ts ├── index.ts └── utils │ ├── gl-constants.js │ ├── gl-utils.ts │ ├── math.ts │ └── shader-snippets.js └── tsconfig.json /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "plugins": [ 5 | "@typescript-eslint", 6 | "eslint-plugin-tsdoc" 7 | ], 8 | "parserOptions": { 9 | "ecmaVersion": 2020 10 | }, 11 | "extends": [ 12 | "eslint:recommended", 13 | "plugin:@typescript-eslint/recommended" 14 | ], 15 | "env": { 16 | "browser": true 17 | }, 18 | "ignorePatterns": ["GLTFLoader.ts"] 19 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "trailingComma": "all", 4 | "singleQuote": true 5 | } 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [1.0.2] - 2021-06-25 9 | 10 | ### Added 11 | 12 | - Support for cube textures 13 | - Geometry: Delete attributes Map on delete() 14 | - Geometry: Implement updating of attributes 15 | - GeometryUtils: add rounded box geometry helpers 16 | 17 | ## [1.0.1] - 2021-06-24 18 | 19 | - export math helpers from library 20 | 21 | ## [1.0.0] - 2021-06-24 22 | 23 | - first release 24 | -------------------------------------------------------------------------------- /dist/@types/camera/camera-controller.d.ts: -------------------------------------------------------------------------------- 1 | import { PerspectiveCamera } from '../index'; 2 | export declare class CameraController { 3 | private camera; 4 | private domElement; 5 | private target; 6 | private minDistance; 7 | private maxDistance; 8 | private isEnabled; 9 | private isDamping; 10 | private dampingFactor; 11 | private isZoom; 12 | private zoomSpeed; 13 | private isRotate; 14 | private rotateSpeed; 15 | private isPan; 16 | private keyPanSpeed; 17 | private enableKeys; 18 | private keys; 19 | private originTarget; 20 | private originPosition; 21 | private targetXDampedAction; 22 | private targetYDampedAction; 23 | private targetZDampedAction; 24 | private targetThetaDampedAction; 25 | private targetPhiDampedAction; 26 | private targetRadiusDampedAction; 27 | private _isShiftDown; 28 | private _rotateStart; 29 | private _rotateEnd; 30 | private _roatteDelta; 31 | private _spherical; 32 | private _zoomDistanceEnd; 33 | private _zoomDistance; 34 | private state; 35 | private loopId; 36 | private _panStart; 37 | private _panDelta; 38 | private _panEnd; 39 | private _paused; 40 | private _isDebug; 41 | private _outputEl; 42 | private mouseWheelForce; 43 | constructor(camera: PerspectiveCamera, domElement?: HTMLElement, isDebug?: boolean, mouseWheelForce?: number); 44 | lookAt([x, y, z]: [any, any, any]): this; 45 | setEventHandler(): void; 46 | removeEventHandler(): void; 47 | startTick(): void; 48 | pause(): void; 49 | start(): void; 50 | tick(): void; 51 | updateDampedAction(): void; 52 | updateCamera(): void; 53 | _bindEvens(): void; 54 | _contextMenuHandler(event: MouseEvent): void; 55 | _mouseDownHandler(event: MouseEvent): void; 56 | _mouseUpHandler(): void; 57 | _mouseMoveHandler(event: MouseEvent): void; 58 | _mouseWheelHandler(event: WheelEvent): void; 59 | _touchStartHandler(event: TouchEvent): void; 60 | _touchMoveHandler(event: TouchEvent): void; 61 | _onKeyDownHandler(event: KeyboardEvent): void; 62 | _onKeyUpHandler(event: KeyboardEvent): void; 63 | _updatePanHandler(): void; 64 | _updateRotateHandler(): void; 65 | } 66 | -------------------------------------------------------------------------------- /dist/@types/camera/orthographic-camera.d.ts: -------------------------------------------------------------------------------- 1 | import { ReadonlyVec3, mat4 } from 'gl-matrix'; 2 | export declare class OrthographicCamera { 3 | static UP_VECTOR: ReadonlyVec3; 4 | left: number; 5 | right: number; 6 | top: number; 7 | bottom: number; 8 | near: number; 9 | far: number; 10 | zoom: number; 11 | position: [number, number, number]; 12 | lookAtPosition: [number, number, number]; 13 | projectionMatrix: mat4; 14 | viewMatrix: mat4; 15 | constructor(left: number, right: number, top: number, bottom: number, near: number, far: number); 16 | setPosition({ x, y, z, }: { 17 | x?: number | undefined; 18 | y?: number | undefined; 19 | z?: number | undefined; 20 | }): this; 21 | updateViewMatrix(): this; 22 | updateProjectionMatrix(): this; 23 | lookAt(target: [number, number, number]): this; 24 | } 25 | -------------------------------------------------------------------------------- /dist/@types/camera/perspective-camera.d.ts: -------------------------------------------------------------------------------- 1 | import { ReadonlyVec3, mat4 } from 'gl-matrix'; 2 | export declare class PerspectiveCamera { 3 | static UP_VECTOR: ReadonlyVec3; 4 | position: [number, number, number]; 5 | lookAtPosition: [number, number, number]; 6 | projectionMatrix: mat4; 7 | viewMatrix: mat4; 8 | zoom: number; 9 | fieldOfView: number; 10 | aspect: number; 11 | near: number; 12 | far: number; 13 | constructor(fieldOfView: number, aspect: number, near: number, far: number); 14 | setPosition({ x, y, z, }: { 15 | x?: number | undefined; 16 | y?: number | undefined; 17 | z?: number | undefined; 18 | }): this; 19 | updateViewMatrix(): this; 20 | updateProjectionMatrix(): this; 21 | lookAt(target: [number, number, number]): this; 22 | } 23 | -------------------------------------------------------------------------------- /dist/@types/core/cube-texture.d.ts: -------------------------------------------------------------------------------- 1 | import { Texture, TextureInterface } from './texture'; 2 | export declare class CubeTexture extends Texture { 3 | #private; 4 | constructor(gl: WebGLRenderingContext, { format, internalFormat, type, unpackAlignment, wrapS, wrapT, minFilter, magFilter, }?: TextureInterface); 5 | /** 6 | * 7 | * @param {Array.} sidesImages 8 | * @returns {this} 9 | */ 10 | addSides(sidesImages: Array): this; 11 | } 12 | -------------------------------------------------------------------------------- /dist/@types/core/framebuffer.d.ts: -------------------------------------------------------------------------------- 1 | import { Texture } from './texture'; 2 | interface FramebufferOptions { 3 | /** 4 | * @default gl.canvas.width 5 | */ 6 | width?: number; 7 | /** 8 | * @default gl.canvas.height 9 | */ 10 | height?: number; 11 | /** 12 | * @default gl.CLAMP_TO_EDGE 13 | */ 14 | wrapS?: GLenum; 15 | /** 16 | * @default gl.CLAMP_TO_EDGE 17 | */ 18 | wrapT?: GLenum; 19 | /** 20 | * @default gl.NEAREST 21 | */ 22 | minFilter?: GLenum; 23 | /** 24 | * @default gl.NEAREST 25 | */ 26 | magFilter?: GLenum; 27 | /** 28 | * @default gl.RGBA 29 | */ 30 | format?: GLenum; 31 | /** 32 | * @default gl.UNSIGNED_BYTE 33 | */ 34 | type?: GLenum; 35 | /** 36 | * @default gl.RGBA 37 | */ 38 | internalFormat?: GLenum; 39 | /** 40 | * @default true 41 | */ 42 | depth?: boolean; 43 | /** 44 | * @description Controls wether to use depth texture using WEBGL_depth_texture extension or regular renderbuffer 45 | * @default true 46 | */ 47 | useDepthRenderBuffer?: boolean; 48 | /** 49 | * @description Optional input texture, otherwise a new empty one will be generated 50 | */ 51 | inputTexture?: Texture; 52 | } 53 | export declare class Framebuffer { 54 | #private; 55 | texture: Texture; 56 | depthTexture?: Texture; 57 | static supportRenderingToFloat(gl: any): boolean; 58 | static supportRenderingToHalfFloat(gl: any): boolean; 59 | constructor(gl: WebGLRenderingContext, params?: FramebufferOptions); 60 | bind(): this; 61 | unbind(): this; 62 | checkCompleteness(): number; 63 | updateWithSize(width: number, height: number, updateTexture?: boolean): this; 64 | reset(): this; 65 | delete(): void; 66 | } 67 | export {}; 68 | -------------------------------------------------------------------------------- /dist/@types/core/geometry.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Geometry class to hold buffers and attributes for a mesh. 3 | * Accepts the data that makes up your model - indices, vertices, uvs, normals, etc. 4 | * The only required attribute & buffer to render is "position" 5 | * 6 | * @public 7 | */ 8 | export declare class Geometry { 9 | #private; 10 | attributes: Map; 11 | vertexCount: number; 12 | constructor(gl: WebGLRenderingContext); 13 | /** 14 | * @description Set data into element array buffer 15 | * @param {WebGLElementBufferInterface} params 16 | * @returns {this} 17 | */ 18 | addIndex(params: WebGLElementBufferInterface): this; 19 | /** 20 | * @description Add attribute as array buffer 21 | * @param {string} key - Name of attribute. Must match attribute name in your GLSL program 22 | * @param {WebGLArrayBufferInterface} params 23 | * @returns {this} 24 | */ 25 | addAttribute(key: string, params: WebGLArrayBufferInterface): this; 26 | /** 27 | * 28 | * @param {string} key - Name of attribute. Must match attribute name in your GLSL program 29 | * @param {number} index - Index to start updating your typed array from 30 | * @param {number} size - How many items are to be updated 31 | * @param {Float32Array} subTypeArray - The whole or partial array to update your attribute with 32 | * @returns {this} 33 | */ 34 | updateAttribute(key: string, index: number, size: number, subTypeArray: Float32Array): this; 35 | /** 36 | * @description Delete all buffers associated with this geometry 37 | */ 38 | delete(): void; 39 | } 40 | interface WebGLElementBufferInterface { 41 | /** 42 | * Indices as typed array 43 | */ 44 | typedArray: Uint32Array | Uint16Array; 45 | } 46 | interface WebGLArrayBufferInterface { 47 | /** 48 | * Data as typed array 49 | */ 50 | typedArray: Float32Array | Float64Array; 51 | /** 52 | * @defaultValue 1 53 | */ 54 | size?: number; 55 | /** 56 | * @defaultValue 1 57 | */ 58 | type?: number; 59 | /** 60 | * @defaultValue false 61 | */ 62 | normalized?: boolean; 63 | /** 64 | * @defaultValue 0 65 | */ 66 | stride?: number; 67 | /** 68 | * @defaultValue 1 69 | */ 70 | offset?: number; 71 | instancedDivisor?: number; 72 | } 73 | export {}; 74 | -------------------------------------------------------------------------------- /dist/@types/core/instanced-mesh.d.ts: -------------------------------------------------------------------------------- 1 | import { Mesh } from './mesh'; 2 | import { MeshInterface } from './Mesh'; 3 | export declare class InstancedMesh extends Mesh { 4 | #private; 5 | instanceCount: number; 6 | constructor(gl: WebGLRenderingContext, { geometry, uniforms, defines, instanceCount, vertexShaderSource, fragmentShaderSource, }: InstancedMeshInterface); 7 | /** 8 | * @param {number} index - Instance index on which to apply the matrix 9 | * @param {Float32Array|Float64Array} matrix - Matrix to control the instance scale, rotation and translation 10 | */ 11 | setMatrixAt(index: number, matrix: Float32Array): this; 12 | /** 13 | * Draws the instanced mesh 14 | */ 15 | draw(): this; 16 | } 17 | interface InstancedMeshInterface extends MeshInterface { 18 | instanceCount?: number; 19 | } 20 | export {}; 21 | -------------------------------------------------------------------------------- /dist/@types/core/mesh.d.ts: -------------------------------------------------------------------------------- 1 | import { SceneObject } from './scene-object'; 2 | import { Program } from './program'; 3 | import { Geometry } from './geometry'; 4 | import { PerspectiveCamera } from '../camera/perspective-camera'; 5 | import { OrthographicCamera } from '../camera/orthographic-camera'; 6 | import { UniformType } from './program'; 7 | /** 8 | * Mesh class for holding the geometry, program and shaders for an object. 9 | * 10 | * @public 11 | */ 12 | export declare class Mesh extends SceneObject { 13 | #private; 14 | protected vaoExtension: OES_vertex_array_objectInterface; 15 | protected hasIndices: boolean; 16 | program: Program; 17 | vao: WebGLVertexArrayObjectOES; 18 | /** 19 | * DrawMode 20 | * @default gl.TRIANGLES 21 | */ 22 | drawMode: GLenum; 23 | constructor(gl: WebGLRenderingContext, params: MeshInterface); 24 | /** 25 | * 26 | * @param {string} key - Name of attribute. Must match attribute name in your GLSL program 27 | * @param {number} index - Index to start updating your typed array from 28 | * @param {number} size - How many items are to be updated 29 | * @param {Float32Array} subTypeArray - The whole or partial array to update your attribute with 30 | * @returns {this} 31 | */ 32 | updateGeometryAttribute(key: string, index: number, size: number, subTypeArray: Float32Array): this; 33 | /** 34 | * Binds the program 35 | * @returns {this} 36 | */ 37 | use(): this; 38 | /** 39 | * Set uniform value. Query the uniform location if necessary and cache it in-memory for future use 40 | * @param {string} uniformName 41 | * @param {UniformType} uniformType 42 | * @param uniformValue 43 | * @returns {this} 44 | */ 45 | setUniform(uniformName: string, uniformType: UniformType, uniformValue: unknown): this; 46 | /** 47 | * Assign camera projection matrix and view matrix to model uniforms 48 | * @param {PerspectiveCamera|OrthographicCamera} camera 49 | * @returns {this} 50 | */ 51 | setCamera(camera: PerspectiveCamera | OrthographicCamera): this; 52 | /** 53 | * Renders the mesh 54 | * @returns {this} 55 | */ 56 | draw(): this; 57 | /** 58 | * Deletes the geometry, program and VAO extension associated with the Mesh 59 | */ 60 | delete(): void; 61 | } 62 | export interface MeshInterface { 63 | geometry: Geometry; 64 | /** 65 | * Uniforms as object list 66 | * @example 67 | * ``` 68 | * { type: 'int', value: 1 } 69 | * { type: 'vec4', value: [0, 1, 2, 3] } 70 | * ``` 71 | * @defaultValue {} 72 | */ 73 | uniforms?: Record; 74 | /** 75 | * TODO 76 | */ 77 | defines?: Record; 78 | /** 79 | * Vertex shader program as string 80 | */ 81 | vertexShaderSource: string; 82 | /** 83 | * Fragment shader program as string 84 | */ 85 | fragmentShaderSource: string; 86 | } 87 | interface OES_vertex_array_objectInterface { 88 | createVertexArrayOES(): WebGLVertexArrayObjectOES; 89 | deleteVertexArrayOES(arrayObject: WebGLVertexArrayObjectOES | null): void; 90 | isVertexArrayOES(arrayObject: WebGLVertexArrayObjectOES | null): boolean; 91 | bindVertexArrayOES(arrayObject: WebGLVertexArrayObjectOES | null): void; 92 | } 93 | export {}; 94 | -------------------------------------------------------------------------------- /dist/@types/core/program.d.ts: -------------------------------------------------------------------------------- 1 | import { UNIFORM_TYPE_INT, UNIFORM_TYPE_FLOAT, UNIFORM_TYPE_VEC2, UNIFORM_TYPE_VEC3, UNIFORM_TYPE_VEC4, UNIFORM_TYPE_MATRIX4X4 } from '../utils/gl-constants'; 2 | /** 3 | * Program class for compiling GLSL shaders and linking them in a WebGLProgram and managing its state 4 | * 5 | * @public 6 | */ 7 | export declare class Program { 8 | #private; 9 | constructor(gl: WebGLRenderingContext, params: ProgramInterface); 10 | /** 11 | * Set uniform value. Query the uniform location if necessary and cache it in-memory for future use 12 | * @param {string} uniformName 13 | * @param {UniformType} uniformType 14 | * @param uniformValue 15 | * @returns {this} 16 | */ 17 | setUniform(uniformName: string, uniformType: UniformType, uniformValue: any): this | null; 18 | /** 19 | * Get the location for an attribute 20 | * @param {string} attribName 21 | * @returns {number} attribLocation 22 | */ 23 | getAttribLocation(attribName: string): number | null; 24 | /** 25 | * Binds the program for use 26 | * @returns {this} 27 | */ 28 | bind(): this; 29 | /** 30 | * Uninds the program for use 31 | * @returns {this} 32 | */ 33 | unbind(): this; 34 | /** 35 | * Deletes the program 36 | */ 37 | delete(): void; 38 | } 39 | export declare type UniformType = typeof UNIFORM_TYPE_INT | typeof UNIFORM_TYPE_FLOAT | typeof UNIFORM_TYPE_VEC2 | typeof UNIFORM_TYPE_VEC3 | typeof UNIFORM_TYPE_VEC4 | typeof UNIFORM_TYPE_MATRIX4X4; 40 | export interface ProgramInterface { 41 | /** 42 | * Vertex shader program as string 43 | */ 44 | vertexShaderSource: string; 45 | /** 46 | * Fragment shader program as string 47 | */ 48 | fragmentShaderSource: string; 49 | } 50 | -------------------------------------------------------------------------------- /dist/@types/core/scene-object.d.ts: -------------------------------------------------------------------------------- 1 | import { mat4, ReadonlyMat4 } from 'gl-matrix'; 2 | import { Transform } from './transform'; 3 | /** 4 | * SceneObject that can have SceneObjects as children. Allows for proper scene graph. 5 | * 6 | * @public 7 | */ 8 | export declare class SceneObject extends Transform { 9 | protected renderable: boolean; 10 | parentNode: SceneObject | null; 11 | children: SceneObject[]; 12 | worldMatrix: mat4; 13 | normalMatrix: mat4; 14 | setParent: (parentNode?: SceneObject | null) => this; 15 | updateWorldMatrix: (parentWorldMatrix?: ReadonlyMat4 | null) => this; 16 | traverseGraph: (callback: any, node?: SceneObject) => this; 17 | } 18 | -------------------------------------------------------------------------------- /dist/@types/core/texture.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Texture class used to store image, video, canvas and data as typed arrays 3 | * @public 4 | */ 5 | export declare class Texture { 6 | protected gl: WebGLRenderingContext; 7 | protected texture: WebGLTexture | null; 8 | protected width: number; 9 | protected height: number; 10 | protected format: number; 11 | protected internalFormat: number; 12 | protected type: number; 13 | protected anisotropyExtension: EXT_texture_filter_anisotropic; 14 | protected target: number; 15 | static isPowerOf2: (width: number, height: number) => boolean; 16 | constructor(gl: WebGLRenderingContext, { format, internalFormat, type, unpackAlignment, wrapS, wrapT, minFilter, magFilter, target, }?: TextureInterface); 17 | /** 18 | * @returns {WebGLTexture|null} 19 | */ 20 | getTexture(): WebGLTexture | null; 21 | /** 22 | * Binds the texture to the target 23 | * @returns {this} 24 | */ 25 | bind(): this; 26 | /** 27 | * Unbinds the texture 28 | * @returns {this} 29 | */ 30 | unbind(): this; 31 | /** 32 | * @param {HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} image 33 | * @param {number} [width] 34 | * @param {number} [height 35 | * @returns {this} 36 | */ 37 | fromImage(image: HTMLImageElement | HTMLVideoElement | HTMLCanvasElement, width?: number, height?: number): this; 38 | /** 39 | * @param {number} width 40 | * @param {number} height 41 | * @returns {this} 42 | */ 43 | fromSize(width: number, height: number): this; 44 | /** 45 | * @param dataArray 46 | * @param {number} [width] 47 | * @param {number} [height] 48 | * @returns {this} 49 | */ 50 | fromData(dataArray: any, width: number, height: number): this; 51 | /** 52 | * @returns {this} 53 | */ 54 | generateMipmap(): this; 55 | /** 56 | * @param {GLEnum} [format = gl.RGB] 57 | * @param {GLEnum} [internalFormat = gl.RGB] 58 | * @param {GLenum} [type = gl.UNSIGNED_BYTE] 59 | * @returns {this} 60 | */ 61 | setFormat(format?: number, internalFormat?: number, type?: number): this; 62 | /** 63 | * @returns {this} 64 | */ 65 | setIsFlip(flip?: number): this; 66 | /** 67 | * @param {GLenum} name 68 | * @param params 69 | * @returns {this} 70 | */ 71 | setPixelStore(name: GLenum, params: GLenum): this; 72 | /** 73 | * @param {GLenum} [filter = gl.LINEAR] 74 | * @returns {this} 75 | */ 76 | setMinFilter(filter?: number): this; 77 | /** 78 | * @param {GLenum} [filter = gl.LINEAR] 79 | * @returns {this} 80 | */ 81 | setMagFilter(filter?: number): this; 82 | /** 83 | * 84 | * @param {GLenum} [wrapS = gl.CLAMP_TO_EDGE] 85 | * @param {GLenum} [wrapT = gl.CLAMP_TO_EDGE] 86 | * @returns {this} 87 | */ 88 | setWrap(wrapS?: number, wrapT?: number): this; 89 | /** 90 | * 91 | * @param {number} anisotropyLevel 92 | * @returns {this} 93 | */ 94 | setAnisotropy(anisotropyLevel: number): this; 95 | delete(): void; 96 | } 97 | export interface TextureInterface { 98 | /** 99 | * @default gl.RGB 100 | */ 101 | format?: GLenum; 102 | /** 103 | * @default gl.RGB 104 | */ 105 | internalFormat?: GLenum; 106 | /** 107 | * @default gl.UNSIGNED_BYTE 108 | */ 109 | type?: GLenum; 110 | /** 111 | * @default 1 112 | */ 113 | unpackAlignment?: number; 114 | /** 115 | * @default gl.CLAMP_TO_EDGE 116 | */ 117 | wrapS?: GLenum; 118 | /** 119 | * @default gl.CLAMP_TO_EDGE 120 | */ 121 | wrapT?: GLenum; 122 | /** 123 | * @default gl.LINEAR 124 | */ 125 | minFilter?: GLenum; 126 | /** 127 | * @default gl.LINEAR 128 | */ 129 | magFilter?: GLenum; 130 | /** 131 | * @default gl.TEXTURE_2D 132 | */ 133 | target?: GLenum; 134 | } 135 | -------------------------------------------------------------------------------- /dist/@types/core/transform.d.ts: -------------------------------------------------------------------------------- 1 | import { mat4, ReadonlyMat4, vec3 } from 'gl-matrix'; 2 | /** 3 | * Base transform class to handle vectors and matrices 4 | * 5 | * @public 6 | */ 7 | export declare class Transform { 8 | position: vec3; 9 | rotation: vec3; 10 | scale: vec3; 11 | modelMatrix: mat4; 12 | shouldUpdate: boolean; 13 | /** 14 | * @returns {this} 15 | */ 16 | copyFromMatrix(matrix: ReadonlyMat4): this; 17 | /** 18 | * @returns {this} 19 | */ 20 | setPosition(position: { 21 | x?: number; 22 | y?: number; 23 | z?: number; 24 | }): this; 25 | /** 26 | * Sets scale 27 | * @returns {this} 28 | */ 29 | setScale(scale: { 30 | x?: number; 31 | y?: number; 32 | z?: number; 33 | }): this; 34 | /** 35 | * Sets rotation 36 | * @returns {this} 37 | */ 38 | setRotation(rotation: { 39 | x?: number; 40 | y?: number; 41 | z?: number; 42 | }): this; 43 | /** 44 | * Update model matrix with scale, rotation and translation 45 | * @returns {this} 46 | */ 47 | updateModelMatrix(): this; 48 | } 49 | -------------------------------------------------------------------------------- /dist/@types/extra/swap-renderer.d.ts: -------------------------------------------------------------------------------- 1 | import { Framebuffer } from '../core/framebuffer'; 2 | import { Texture } from '../core/texture'; 3 | import { UniformType } from '../core/program'; 4 | export declare class SwapRenderer { 5 | #private; 6 | constructor(gl: WebGLRenderingContext); 7 | /** 8 | * @returns {Texture} 9 | */ 10 | getTexture(name: string): Texture; 11 | /** 12 | * Add external texture 13 | * @param {string} name Name for referencing later 14 | * @param {Texture} texture 15 | * @returns {this} 16 | */ 17 | addTexture(name: string, texture: Texture): this; 18 | /** 19 | * Add external framebuffer 20 | * @param {string} name Name for referencing later 21 | * @param {Framebuffer} framebuffer 22 | * @returns 23 | */ 24 | addFramebuffer(name: string, framebuffer: Framebuffer): this; 25 | /** 26 | * @param {string} name Name for referencing later 27 | * @param {number} width 28 | * @param {number} height 29 | * @param {Float32Array} data 30 | * @param {GLenum} filtering 31 | * @param {GLenum} inputType 32 | * @returns {this} 33 | */ 34 | createTexture(name: string, width: number, height: number, data?: Float32Array | Uint16Array | null, filtering?: number, inputType?: GLenum): this; 35 | /** 36 | * @param {string} name Name for referencing later 37 | * @param {number} width 38 | * @param {number} height 39 | * @returns {this} 40 | */ 41 | createFramebuffer(name: string, width: number, height: number): this; 42 | /** 43 | * @param {string} programName 44 | * @param {string} vertexShaderSource 45 | * @param {string} fragmentShaderSource 46 | * @returns {this} 47 | */ 48 | createProgram(programName: string, vertexShaderSource: string, fragmentShaderSource: string, defines?: { 49 | [key: string]: string; 50 | }): this; 51 | /** 52 | * Binds a program for use 53 | * @param {string} programName 54 | * @returns {this} 55 | */ 56 | useProgram(programName: string): this; 57 | /** 58 | * Sets a uniform to the active program 59 | * @param {string} uniformName 60 | * @param {string} uniformType 61 | * @param {string} uniformValue 62 | * @returns {this} 63 | */ 64 | setUniform(uniformName: string, uniformType: UniformType, uniformValue: string): this; 65 | /** 66 | * Set gl viewport size 67 | * @param {number} width 68 | * @param {number} height 69 | * @returns {this} 70 | */ 71 | setSize(width: number, height: number): this; 72 | /** 73 | * Renders a program with specific inputs to output framebuffer 74 | * @param {String[]} inputNameArr - Name of input framebuffers 75 | * @param outputName - Name of output framebuffer. "null" to render to device screen 76 | * @returns 77 | */ 78 | run(inputNameArr: string[], outputName: string): this; 79 | /** 80 | * Swap programs 81 | * @param {string} name1 82 | * @param {string} name2 83 | * @returns {this} 84 | */ 85 | swap(name1: string, name2: string): this; 86 | /** 87 | * @returns {this} 88 | */ 89 | reset(): this; 90 | /** 91 | * @returns {this} 92 | */ 93 | delete(): this; 94 | } 95 | -------------------------------------------------------------------------------- /dist/@types/geometry-utils/build-plane.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @private 3 | */ 4 | export declare function buildPlane(vertices: Float32Array, normal: Float32Array, uv: Float32Array, indices: Uint16Array | Uint32Array, width: number, height: number, depth: number, wSegs: number, hSegs: number, u?: number, v?: number, w?: number, uDir?: number, vDir?: number, i?: number, ii?: number): void; 5 | -------------------------------------------------------------------------------- /dist/@types/geometry-utils/create-box-separate-faces.d.ts: -------------------------------------------------------------------------------- 1 | export interface Box { 2 | /** 3 | * @defaultValue 1 4 | */ 5 | width?: number; 6 | /** 7 | * @defaultValue 1 8 | */ 9 | height?: number; 10 | /** 11 | * @defaultValue 1 12 | */ 13 | depth?: number; 14 | /** 15 | * @defaultValue 1 16 | */ 17 | widthSegments?: number; 18 | /** 19 | * @defaultValue 1 20 | */ 21 | heightSegments?: number; 22 | /** 23 | * @defaultValue 1 24 | */ 25 | depthSegments?: number; 26 | } 27 | /** 28 | * Generates geometry data for a box 29 | * @param {Box} params 30 | * @returns {[{ vertices, normal, uv, indices, orientation }]} 31 | */ 32 | export declare function createBoxSeparateFace(params?: Box): any[]; 33 | -------------------------------------------------------------------------------- /dist/@types/geometry-utils/create-box.d.ts: -------------------------------------------------------------------------------- 1 | export interface Box { 2 | /** 3 | * @defaultValue 1 4 | */ 5 | width?: number; 6 | /** 7 | * @defaultValue 1 8 | */ 9 | height?: number; 10 | /** 11 | * @defaultValue 1 12 | */ 13 | depth?: number; 14 | /** 15 | * @defaultValue 1 16 | */ 17 | widthSegments?: number; 18 | /** 19 | * @defaultValue 1 20 | */ 21 | heightSegments?: number; 22 | /** 23 | * @defaultValue 1 24 | */ 25 | depthSegments?: number; 26 | /** 27 | * @defaultValue false 28 | */ 29 | separateFaces?: boolean; 30 | } 31 | /** 32 | * Generates geometry data for a box 33 | * @param {Box} params 34 | * @returns {{ vertices, normal, uv, indices }} 35 | */ 36 | export declare function createBox(params?: Box): { 37 | vertices: Float32Array; 38 | normal: Float32Array; 39 | uv: Float32Array; 40 | indices: Uint32Array | Uint16Array; 41 | }; 42 | -------------------------------------------------------------------------------- /dist/@types/geometry-utils/create-circle.d.ts: -------------------------------------------------------------------------------- 1 | interface Circle { 2 | /** 3 | * @default 1 4 | */ 5 | radius?: number; 6 | /** 7 | * @default 8 8 | */ 9 | segments?: number; 10 | /** 11 | * @default 0 12 | */ 13 | thetaStart?: number; 14 | /** 15 | * @default Math.PI * 2 16 | */ 17 | thetaLength?: number; 18 | } 19 | /** 20 | * @description Generate circle geometry 21 | * @param {Circle} params 22 | * @returns {{ vertices, normal, uv, indices }} 23 | */ 24 | export declare function createCircle(params?: Circle): { 25 | indices: Uint32Array | Uint16Array; 26 | vertices: Float32Array; 27 | normal: Float32Array; 28 | uv: Float32Array; 29 | }; 30 | export {}; 31 | -------------------------------------------------------------------------------- /dist/@types/geometry-utils/create-plane.d.ts: -------------------------------------------------------------------------------- 1 | interface Plane { 2 | /** 3 | * @defaultValue 1 4 | */ 5 | width?: number; 6 | /** 7 | * @defaultValue 1 8 | */ 9 | height?: number; 10 | /** 11 | * @defaultValue 1 12 | */ 13 | widthSegments?: number; 14 | /** 15 | * @defaultValue 1 16 | */ 17 | heightSegments?: number; 18 | } 19 | /** 20 | * Generates geometry data for a quad 21 | * @param {PlaneInterface} params 22 | * @returns {{ vertices, normal, uv, indices }} 23 | */ 24 | export declare function createPlane(params?: Plane): { 25 | vertices: Float32Array; 26 | normal: Float32Array; 27 | uv: Float32Array; 28 | indices: Uint32Array | Uint16Array; 29 | }; 30 | export {}; 31 | -------------------------------------------------------------------------------- /dist/@types/geometry-utils/create-rounded-box-separate-faces.d.ts: -------------------------------------------------------------------------------- 1 | export declare const createRoundedBoxSeparateFace: ({ width, height, depth, radius, div, }: { 2 | width?: number | undefined; 3 | height?: number | undefined; 4 | depth?: number | undefined; 5 | radius?: number | undefined; 6 | div?: number | undefined; 7 | }) => never[]; 8 | -------------------------------------------------------------------------------- /dist/@types/geometry-utils/create-rounded-box.d.ts: -------------------------------------------------------------------------------- 1 | export declare class VRot90 { 2 | static xp(v: any, o: any): any; 3 | static xn(v: any, o: any): any; 4 | static yp(v: any, o: any): any; 5 | static yn(v: any, o: any): any; 6 | static zp(v: any, o: any): any; 7 | static zn(v: any, o: any): any; 8 | static xp_yn(v: any, o: any): any; 9 | static xp_yp(v: any, o: any): any; 10 | static xp_yp_yp(v: any, o: any): any; 11 | static xp_xp(v: any, o: any): any; 12 | } 13 | export declare const createRoundedBox: ({ width, height, depth, radius, div, }: { 14 | width?: number | undefined; 15 | height?: number | undefined; 16 | depth?: number | undefined; 17 | radius?: number | undefined; 18 | div?: number | undefined; 19 | }) => { 20 | vertices: Float32Array; 21 | normal: Float32Array; 22 | uv: Float32Array; 23 | indices: Uint16Array; 24 | }; 25 | -------------------------------------------------------------------------------- /dist/@types/geometry-utils/create-sphere.d.ts: -------------------------------------------------------------------------------- 1 | export interface Sphere { 2 | /** 3 | * @defaultValue 0.5 4 | */ 5 | radius?: number; 6 | /** 7 | * @defaultValue 16 8 | */ 9 | widthSegments?: number; 10 | /** 11 | * @defaultValue Math.ceil(widthSegments * 0.5) 12 | */ 13 | heightSegments?: number; 14 | /** 15 | * @defaultValue 0 16 | */ 17 | phiStart?: number; 18 | /** 19 | * @defaultValue Math.PI * 2 20 | */ 21 | phiLength?: number; 22 | /** 23 | * @defaultValue 0 24 | */ 25 | thetaStart?: number; 26 | /** 27 | * @defaultValue Math.PI 28 | */ 29 | thetaLength?: number; 30 | } 31 | /** 32 | * Generates geometry data for a sphere 33 | * @param {Sphere} params 34 | * @returns {{ vertices, normal, uv, indices }} 35 | */ 36 | export declare function createSphere(params?: Sphere): { 37 | vertices: Float32Array; 38 | normal: Float32Array; 39 | uv: Float32Array; 40 | indices: Uint32Array | Uint16Array; 41 | }; 42 | -------------------------------------------------------------------------------- /dist/@types/geometry-utils/create-torus.d.ts: -------------------------------------------------------------------------------- 1 | interface Torus { 2 | /** 3 | * @defaultValue 0.5 4 | */ 5 | radius?: number; 6 | /** 7 | * @defaultValue 0.35 8 | */ 9 | tube?: number; 10 | /** 11 | * @defaultValue Math.PI * 2 12 | */ 13 | arc?: number; 14 | /** 15 | * @defaultValue Math.PI * 2 16 | */ 17 | radialSegments?: number; 18 | /** 19 | * @defaultValue Math.PI * 2 20 | */ 21 | tubularSegments?: number; 22 | } 23 | /** 24 | * @description Generate torus geometry 25 | * @param {Torus} params 26 | * @returns {{ vertices, normal, uv, indices }} 27 | */ 28 | export declare function createTorus(params?: Torus): { 29 | indices: Uint32Array | Uint16Array; 30 | vertices: Float32Array; 31 | normal: Float32Array; 32 | uv: Float32Array; 33 | }; 34 | export {}; 35 | -------------------------------------------------------------------------------- /dist/@types/geometry-utils/index.d.ts: -------------------------------------------------------------------------------- 1 | import { createBox } from './create-box'; 2 | import { createBoxSeparateFace } from './create-box-separate-faces'; 3 | import { createRoundedBox } from './create-rounded-box'; 4 | import { createRoundedBoxSeparateFace } from './create-rounded-box-separate-faces'; 5 | import { createCircle } from './create-circle'; 6 | import { createPlane } from './create-plane'; 7 | import { createSphere } from './create-sphere'; 8 | import { createTorus } from './create-torus'; 9 | export { createBox }; 10 | export { createBoxSeparateFace }; 11 | export { createRoundedBoxSeparateFace }; 12 | export { createRoundedBox }; 13 | export { createCircle }; 14 | export { createPlane }; 15 | export { createSphere }; 16 | export { createTorus }; 17 | /** 18 | * @namespace GeometryUtils 19 | */ 20 | export declare const GeometryUtils: { 21 | createBox: typeof createBox; 22 | createBoxSeparateFace: typeof createBoxSeparateFace; 23 | createRoundedBoxSeparateFace: ({ width, height, depth, radius, div, }: { 24 | width?: number | undefined; 25 | height?: number | undefined; 26 | depth?: number | undefined; 27 | radius?: number | undefined; 28 | div?: number | undefined; 29 | }) => never[]; 30 | createRoundedBox: ({ width, height, depth, radius, div, }: { 31 | width?: number | undefined; 32 | height?: number | undefined; 33 | depth?: number | undefined; 34 | radius?: number | undefined; 35 | div?: number | undefined; 36 | }) => { 37 | vertices: Float32Array; 38 | normal: Float32Array; 39 | uv: Float32Array; 40 | indices: Uint16Array; 41 | }; 42 | createCircle: typeof createCircle; 43 | createPlane: typeof createPlane; 44 | createSphere: typeof createSphere; 45 | createTorus: typeof createTorus; 46 | }; 47 | -------------------------------------------------------------------------------- /dist/@types/index.d.ts: -------------------------------------------------------------------------------- 1 | export { Program } from './core/program'; 2 | export { Geometry } from './core/geometry'; 3 | export { Transform } from './core/transform'; 4 | export { SceneObject } from './core/scene-object'; 5 | export { Mesh } from './core/mesh'; 6 | export { InstancedMesh } from './core/instanced-mesh'; 7 | export { Texture } from './core/texture'; 8 | export { CubeTexture } from './core/cube-texture'; 9 | export { Framebuffer } from './core/framebuffer'; 10 | export { CameraController } from './camera/camera-controller'; 11 | export { PerspectiveCamera } from './camera/perspective-camera'; 12 | export { OrthographicCamera } from './camera/orthographic-camera'; 13 | export { SwapRenderer } from './extra/swap-renderer'; 14 | export * from './utils/gl-utils'; 15 | export * from './utils/gl-constants'; 16 | export * from './utils/math'; 17 | export * as GeometryUtils from './geometry-utils'; 18 | -------------------------------------------------------------------------------- /dist/@types/utils/gl-constants.d.ts: -------------------------------------------------------------------------------- 1 | export const MODEL_MATRIX_UNIFORM_NAME: "modelMatrix"; 2 | export const VIEW_MATRIX_UNIFORM_NAME: "viewMatrix"; 3 | export const PROJECTION_MATRIX_UNIFORM_NAME: "projectionMatrix"; 4 | export const INDEX_ATTRIB_NAME: "index"; 5 | export const POSITION_ATTRIB_NAME: "position"; 6 | export const INSTANCED_OFFSET_MODEL_MATRIX: "instanceModelMatrix"; 7 | export const UNIFORM_TYPE_INT: "int"; 8 | export const UNIFORM_TYPE_FLOAT: "float"; 9 | export const UNIFORM_TYPE_VEC2: "vec2"; 10 | export const UNIFORM_TYPE_VEC3: "vec3"; 11 | export const UNIFORM_TYPE_VEC4: "vec4"; 12 | export const UNIFORM_TYPE_MATRIX4X4: "mat4"; 13 | export const CUBE_SIDE_FRONT: "front"; 14 | export const CUBE_SIDE_BACK: "back"; 15 | export const CUBE_SIDE_TOP: "top"; 16 | export const CUBE_SIDE_BOTTOM: "bottom"; 17 | export const CUBE_SIDE_LEFT: "left"; 18 | export const CUBE_SIDE_RIGHT: "right"; 19 | export const POINTS: 0; 20 | export const LINES: 1; 21 | export const TRIANGLES: 4; 22 | export const STATIC_DRAW: 35044; 23 | export const TEXTURE_FILTER_NEAREST: 9728; 24 | export const TEXTURE_FILTER_LINEAR: 9729; 25 | -------------------------------------------------------------------------------- /dist/@types/utils/gl-utils.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Create and compile WebGLShader 3 | * @param {WebGLRenderingContext)} gl 4 | * @param {GLenum} shaderType 5 | * @param {string} shaderSource 6 | * @returns {WebGLShader} 7 | */ 8 | export declare function compileShader(gl: WebGLRenderingContext, shaderType: GLenum, shaderSource: string): WebGLShader | null; 9 | /** 10 | * Create and link WebGLProgram with provided shader strings 11 | * @param {(WebGLRenderingContext)} gl 12 | * @param {string} vertexShaderSource 13 | * @param {string} fragmentShaderSource 14 | * @returns {WebGLProgram} 15 | */ 16 | export declare function createProgram(gl: WebGLRenderingContext, vertexShaderSource: string, fragmentShaderSource: string): WebGLProgram | null; 17 | /** 18 | * Create a ARRAY_BUFFER buffer 19 | * @param {WebGLRenderingContext)} gl 20 | * @param {ArrayBuffer} data - Typed array types that will be copied into the data store 21 | * @param {GLenum} [usage = gl.STATIC_DRAW] - A GLenum specifying the intended usage pattern of the data store for optimization purposes 22 | * @returns {WebGLBuffer} 23 | */ 24 | export declare function createBuffer(gl: WebGLRenderingContext, data: Float32Array | Float64Array, usage?: GLenum): WebGLBuffer | null; 25 | /** 26 | * Create a ELEMENT_ARRAY_BUFFER buffer 27 | * @param {WebGLRenderingContext)} gl 28 | * @param {ArrayBuffer} data - Typed array types that will be copied into the data store 29 | * @param {GLenum} [usage=STATIC_DRAW] - A GLenum specifying the intended usage pattern of the data store for optimization purposes 30 | * @returns {WebGLBuffer} 31 | */ 32 | export declare function createIndexBuffer(gl: WebGLRenderingContext, indices: Uint16Array | Uint32Array, usage?: GLenum): WebGLBuffer | null; 33 | /** 34 | * Obtains and returns a WebGL extension if available. Caches it in-memory for future use. 35 | * @param {WebGLRenderingContext)} gl 36 | * @param {string} extensionName 37 | * @param {boolean} caching 38 | */ 39 | export declare function getExtension(gl: WebGLRenderingContext, extensionName: string, caching?: boolean): any; 40 | -------------------------------------------------------------------------------- /dist/@types/utils/math.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Clamp number to a given range 3 | * @param {number} num 4 | * @param {number} min 5 | * @param {number} max 6 | * @returns {number} 7 | */ 8 | export declare const clamp: (num: number, min: number, max: number) => number; 9 | /** 10 | * 11 | * @param {number} val 12 | * @param {number} inMin 13 | * @param {number} inMax 14 | * @param {number} outMin 15 | * @param {number} outMax 16 | * @returns {number} 17 | */ 18 | export declare const mapNumberRange: (val: number, inMin: number, inMax: number, outMin: number, outMax: number) => number; 19 | /** 20 | * Check if number is power of 2 21 | * @param {number} value 22 | * @returns {number} 23 | */ 24 | export declare const isPowerOf2: (value: number) => boolean; 25 | /** 26 | * Normalizes a number 27 | * @param {number} min 28 | * @param {number} max 29 | * @param {number} val 30 | * @returns {number} 31 | */ 32 | export declare const normalizeNumber: (min: number, max: number, val: number) => number; 33 | /** 34 | * 35 | * @param {number} t 36 | * @returns {number} 37 | */ 38 | export declare const triangleWave: (t: number) => number; 39 | -------------------------------------------------------------------------------- /dist/@types/utils/shader-snippets.d.ts: -------------------------------------------------------------------------------- 1 | export const vertexShaderSourceHead: string; 2 | export const fragmentShaderSourceHead: "\n precision highp float;\n"; 3 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | ![Preview hwoa-rang-gl renders](https://gnikoloff.github.io/hwoa-rang-gl/examples/dist/assets/textures/hwoa-rang-gl-preview.png) 2 | 3 | # hwoa-rang-gl 4 | 5 | ### Lightweight WebGL Library written in Typescript 6 | 7 | [![](https://img.shields.io/npm/v/hwoa-rang-gl)](https://www.npmjs.com/package/hwoa-rang-gl) [![](https://img.shields.io/npm/l/hwoa-rang-gl) ](https://www.npmjs.com/package/hwoa-rang-gl) [![size](https://badgen.net/bundlephobia/minzip/hwoa-rang-gl)](https://bundlephobia.com/result?p=hwoa-rang-gl@0.0.3) ![size](https://badgen.net/npm/types/hwoa-rang-gl) 8 | 9 | ### Install 10 | 11 | `npm i hwoa-rang-gl` 12 | 13 | ### Source code 14 | 15 | [hwoa-rang-gl/source](https://github.com/gnikoloff/hwoa-rang-gl) 16 | 17 | ### API Documentation 18 | 19 | [hwoa-rang-gl/docs](https://gnikoloff.github.io/hwoa-rang-gl/docs) 20 | 21 | ### Examples 22 | 23 | [hwoa-rang-gl/examples](https://gnikoloff.github.io/hwoa-rang-gl/examples/dist) 24 | 25 | ### Tutorials 26 | 27 | [hwoa-rang-gl/tutorials](https://gnikoloff.github.io/hwoa-rang-gl-tutorials/) 28 | 29 | ### Used in: 30 | 31 | - [https://2021.georgi-nikolov.com](https://2021.georgi-nikolov.com) 32 | - [https://gpgpu-boxes.georgi-nikolov.com/](https://gpgpu-boxes.georgi-nikolov.com/) 33 | - [https://redrockla.com/](https://redrockla.com/) 34 | 35 | ### Tools used 36 | 37 | - [Typescript](https://www.typescriptlang.org/) 38 | - [glMatrix](https://glmatrix.net/) 39 | - [WebGL Lint](https://github.com/greggman/webgl-lint) 40 | - [Spector.js](https://spector.babylonjs.com/) 41 | 42 | ### References 43 | 44 | - [tubugl](https://github.com/kenjiSpecial/tubugl) 45 | - [ogl](https://github.com/oframe/ogl) 46 | - [WebGL2 examples](https://github.com/tsherif/webgl2examples) 47 | - [three.js](https://github.com/mrdoob/three.js/) 48 | 49 | ### Resources 50 | 51 | - [WebGL fundamentals](https://webglfundamentals.org/) 52 | - [TojiCode](https://blog.tojicode.com/) 53 | - [Modern OpenGL Tutorials](http://ogldev.atspace.co.uk/) 54 | - [Understanding OpenGL Objects](https://www.haroldserrano.com/blog/understanding-opengl-objects) 55 | - [Learn OpenGL ES](https://www.learnopengles.com/tag/mipmap/) 56 | -------------------------------------------------------------------------------- /docs/docs/assets/images/icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/docs/assets/images/icons.png -------------------------------------------------------------------------------- /docs/docs/assets/images/icons@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/docs/assets/images/icons@2x.png -------------------------------------------------------------------------------- /docs/docs/assets/images/widgets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/docs/assets/images/widgets.png -------------------------------------------------------------------------------- /docs/docs/assets/images/widgets@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/docs/assets/images/widgets@2x.png -------------------------------------------------------------------------------- /docs/docs/modules/core_cube_texture.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | core/cube-texture | hwoa-rang-gl 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |
16 |
17 | 28 |
29 |
30 | Options 31 |
32 |
33 | All 34 |
    35 |
  • Public
  • 36 |
  • Public/Protected
  • 37 |
  • All
  • 38 |
39 |
40 | 41 | 42 | 43 | 44 |
45 |
46 | Menu 47 |
48 |
49 |
50 |
51 |
52 |
53 | 61 |

Module core/cube-texture

62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |

Index

70 |
71 |
72 |
73 |

Classes

74 | 77 |
78 |
79 |
80 |
81 |
82 | 101 |
102 |
103 |
104 |
105 |

Legend

106 |
107 |
    108 |
  • Variable
  • 109 |
  • Function
  • 110 |
  • Type alias
  • 111 |
112 |
    113 |
  • Interface
  • 114 |
115 |
    116 |
  • Class
  • 117 |
118 |
119 |
120 |
121 |
122 |

Generated using TypeDoc

123 |
124 |
125 | 126 | 127 | -------------------------------------------------------------------------------- /docs/docs/modules/core_framebuffer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | core/framebuffer | hwoa-rang-gl 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |
16 |
17 | 28 |
29 |
30 | Options 31 |
32 |
33 | All 34 |
    35 |
  • Public
  • 36 |
  • Public/Protected
  • 37 |
  • All
  • 38 |
39 |
40 | 41 | 42 | 43 | 44 |
45 |
46 | Menu 47 |
48 |
49 |
50 |
51 |
52 |
53 | 61 |

Module core/framebuffer

62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |

Index

70 |
71 |
72 |
73 |

Classes

74 | 77 |
78 |
79 |
80 |
81 |
82 | 101 |
102 |
103 |
104 |
105 |

Legend

106 |
107 |
    108 |
  • Variable
  • 109 |
  • Function
  • 110 |
  • Type alias
  • 111 |
112 |
    113 |
  • Interface
  • 114 |
115 |
    116 |
  • Class
  • 117 |
118 |
119 |
120 |
121 |
122 |

Generated using TypeDoc

123 |
124 |
125 | 126 | 127 | -------------------------------------------------------------------------------- /docs/docs/modules/core_geometry.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | core/geometry | hwoa-rang-gl 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |
16 |
17 | 28 |
29 |
30 | Options 31 |
32 |
33 | All 34 |
    35 |
  • Public
  • 36 |
  • Public/Protected
  • 37 |
  • All
  • 38 |
39 |
40 | 41 | 42 | 43 | 44 |
45 |
46 | Menu 47 |
48 |
49 |
50 |
51 |
52 |
53 | 61 |

Module core/geometry

62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |

Index

70 |
71 |
72 |
73 |

Classes

74 | 77 |
78 |
79 |
80 |
81 |
82 | 101 |
102 |
103 |
104 |
105 |

Legend

106 |
107 |
    108 |
  • Variable
  • 109 |
  • Function
  • 110 |
  • Type alias
  • 111 |
112 |
    113 |
  • Interface
  • 114 |
115 |
    116 |
  • Class
  • 117 |
118 |
119 |
120 |
121 |
122 |

Generated using TypeDoc

123 |
124 |
125 | 126 | 127 | -------------------------------------------------------------------------------- /docs/docs/modules/core_transform.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | core/transform | hwoa-rang-gl 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |
16 |
17 | 28 |
29 |
30 | Options 31 |
32 |
33 | All 34 |
    35 |
  • Public
  • 36 |
  • Public/Protected
  • 37 |
  • All
  • 38 |
39 |
40 | 41 | 42 | 43 | 44 |
45 |
46 | Menu 47 |
48 |
49 |
50 |
51 |
52 |
53 | 61 |

Module core/transform

62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |

Index

70 |
71 |
72 |
73 |

Classes

74 | 77 |
78 |
79 |
80 |
81 |
82 | 101 |
102 |
103 |
104 |
105 |

Legend

106 |
107 |
    108 |
  • Variable
  • 109 |
  • Function
  • 110 |
  • Type alias
  • 111 |
112 |
    113 |
  • Interface
  • 114 |
115 |
    116 |
  • Class
  • 117 |
118 |
119 |
120 |
121 |
122 |

Generated using TypeDoc

123 |
124 |
125 | 126 | 127 | -------------------------------------------------------------------------------- /docs/examples/EXAMPLES.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "label": "Particles", 4 | "group": "particles", 5 | "children": [ 6 | { 7 | "label": "Particles 01", 8 | "id": "particles-01" 9 | }, 10 | { 11 | "label": "Particles 02", 12 | "id": "particles-02" 13 | } 14 | ] 15 | }, 16 | { 17 | "label": "Geometry", 18 | "group": "geometry", 19 | "children": [ 20 | { 21 | "label": "Geometry", 22 | "id": "geometry" 23 | }, 24 | { 25 | "label": "Instanced Geometry", 26 | "id": "instanced-geometry" 27 | } 28 | ] 29 | }, 30 | { 31 | "label": "Texture", 32 | "group": "texture", 33 | "children": [ 34 | { 35 | "label": "Texture", 36 | "id": "texture" 37 | }, 38 | { 39 | "label": "Multi Face Texture", 40 | "id": "multi-texture" 41 | }, 42 | { 43 | "label": "Projection Mapping", 44 | "id": "projection-mapping" 45 | } 46 | ] 47 | }, 48 | { 49 | "label": "Lighting", 50 | "group": "lighting", 51 | "children": [ 52 | { 53 | "label": "Directional Light", 54 | "id": "directional-light" 55 | }, 56 | { 57 | "label": "Point Light", 58 | "id": "point-light" 59 | }, 60 | { 61 | "label": "Spot Light", 62 | "id": "spot-light" 63 | }, 64 | { 65 | "label": "Deferred Shading", 66 | "id": "deferred-shading" 67 | }, 68 | { 69 | "label": "Shadow Map", 70 | "id": "shadow" 71 | } 72 | ] 73 | }, 74 | { 75 | "label": "Framebuffer", 76 | "group": "framebuffer", 77 | "children": [ 78 | { 79 | "label": "Godrays", 80 | "id": "godrays" 81 | }, 82 | { 83 | "label": "Persistence", 84 | "id": "persistence" 85 | } 86 | ] 87 | }, 88 | { 89 | "label": "Swap Renderer", 90 | "group": "swap-renderer", 91 | "children": [ 92 | { 93 | "label": "Particles", 94 | "id": "gpgpu-particles" 95 | }, 96 | { 97 | "label": "Noise Texture", 98 | "id": "swaprenderer-noise-texture" 99 | }, 100 | { 101 | "label": "Image", 102 | "id": "swaprenderer-image" 103 | }, 104 | { 105 | "label": "Fluid", 106 | "id": "swaprenderer-fluid" 107 | } 108 | ] 109 | }, 110 | { 111 | "label": "Extra", 112 | "group": "extra", 113 | "children": [ 114 | { 115 | "label": "Mouse Picking", 116 | "id": "mouse-picking" 117 | }, 118 | { 119 | "label": "Text", 120 | "id": "text" 121 | }, 122 | { 123 | "label": "GLTF", 124 | "id": "gltf" 125 | }, 126 | { 127 | "label": "Fog", 128 | "id": "fog" 129 | } 130 | ] 131 | } 132 | ] -------------------------------------------------------------------------------- /docs/examples/assets/models/Suzanne.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/assets/models/Suzanne.bin -------------------------------------------------------------------------------- /docs/examples/assets/models/Suzanne.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "accessors" : [ 3 | { 4 | "bufferView" : 0, 5 | "byteOffset" : 0, 6 | "componentType" : 5123, 7 | "count" : 11808, 8 | "max" : [ 9 | 11807 10 | ], 11 | "min" : [ 12 | 0 13 | ], 14 | "type" : "SCALAR" 15 | }, 16 | { 17 | "bufferView" : 1, 18 | "byteOffset" : 0, 19 | "componentType" : 5126, 20 | "count" : 11808, 21 | "max" : [ 22 | 1.336914, 23 | 0.950195, 24 | 0.825684 25 | ], 26 | "min" : [ 27 | -1.336914, 28 | -0.974609, 29 | -0.800781 30 | ], 31 | "type" : "VEC3" 32 | }, 33 | { 34 | "bufferView" : 2, 35 | "byteOffset" : 0, 36 | "componentType" : 5126, 37 | "count" : 11808, 38 | "max" : [ 39 | 0.996339, 40 | 0.999958, 41 | 0.999929 42 | ], 43 | "min" : [ 44 | -0.996339, 45 | -0.985940, 46 | -0.999994 47 | ], 48 | "type" : "VEC3" 49 | }, 50 | { 51 | "bufferView" : 3, 52 | "byteOffset" : 0, 53 | "componentType" : 5126, 54 | "count" : 11808, 55 | "max" : [ 56 | 0.998570, 57 | 0.999996, 58 | 0.999487, 59 | 1.000000 60 | ], 61 | "min" : [ 62 | -0.999233, 63 | -0.999453, 64 | -0.999812, 65 | 1.000000 66 | ], 67 | "type" : "VEC4" 68 | }, 69 | { 70 | "bufferView" : 4, 71 | "byteOffset" : 0, 72 | "componentType" : 5126, 73 | "count" : 11808, 74 | "max" : [ 75 | 0.999884, 76 | 0.884359 77 | ], 78 | "min" : [ 79 | 0.000116, 80 | 0.000116 81 | ], 82 | "type" : "VEC2" 83 | } 84 | ], 85 | "asset" : { 86 | "generator" : "VKTS glTF 2.0 exporter", 87 | "version" : "2.0" 88 | }, 89 | "bufferViews" : [ 90 | { 91 | "buffer" : 0, 92 | "byteLength" : 23616, 93 | "byteOffset" : 0, 94 | "target" : 34963 95 | }, 96 | { 97 | "buffer" : 0, 98 | "byteLength" : 141696, 99 | "byteOffset" : 23616, 100 | "target" : 34962 101 | }, 102 | { 103 | "buffer" : 0, 104 | "byteLength" : 141696, 105 | "byteOffset" : 165312, 106 | "target" : 34962 107 | }, 108 | { 109 | "buffer" : 0, 110 | "byteLength" : 188928, 111 | "byteOffset" : 307008, 112 | "target" : 34962 113 | }, 114 | { 115 | "buffer" : 0, 116 | "byteLength" : 94464, 117 | "byteOffset" : 495936, 118 | "target" : 34962 119 | } 120 | ], 121 | "buffers" : [ 122 | { 123 | "byteLength" : 590400, 124 | "uri" : "Suzanne.bin" 125 | } 126 | ], 127 | "images" : [ 128 | { 129 | "uri" : "Suzanne_BaseColor.png" 130 | }, 131 | { 132 | "uri" : "Suzanne_MetallicRoughness.png" 133 | } 134 | ], 135 | "materials" : [ 136 | { 137 | "name" : "Suzanne", 138 | "pbrMetallicRoughness" : { 139 | "baseColorTexture" : { 140 | "index" : 0 141 | }, 142 | "metallicRoughnessTexture" : { 143 | "index" : 1 144 | } 145 | } 146 | } 147 | ], 148 | "meshes" : [ 149 | { 150 | "name" : "Suzanne", 151 | "primitives" : [ 152 | { 153 | "attributes" : { 154 | "NORMAL" : 2, 155 | "POSITION" : 1, 156 | "TANGENT" : 3, 157 | "TEXCOORD_0" : 4 158 | }, 159 | "indices" : 0, 160 | "material" : 0, 161 | "mode" : 4 162 | } 163 | ] 164 | } 165 | ], 166 | "nodes" : [ 167 | { 168 | "mesh" : 0, 169 | "name" : "Suzanne" 170 | } 171 | ], 172 | "samplers" : [ 173 | {} 174 | ], 175 | "scene" : 0, 176 | "scenes" : [ 177 | { 178 | "nodes" : [ 179 | 0 180 | ] 181 | } 182 | ], 183 | "textures" : [ 184 | { 185 | "sampler" : 0, 186 | "source" : 0 187 | }, 188 | { 189 | "sampler" : 0, 190 | "source" : 1 191 | } 192 | ] 193 | } -------------------------------------------------------------------------------- /docs/examples/assets/textures/Suzanne_BaseColor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/assets/textures/Suzanne_BaseColor.png -------------------------------------------------------------------------------- /docs/examples/assets/textures/Suzanne_MetallicRoughness.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/assets/textures/Suzanne_MetallicRoughness.png -------------------------------------------------------------------------------- /docs/examples/assets/textures/UV_Grid_Sm.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/assets/textures/UV_Grid_Sm.jpeg -------------------------------------------------------------------------------- /docs/examples/assets/textures/UV_Grid_Sm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/assets/textures/UV_Grid_Sm.png -------------------------------------------------------------------------------- /docs/examples/assets/textures/box.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/assets/textures/box.jpeg -------------------------------------------------------------------------------- /docs/examples/assets/textures/debug_uv_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/assets/textures/debug_uv_01.png -------------------------------------------------------------------------------- /docs/examples/assets/textures/hwoa-rang-gl-preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/assets/textures/hwoa-rang-gl-preview.png -------------------------------------------------------------------------------- /docs/examples/assets/textures/social-preview-hwoa-rang-gl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/assets/textures/social-preview-hwoa-rang-gl.png -------------------------------------------------------------------------------- /docs/examples/assets/textures/texture04.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/assets/textures/texture04.jpeg -------------------------------------------------------------------------------- /docs/examples/assets/textures/webgl-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/assets/textures/webgl-logo.png -------------------------------------------------------------------------------- /docs/examples/assets/textures/zhang-kaiyv-44yxPSPmtjg-unsplash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/assets/textures/zhang-kaiyv-44yxPSPmtjg-unsplash.png -------------------------------------------------------------------------------- /docs/examples/assets/textures/zhang-kaiyv-G7oFLe-OW74-unsplash.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/assets/textures/zhang-kaiyv-G7oFLe-OW74-unsplash.jpeg -------------------------------------------------------------------------------- /docs/examples/assets/textures/zhang-kaiyv-Jt5a-wTJR1Q-unsplash.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/assets/textures/zhang-kaiyv-Jt5a-wTJR1Q-unsplash.jpeg -------------------------------------------------------------------------------- /docs/examples/assets/textures/zhang-kaiyv-MheaLsLj1to-unsplash.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/assets/textures/zhang-kaiyv-MheaLsLj1to-unsplash.jpeg -------------------------------------------------------------------------------- /docs/examples/assets/textures/zhang-kaiyv-X9GKFnHy_WA-unsplash.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/assets/textures/zhang-kaiyv-X9GKFnHy_WA-unsplash.jpeg -------------------------------------------------------------------------------- /docs/examples/assets/textures/zhang-kaiyv-mh2o8DuHaMM-unsplash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/assets/textures/zhang-kaiyv-mh2o8DuHaMM-unsplash.png -------------------------------------------------------------------------------- /docs/examples/dist/assets/models/Suzanne.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/dist/assets/models/Suzanne.bin -------------------------------------------------------------------------------- /docs/examples/dist/assets/models/Suzanne.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "accessors" : [ 3 | { 4 | "bufferView" : 0, 5 | "byteOffset" : 0, 6 | "componentType" : 5123, 7 | "count" : 11808, 8 | "max" : [ 9 | 11807 10 | ], 11 | "min" : [ 12 | 0 13 | ], 14 | "type" : "SCALAR" 15 | }, 16 | { 17 | "bufferView" : 1, 18 | "byteOffset" : 0, 19 | "componentType" : 5126, 20 | "count" : 11808, 21 | "max" : [ 22 | 1.336914, 23 | 0.950195, 24 | 0.825684 25 | ], 26 | "min" : [ 27 | -1.336914, 28 | -0.974609, 29 | -0.800781 30 | ], 31 | "type" : "VEC3" 32 | }, 33 | { 34 | "bufferView" : 2, 35 | "byteOffset" : 0, 36 | "componentType" : 5126, 37 | "count" : 11808, 38 | "max" : [ 39 | 0.996339, 40 | 0.999958, 41 | 0.999929 42 | ], 43 | "min" : [ 44 | -0.996339, 45 | -0.985940, 46 | -0.999994 47 | ], 48 | "type" : "VEC3" 49 | }, 50 | { 51 | "bufferView" : 3, 52 | "byteOffset" : 0, 53 | "componentType" : 5126, 54 | "count" : 11808, 55 | "max" : [ 56 | 0.998570, 57 | 0.999996, 58 | 0.999487, 59 | 1.000000 60 | ], 61 | "min" : [ 62 | -0.999233, 63 | -0.999453, 64 | -0.999812, 65 | 1.000000 66 | ], 67 | "type" : "VEC4" 68 | }, 69 | { 70 | "bufferView" : 4, 71 | "byteOffset" : 0, 72 | "componentType" : 5126, 73 | "count" : 11808, 74 | "max" : [ 75 | 0.999884, 76 | 0.884359 77 | ], 78 | "min" : [ 79 | 0.000116, 80 | 0.000116 81 | ], 82 | "type" : "VEC2" 83 | } 84 | ], 85 | "asset" : { 86 | "generator" : "VKTS glTF 2.0 exporter", 87 | "version" : "2.0" 88 | }, 89 | "bufferViews" : [ 90 | { 91 | "buffer" : 0, 92 | "byteLength" : 23616, 93 | "byteOffset" : 0, 94 | "target" : 34963 95 | }, 96 | { 97 | "buffer" : 0, 98 | "byteLength" : 141696, 99 | "byteOffset" : 23616, 100 | "target" : 34962 101 | }, 102 | { 103 | "buffer" : 0, 104 | "byteLength" : 141696, 105 | "byteOffset" : 165312, 106 | "target" : 34962 107 | }, 108 | { 109 | "buffer" : 0, 110 | "byteLength" : 188928, 111 | "byteOffset" : 307008, 112 | "target" : 34962 113 | }, 114 | { 115 | "buffer" : 0, 116 | "byteLength" : 94464, 117 | "byteOffset" : 495936, 118 | "target" : 34962 119 | } 120 | ], 121 | "buffers" : [ 122 | { 123 | "byteLength" : 590400, 124 | "uri" : "Suzanne.bin" 125 | } 126 | ], 127 | "images" : [ 128 | { 129 | "uri" : "Suzanne_BaseColor.png" 130 | }, 131 | { 132 | "uri" : "Suzanne_MetallicRoughness.png" 133 | } 134 | ], 135 | "materials" : [ 136 | { 137 | "name" : "Suzanne", 138 | "pbrMetallicRoughness" : { 139 | "baseColorTexture" : { 140 | "index" : 0 141 | }, 142 | "metallicRoughnessTexture" : { 143 | "index" : 1 144 | } 145 | } 146 | } 147 | ], 148 | "meshes" : [ 149 | { 150 | "name" : "Suzanne", 151 | "primitives" : [ 152 | { 153 | "attributes" : { 154 | "NORMAL" : 2, 155 | "POSITION" : 1, 156 | "TANGENT" : 3, 157 | "TEXCOORD_0" : 4 158 | }, 159 | "indices" : 0, 160 | "material" : 0, 161 | "mode" : 4 162 | } 163 | ] 164 | } 165 | ], 166 | "nodes" : [ 167 | { 168 | "mesh" : 0, 169 | "name" : "Suzanne" 170 | } 171 | ], 172 | "samplers" : [ 173 | {} 174 | ], 175 | "scene" : 0, 176 | "scenes" : [ 177 | { 178 | "nodes" : [ 179 | 0 180 | ] 181 | } 182 | ], 183 | "textures" : [ 184 | { 185 | "sampler" : 0, 186 | "source" : 0 187 | }, 188 | { 189 | "sampler" : 0, 190 | "source" : 1 191 | } 192 | ] 193 | } -------------------------------------------------------------------------------- /docs/examples/dist/assets/textures/Suzanne_BaseColor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/dist/assets/textures/Suzanne_BaseColor.png -------------------------------------------------------------------------------- /docs/examples/dist/assets/textures/Suzanne_MetallicRoughness.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/dist/assets/textures/Suzanne_MetallicRoughness.png -------------------------------------------------------------------------------- /docs/examples/dist/assets/textures/UV_Grid_Sm.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/dist/assets/textures/UV_Grid_Sm.jpeg -------------------------------------------------------------------------------- /docs/examples/dist/assets/textures/UV_Grid_Sm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/dist/assets/textures/UV_Grid_Sm.png -------------------------------------------------------------------------------- /docs/examples/dist/assets/textures/box.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/dist/assets/textures/box.jpeg -------------------------------------------------------------------------------- /docs/examples/dist/assets/textures/debug_uv_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/dist/assets/textures/debug_uv_01.png -------------------------------------------------------------------------------- /docs/examples/dist/assets/textures/hwoa-rang-gl-preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/dist/assets/textures/hwoa-rang-gl-preview.png -------------------------------------------------------------------------------- /docs/examples/dist/assets/textures/social-preview-hwoa-rang-gl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/dist/assets/textures/social-preview-hwoa-rang-gl.png -------------------------------------------------------------------------------- /docs/examples/dist/assets/textures/texture04.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/dist/assets/textures/texture04.jpeg -------------------------------------------------------------------------------- /docs/examples/dist/assets/textures/webgl-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/dist/assets/textures/webgl-logo.png -------------------------------------------------------------------------------- /docs/examples/dist/assets/textures/zhang-kaiyv-44yxPSPmtjg-unsplash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/dist/assets/textures/zhang-kaiyv-44yxPSPmtjg-unsplash.png -------------------------------------------------------------------------------- /docs/examples/dist/assets/textures/zhang-kaiyv-G7oFLe-OW74-unsplash.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/dist/assets/textures/zhang-kaiyv-G7oFLe-OW74-unsplash.jpeg -------------------------------------------------------------------------------- /docs/examples/dist/assets/textures/zhang-kaiyv-Jt5a-wTJR1Q-unsplash.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/dist/assets/textures/zhang-kaiyv-Jt5a-wTJR1Q-unsplash.jpeg -------------------------------------------------------------------------------- /docs/examples/dist/assets/textures/zhang-kaiyv-MheaLsLj1to-unsplash.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/dist/assets/textures/zhang-kaiyv-MheaLsLj1to-unsplash.jpeg -------------------------------------------------------------------------------- /docs/examples/dist/assets/textures/zhang-kaiyv-X9GKFnHy_WA-unsplash.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/dist/assets/textures/zhang-kaiyv-X9GKFnHy_WA-unsplash.jpeg -------------------------------------------------------------------------------- /docs/examples/dist/assets/textures/zhang-kaiyv-mh2o8DuHaMM-unsplash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/dist/assets/textures/zhang-kaiyv-mh2o8DuHaMM-unsplash.png -------------------------------------------------------------------------------- /docs/examples/dist/deferred-shading/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | GLTF 8 | 34 | 35 | 36 |
37 | 40 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /docs/examples/dist/directional-light/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Geometry 8 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/examples/dist/fog/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Geometry 8 | 9 | 68 | 69 | 70 | 71 | 72 |
73 |
74 |
75 |

Linear Fog

76 |

Fog that grows linearly denser with the distance

77 |
78 |
79 |
80 |
81 |

Exponential Squared Fog

82 |

Fog exponentially densening with the distance

83 |
84 |
85 |
86 | 87 | 88 | -------------------------------------------------------------------------------- /docs/examples/dist/geometry/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Geometry 8 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/examples/dist/gltf/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | GLTF 8 | 18 | 19 | 20 |
21 | 22 | 23 | -------------------------------------------------------------------------------- /docs/examples/dist/godrays/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Godrays 8 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/examples/dist/gpgpu-particles/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | GPGPU Particles 8 | 34 | 35 | 36 |
37 |
38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /docs/examples/dist/instanced-geometry/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Geometry 8 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/examples/dist/mouse-picking/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Mousepicking 8 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/examples/dist/multi-texture/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Multi Face Texture 8 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/examples/dist/particles-01/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Particles 01 8 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/examples/dist/particles-02/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Particles 01 8 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/examples/dist/persistence/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Persistence 8 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/examples/dist/point-light/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Point Light 8 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /docs/examples/dist/projection-mapping/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Planar Perspective Projection 8 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /docs/examples/dist/shadow/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Planar Perspective Projection 8 | 11 | 12 | 13 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /docs/examples/dist/spot-light/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Spot Light 8 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/examples/dist/swaprenderer-fluid/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | GPGPU Particles 8 | 33 | 34 | 35 | 36 | 37 | 45 | 46 |
47 | 48 | 49 | -------------------------------------------------------------------------------- /docs/examples/dist/swaprenderer-image/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | GPGPU Particles 8 | 33 | 34 | 35 |
36 |
Photo by Zhang Kaiyv
37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /docs/examples/dist/swaprenderer-noise-texture/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | GPGPU Particles 8 | 34 | 35 | 36 |
37 |
38 | 39 | 40 | -------------------------------------------------------------------------------- /docs/examples/dist/text/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Text 8 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /docs/examples/dist/texture/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Texture 8 | 18 | 19 | 20 |
Photo by Zhang Kaiyv
21 | 22 | 23 | -------------------------------------------------------------------------------- /docs/examples/examples-src/gpgpu-fluid/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | GPGPU Particles 8 | 32 | 33 | 34 |
35 |
36 | 37 | 38 | -------------------------------------------------------------------------------- /docs/examples/index.js: -------------------------------------------------------------------------------- 1 | import examplesDefinitions from './EXAMPLES.json' 2 | 3 | let currentExampleTitle = 'Particles 01' 4 | 5 | const viewerIframe = document.getElementById('preview-iframe') 6 | const appAside = document.getElementsByClassName('app-aside')[0] 7 | const appNav = document.getElementById('app-nav') 8 | const sourceLinkBtn = document.getElementById('source-link') 9 | const mobileNavToggleBtn = document.getElementById('toggle-mobile-nav') 10 | 11 | examplesDefinitions.forEach((groupDefinition) => { 12 | const { label, children } = groupDefinition 13 | const groupHeadline = document.createElement('h3') 14 | groupHeadline.textContent = label 15 | const childrenList = document.createElement('ul') 16 | 17 | appNav.appendChild(groupHeadline) 18 | appNav.appendChild(childrenList) 19 | 20 | children.forEach((definition) => { 21 | const link = document.createElement('a') 22 | if (definition.id) { 23 | link.setAttribute('href', `#${definition.id}`) 24 | } 25 | link.innerText = definition.label 26 | 27 | const listItem = document.createElement('li') 28 | listItem.appendChild(link) 29 | childrenList.appendChild(listItem) 30 | }) 31 | }) 32 | 33 | function onHashChange() { 34 | if (location.hash) { 35 | const exampleName = location.hash.substring(1) 36 | 37 | document.title = `hwoa-rang-gl | ${exampleName}` 38 | 39 | viewerIframe.setAttribute('src', `${exampleName}/index.html`) 40 | viewerIframe.setAttribute('title', currentExampleTitle) 41 | 42 | sourceLinkBtn.setAttribute( 43 | 'href', 44 | `https://github.com/gnikoloff/hwoa-rang-gl/tree/main/docs/examples/src/${exampleName}/index.js`, 45 | ) 46 | } else { 47 | const exampleName = 'particles-01' 48 | location.hash = exampleName 49 | sourceLinkBtn.setAttribute( 50 | 'href', 51 | `https://github.com/gnikoloff/hwoa-rang-gl/tree/main/docs/examples/src/${exampleName}/index.js`, 52 | ) 53 | } 54 | if (appAside.classList.contains('visible')) { 55 | appAside.classList.remove('visible') 56 | } 57 | } 58 | 59 | function onNavClick(e) { 60 | if (e.target.nodeName === 'A') { 61 | currentExampleTitle = e.target.dataset.title 62 | } 63 | } 64 | 65 | function toggleMobileNav() { 66 | appAside.classList.toggle('visible') 67 | } 68 | 69 | function onDOMLoad() { 70 | onHashChange() 71 | 72 | appNav.addEventListener('click', onNavClick) 73 | mobileNavToggleBtn.addEventListener('click', toggleMobileNav) 74 | } 75 | 76 | function onResize() { 77 | const doc = document.documentElement 78 | doc.style.setProperty('--app-height', `${window.innerHeight}px`) 79 | } 80 | 81 | window.onhashchange = onHashChange 82 | document.addEventListener('DOMContentLoaded', onDOMLoad) 83 | window.addEventListener('resize', onResize) 84 | onResize() 85 | -------------------------------------------------------------------------------- /docs/examples/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hwoa-rang-gl-examples", 3 | "version": "0.0.1", 4 | "description": "Examples for webgl library hwoa-rang-gl", 5 | "main": "index.js", 6 | "scripts": { 7 | "start:dev": "rollup -c -w", 8 | "start": "rollup -c" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "@rollup/plugin-node-resolve": "^11.2.0", 14 | "rollup": "^2.41.2", 15 | "rollup-plugin-commonjs": "^10.1.0", 16 | "rollup-plugin-copy": "^3.4.0", 17 | "rollup-plugin-sourcemaps": "^0.6.3" 18 | }, 19 | "dependencies": { 20 | "@rollup/plugin-json": "^4.1.0", 21 | "dat.gui": "^0.7.7", 22 | "gl-matrix": "^3.3.0", 23 | "stats-js": "^1.0.1" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /docs/examples/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { nodeResolve } from '@rollup/plugin-node-resolve' 2 | import commonjs from 'rollup-plugin-commonjs' 3 | import sourcemaps from 'rollup-plugin-sourcemaps' 4 | import json from '@rollup/plugin-json' 5 | import copy from 'rollup-plugin-copy' 6 | import glslify from 'rollup-plugin-glslify' 7 | 8 | import examplesDefinitions from './EXAMPLES.json' 9 | 10 | const exampleInputs = examplesDefinitions.reduce((acc, { children }) => { 11 | acc.push(...children.filter(({ id }) => id).map(({ id }) => id)) 12 | return acc 13 | }, []) 14 | 15 | const sharedPlugins = [ 16 | glslify(), 17 | json(), 18 | commonjs(), 19 | nodeResolve(), 20 | sourcemaps(), 21 | ] 22 | 23 | export default [ 24 | { 25 | input: `index.js`, 26 | output: { 27 | file: 'dist/index.js', 28 | format: 'iife', 29 | }, 30 | plugins: [ 31 | copy({ 32 | targets: [ 33 | { src: `index.html`, dest: `dist` }, 34 | { src: `assets`, dest: `dist` }, 35 | ], 36 | }), 37 | ...sharedPlugins, 38 | ], 39 | }, 40 | ...exampleInputs.map((input) => ({ 41 | input: `src/${input}`, 42 | output: { 43 | dir: `dist/${input}`, 44 | format: 'iife', 45 | }, 46 | plugins: [ 47 | copy({ 48 | targets: [{ src: `src/${input}/index.html`, dest: `dist/${input}` }], 49 | }), 50 | ...sharedPlugins, 51 | ], 52 | })), 53 | ] 54 | -------------------------------------------------------------------------------- /docs/examples/src/deferred-shading/base.frag: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform sampler2D texture; 4 | 5 | #ifdef INCLUDE_UVS 6 | varying vec2 v_uv; 7 | #endif 8 | 9 | #ifdef USE_FXAA 10 | 11 | uniform vec2 resolution; 12 | 13 | void texcoords(vec2 fragCoord, vec2 resolution, 14 | out vec2 v_rgbNW, out vec2 v_rgbNE, 15 | out vec2 v_rgbSW, out vec2 v_rgbSE, 16 | out vec2 v_rgbM) { 17 | vec2 inverseVP = 1.0 / resolution.xy; 18 | v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; 19 | v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; 20 | v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; 21 | v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; 22 | v_rgbM = vec2(fragCoord * inverseVP); 23 | } 24 | 25 | #ifndef FXAA_REDUCE_MIN 26 | #define FXAA_REDUCE_MIN (1.0/ 128.0) 27 | #endif 28 | #ifndef FXAA_REDUCE_MUL 29 | #define FXAA_REDUCE_MUL (1.0 / 8.0) 30 | #endif 31 | #ifndef FXAA_SPAN_MAX 32 | #define FXAA_SPAN_MAX 8.0 33 | #endif 34 | 35 | //optimized version for mobile, where dependent 36 | //texture reads can be a bottleneck 37 | vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, 38 | vec2 v_rgbNW, vec2 v_rgbNE, 39 | vec2 v_rgbSW, vec2 v_rgbSE, 40 | vec2 v_rgbM) { 41 | vec4 color; 42 | mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); 43 | vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; 44 | vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; 45 | vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; 46 | vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; 47 | vec4 texColor = texture2D(tex, v_rgbM); 48 | vec3 rgbM = texColor.xyz; 49 | vec3 luma = vec3(0.299, 0.587, 0.114); 50 | float lumaNW = dot(rgbNW, luma); 51 | float lumaNE = dot(rgbNE, luma); 52 | float lumaSW = dot(rgbSW, luma); 53 | float lumaSE = dot(rgbSE, luma); 54 | float lumaM = dot(rgbM, luma); 55 | float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); 56 | float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); 57 | 58 | mediump vec2 dir; 59 | dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); 60 | dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); 61 | 62 | float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * 63 | (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); 64 | 65 | float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); 66 | dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), 67 | max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), 68 | dir * rcpDirMin)) * inverseVP; 69 | 70 | vec3 rgbA = 0.5 * ( 71 | texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + 72 | texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); 73 | vec3 rgbB = rgbA * 0.5 + 0.25 * ( 74 | texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + 75 | texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); 76 | 77 | float lumaB = dot(rgbB, luma); 78 | if ((lumaB < lumaMin) || (lumaB > lumaMax)) { 79 | color = vec4(rgbA, texColor.a); 80 | } else { 81 | color = vec4(rgbB, texColor.a); 82 | } 83 | return color; 84 | } 85 | 86 | vec4 applyFXAA(sampler2D tex, vec2 fragCoord, vec2 resolution) { 87 | mediump vec2 v_rgbNW; 88 | mediump vec2 v_rgbNE; 89 | mediump vec2 v_rgbSW; 90 | mediump vec2 v_rgbSE; 91 | mediump vec2 v_rgbM; 92 | 93 | //compute the texture coords 94 | texcoords(fragCoord, resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); 95 | 96 | //compute FXAA 97 | return fxaa(tex, fragCoord, resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); 98 | } 99 | 100 | #endif 101 | 102 | 103 | #ifdef IS_DEPTH_TEXTURE 104 | const float near_plane = 0.1; 105 | const float far_plane = 100.0; 106 | 107 | float LinearizeDepth(float depth) { 108 | float z = depth * 2.0 - 1.0; // Back to NDC 109 | return (2.0 * near_plane * far_plane) / (far_plane + near_plane - z * (far_plane - near_plane)); 110 | } 111 | #endif 112 | 113 | void main () { 114 | #ifdef USE_FXAA 115 | vec2 fragCoord = v_uv * resolution; 116 | gl_FragColor = applyFXAA(texture, fragCoord, resolution); 117 | #else 118 | #ifdef IS_DEPTH_TEXTURE 119 | float depthValue = texture2D(texture, v_uv).r; 120 | float debugDepth = LinearizeDepth(depthValue) / far_plane; 121 | gl_FragColor = vec4(vec3(debugDepth), 1.0); 122 | #else 123 | gl_FragColor = texture2D(texture, v_uv); 124 | #endif 125 | #endif 126 | } 127 | -------------------------------------------------------------------------------- /docs/examples/src/deferred-shading/base.vert: -------------------------------------------------------------------------------- 1 | attribute vec4 position; 2 | 3 | #ifdef INCLUDE_UVS 4 | attribute vec2 uv; 5 | 6 | #endif 7 | 8 | varying vec2 v_uv; 9 | 10 | void main () { 11 | gl_Position = projectionMatrix * viewMatrix * modelMatrix * position; 12 | 13 | #ifdef INCLUDE_UVS 14 | v_uv = uv; 15 | #endif 16 | } 17 | -------------------------------------------------------------------------------- /docs/examples/src/deferred-shading/directional-lighting.frag: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform vec2 resolution; 4 | uniform sampler2D positionTexture; 5 | uniform sampler2D normalTexture; 6 | uniform sampler2D colorTexture; 7 | uniform vec3 lightDirection; 8 | uniform float lightFactor; 9 | 10 | void main () { 11 | vec2 fragCoord = gl_FragCoord.xy / resolution; 12 | 13 | // vec3 position = texture2D(positionTexture, fragCoord).xyz; 14 | vec3 normal = normalize(texture2D(normalTexture, fragCoord).xyz); 15 | vec3 color = texture2D(colorTexture, fragCoord).xyz; 16 | 17 | float light = dot(normal, lightDirection); 18 | gl_FragColor = vec4(color * light * lightFactor, 1.0); 19 | } 20 | -------------------------------------------------------------------------------- /docs/examples/src/deferred-shading/gbuffer.frag: -------------------------------------------------------------------------------- 1 | #extension GL_EXT_draw_buffers : require 2 | 3 | precision highp float; 4 | 5 | varying vec3 v_color; 6 | varying vec3 v_normal; 7 | varying vec3 v_position; 8 | 9 | void main () { 10 | 11 | gl_FragData[0] = vec4(v_position, 0.0); 12 | gl_FragData[1] = vec4(normalize(v_normal.xyz), 0.0); 13 | gl_FragData[2] = vec4(v_color, 0.0); 14 | } 15 | -------------------------------------------------------------------------------- /docs/examples/src/deferred-shading/gbuffer.vert: -------------------------------------------------------------------------------- 1 | attribute vec4 position; 2 | attribute vec3 color; 3 | attribute vec3 normal; 4 | attribute mat4 instanceModelMatrix; 5 | 6 | varying vec3 v_color; 7 | varying vec3 v_normal; 8 | varying vec3 v_position; 9 | 10 | void main () { 11 | vec4 worldPosition = modelMatrix * instanceModelMatrix * position; 12 | 13 | gl_Position = projectionMatrix * viewMatrix * worldPosition; 14 | 15 | v_color = color; 16 | v_normal = (modelMatrix * vec4(normal, 1.0)).xyz; 17 | v_position = worldPosition.xyz; 18 | } 19 | -------------------------------------------------------------------------------- /docs/examples/src/deferred-shading/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | GLTF 8 | 34 | 35 | 36 |
37 | 40 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /docs/examples/src/deferred-shading/point-lighting.frag: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | struct PointLightBase { 4 | vec3 shininessSpecularRadius; 5 | vec3 position; 6 | vec3 color; 7 | }; 8 | 9 | uniform sampler2D positionTexture; 10 | uniform sampler2D normalTexture; 11 | uniform sampler2D colorTexture; 12 | uniform vec3 eyePosition; 13 | uniform vec2 resolution; 14 | uniform PointLightBase PointLight; 15 | 16 | void main () { 17 | vec2 fragCoord = gl_FragCoord.xy / resolution; 18 | 19 | vec3 position = texture2D(positionTexture, fragCoord).xyz; 20 | vec3 normal = normalize(texture2D(normalTexture, fragCoord).xyz); 21 | vec3 color = texture2D(colorTexture, fragCoord).xyz; 22 | 23 | vec4 baseColor = vec4(color, 1.0); 24 | 25 | vec3 eyeDirection = normalize(eyePosition - position); 26 | vec3 lightVec = PointLight.position - position; 27 | 28 | float shininess = PointLight.shininessSpecularRadius.x; 29 | float lightR = PointLight.shininessSpecularRadius.z; 30 | 31 | float dist = distance(PointLight.position, position) * 2.0; 32 | if(dist < lightR){ 33 | float attenuation = dist / (1.0 - (dist / lightR) * (dist / lightR)); 34 | attenuation = attenuation / lightR + 1.0; 35 | attenuation = 1.0 / (attenuation * attenuation); 36 | 37 | // float diffuse = abs(dot(normal, normalize(lightVec))); 38 | vec3 lightDirection = normalize(lightVec); 39 | vec3 reflectionDirection = reflect(-lightDirection, normal); 40 | float nDotL = max(dot(lightDirection, normal), 0.0); 41 | vec3 diffuse = nDotL * PointLight.color; 42 | 43 | gl_FragColor = vec4(diffuse * PointLight.color * baseColor.rgb * attenuation * shininess, baseColor.a); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /docs/examples/src/directional-light/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Geometry 8 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/examples/src/environment-map/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Geometry 8 | 9 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /docs/examples/src/fog/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Geometry 8 | 9 | 68 | 69 | 70 | 71 | 72 |
73 |
74 |
75 |

Linear Fog

76 |

Fog that grows linearly denser with the distance

77 |
78 |
79 |
80 |
81 |

Exponential Squared Fog

82 |

Fog exponentially densening with the distance

83 |
84 |
85 |
86 | 87 | 88 | -------------------------------------------------------------------------------- /docs/examples/src/geometry/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Geometry 8 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/examples/src/gltf/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | GLTF 8 | 18 | 19 | 20 |
21 | 22 | 23 | -------------------------------------------------------------------------------- /docs/examples/src/godrays/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Godrays 8 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/examples/src/gpgpu-fluid/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | GPGPU Particles 8 | 32 | 33 | 34 |
35 |
36 | 37 | 38 | -------------------------------------------------------------------------------- /docs/examples/src/gpgpu-particles/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | GPGPU Particles 8 | 34 | 35 | 36 |
37 |
38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /docs/examples/src/images/cubemap/negx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/src/images/cubemap/negx.jpg -------------------------------------------------------------------------------- /docs/examples/src/images/cubemap/negy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/src/images/cubemap/negy.jpg -------------------------------------------------------------------------------- /docs/examples/src/images/cubemap/negz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/src/images/cubemap/negz.jpg -------------------------------------------------------------------------------- /docs/examples/src/images/cubemap/posx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/src/images/cubemap/posx.jpg -------------------------------------------------------------------------------- /docs/examples/src/images/cubemap/posy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/src/images/cubemap/posy.jpg -------------------------------------------------------------------------------- /docs/examples/src/images/cubemap/posz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/src/images/cubemap/posz.jpg -------------------------------------------------------------------------------- /docs/examples/src/images/tekken2-cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/src/images/tekken2-cover.jpg -------------------------------------------------------------------------------- /docs/examples/src/images/texture-example.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/src/images/texture-example.jpg -------------------------------------------------------------------------------- /docs/examples/src/images/webgl-logo-pot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnikoloff/hwoa-rang-gl/a2698da07f7e98292e91ebc03640a6994cd4b413/docs/examples/src/images/webgl-logo-pot.png -------------------------------------------------------------------------------- /docs/examples/src/instanced-geometry/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Geometry 8 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/examples/src/instanced-geometry/index.js: -------------------------------------------------------------------------------- 1 | import Stats from 'stats-js' 2 | import throttle from 'lodash.throttle' 3 | 4 | import { vec3, vec4, mat4 } from 'gl-matrix' 5 | 6 | import { 7 | PerspectiveCamera, 8 | Geometry, 9 | GeometryUtils, 10 | InstancedMesh, 11 | } from '../../../../dist/esm' 12 | 13 | const BOXES_X_COUNT = 12 14 | const BOXES_Y_COUNT = 12 15 | const BOXES_COUNT = BOXES_X_COUNT * BOXES_Y_COUNT 16 | 17 | const dpr = Math.min(devicePixelRatio, 2) 18 | const canvas = document.createElement('canvas') 19 | const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl') 20 | 21 | const stats = new Stats() 22 | document.body.appendChild(stats.domElement) 23 | 24 | let mouseX = 0 25 | let mouseY = 0 26 | 27 | gl.enable(gl.BLEND) 28 | gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) 29 | gl.enable(gl.DEPTH_TEST) 30 | // gl.enable(gl.CULL_FACE) 31 | gl.depthFunc(gl.LEQUAL) 32 | 33 | const camera = new PerspectiveCamera( 34 | (45 * Math.PI) / 180, 35 | innerWidth / innerHeight, 36 | 0.1, 37 | 100, 38 | ) 39 | camera.position = [0, 0, 10] 40 | camera.lookAt([0, 0, 0]) 41 | 42 | const { indices, vertices, uv } = GeometryUtils.createBox() 43 | const geometry = new Geometry(gl) 44 | geometry 45 | .addIndex({ typedArray: indices }) 46 | .addAttribute('position', { 47 | typedArray: vertices, 48 | size: 3, 49 | }) 50 | .addAttribute('uv', { 51 | typedArray: uv, 52 | size: 2, 53 | }) 54 | const mesh = new InstancedMesh(gl, { 55 | geometry, 56 | instanceCount: BOXES_COUNT, 57 | vertexShaderSource: ` 58 | attribute vec4 position; 59 | attribute vec2 uv; 60 | attribute mat4 instanceModelMatrix; 61 | 62 | varying vec2 v_uv; 63 | 64 | void main () { 65 | gl_Position = projectionMatrix * 66 | viewMatrix * 67 | modelMatrix * 68 | instanceModelMatrix * 69 | position; 70 | v_uv = uv; 71 | } 72 | `, 73 | fragmentShaderSource: ` 74 | varying vec2 v_uv; 75 | void main () { 76 | gl_FragColor = vec4(0.0, v_uv, 1.0); 77 | } 78 | `, 79 | }) 80 | 81 | mesh.use() 82 | 83 | const matrix = mat4.create() 84 | const translateVec = vec3.create() 85 | const scaleVec = vec4.create() 86 | 87 | document.body.addEventListener('mousemove', (e) => { 88 | mouseX = (e.pageX / innerWidth) * BOXES_X_COUNT - BOXES_X_COUNT / 2 89 | mouseY = (1 - e.pageY / innerHeight) * BOXES_Y_COUNT - BOXES_Y_COUNT / 2 90 | }) 91 | document.body.addEventListener('touchmove', (e) => { 92 | e.preventDefault() 93 | mouseX = (e.changedTouches[0].pageX / innerWidth) * 8 - 4 94 | mouseY = (1 - e.changedTouches[0].pageY / innerHeight) * 10 - 5 95 | }) 96 | document.body.appendChild(canvas) 97 | requestAnimationFrame(updateFrame) 98 | sizeCanvas() 99 | window.addEventListener('resize', throttle(resize, 100)) 100 | 101 | function updateFrame() { 102 | stats.begin() 103 | 104 | gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight) 105 | gl.clearColor(0.9, 0.9, 0.9, 1) 106 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) 107 | 108 | for (let i = 0; i < BOXES_COUNT; i++) { 109 | const x = (i % BOXES_X_COUNT) - BOXES_X_COUNT / 2 110 | const y = (i - x) / BOXES_Y_COUNT - BOXES_X_COUNT / 2 111 | 112 | const dx = mouseX - x 113 | const dy = mouseY - y 114 | 115 | const angle = Math.atan2(dx, dy) 116 | const dist = Math.sqrt(dx * dx + dy * dy) 117 | 118 | 119 | mat4.identity(matrix) 120 | vec3.set(translateVec, x, y, dist * 0.3) 121 | mat4.translate(matrix, matrix, translateVec) 122 | mat4.rotateX(matrix, matrix, angle) 123 | mat4.rotateZ(matrix, matrix, angle) 124 | 125 | const scale = dist * 0.1 126 | vec3.set(scaleVec, scale, scale, scale) 127 | mat4.scale(matrix, matrix, scaleVec) 128 | mesh.setMatrixAt(i, matrix) 129 | } 130 | 131 | mesh.setCamera(camera).draw() 132 | 133 | stats.end() 134 | 135 | requestAnimationFrame(updateFrame) 136 | } 137 | 138 | function resize() { 139 | camera.aspect = innerWidth / innerHeight 140 | camera.updateProjectionMatrix() 141 | 142 | sizeCanvas() 143 | } 144 | 145 | function sizeCanvas() { 146 | canvas.width = innerWidth * dpr 147 | canvas.height = innerHeight * dpr 148 | canvas.style.setProperty('width', `${innerWidth}px`) 149 | canvas.style.setProperty('height', `${innerHeight}px`) 150 | } 151 | -------------------------------------------------------------------------------- /docs/examples/src/mouse-picking/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Mousepicking 8 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/examples/src/multi-texture/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Multi Face Texture 8 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/examples/src/multi-texture/index.js: -------------------------------------------------------------------------------- 1 | import Stats from 'stats-js' 2 | import throttle from 'lodash.throttle' 3 | 4 | import { 5 | PerspectiveCamera, 6 | CameraController, 7 | Geometry, 8 | GeometryUtils, 9 | Mesh, 10 | Texture, 11 | UNIFORM_TYPE_INT, 12 | } from '../../../../dist/esm' 13 | 14 | const stats = new Stats() 15 | document.body.appendChild(stats.domElement) 16 | 17 | const dpr = Math.min(devicePixelRatio, 2) 18 | const canvas = document.createElement('canvas') 19 | const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl') 20 | 21 | const colors = [ 22 | '#2ecc71', 23 | '#e67e22', 24 | '#f1c40f', 25 | '#2980b9', 26 | '#c0392b', 27 | '#34495e', 28 | ] 29 | const textures = [] 30 | const meshes = [] 31 | 32 | gl.enable(gl.BLEND) 33 | gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) 34 | gl.enable(gl.DEPTH_TEST) 35 | // gl.enable(gl.CULL_FACE) 36 | // gl.depthFunc(gl.LEQUAL) 37 | 38 | const camera = new PerspectiveCamera( 39 | (45 * Math.PI) / 180, 40 | innerWidth / innerHeight, 41 | 0.1, 42 | 100, 43 | ) 44 | camera.position = [20, 20, 20] 45 | camera.lookAt([0, 0, 0]) 46 | 47 | new CameraController(camera, canvas) 48 | 49 | const sidesData = GeometryUtils.createBox({ 50 | width: 10, 51 | height: 10, 52 | depth: 10, 53 | separateFaces: true, 54 | }) 55 | for (let i = 0; i < sidesData.length; i++) { 56 | const side = sidesData[i] 57 | const geometry = new Geometry(gl) 58 | 59 | const { indices, vertices, uv } = side 60 | 61 | geometry 62 | .addIndex({ 63 | typedArray: indices, 64 | }) 65 | .addAttribute('position', { 66 | typedArray: vertices, 67 | size: 3, 68 | }) 69 | .addAttribute('uv', { 70 | typedArray: uv, 71 | size: 2, 72 | }) 73 | 74 | const mesh = new Mesh(gl, { 75 | geometry, 76 | uniforms: { 77 | diffuse: { type: UNIFORM_TYPE_INT, value: 0 }, 78 | }, 79 | vertexShaderSource: ` 80 | attribute vec4 position; 81 | attribute vec2 uv; 82 | 83 | varying vec2 v_uv; 84 | 85 | void main () { 86 | gl_Position = projectionMatrix * viewMatrix * modelMatrix * position; 87 | v_uv = uv; 88 | } 89 | `, 90 | fragmentShaderSource: ` 91 | uniform sampler2D diffuse; 92 | 93 | varying vec2 v_uv; 94 | 95 | void main () { 96 | gl_FragColor = texture2D(diffuse, v_uv); 97 | } 98 | `, 99 | }) 100 | meshes.push(mesh) 101 | 102 | const tex = new Texture(gl, { 103 | minFilter: gl.LINEAR_MIPMAP_LINEAR, 104 | magFilter: gl.LINEAR, 105 | }) 106 | .bind() 107 | .setIsFlip() 108 | .fromImage(createNumCanvas(i)) 109 | .generateMipmap() 110 | 111 | textures.push(tex) 112 | } 113 | 114 | document.body.appendChild(canvas) 115 | requestAnimationFrame(updateFrame) 116 | sizeCanvas() 117 | window.addEventListener('resize', throttle(resize, 100)) 118 | 119 | function updateFrame() { 120 | stats.begin() 121 | 122 | gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight) 123 | gl.clearColor(0.9, 0.9, 0.9, 1) 124 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) 125 | 126 | meshes.forEach((mesh, i) => { 127 | const texture = textures[i] 128 | texture.bind() 129 | mesh.use().setCamera(camera).draw() 130 | texture.unbind() 131 | }) 132 | 133 | stats.end() 134 | 135 | requestAnimationFrame(updateFrame) 136 | } 137 | 138 | function resize() { 139 | camera.aspect = innerWidth / innerHeight 140 | camera.updateProjectionMatrix() 141 | 142 | sizeCanvas() 143 | } 144 | 145 | function sizeCanvas() { 146 | canvas.width = innerWidth * dpr 147 | canvas.height = innerHeight * dpr 148 | canvas.style.setProperty('width', `${innerWidth}px`) 149 | canvas.style.setProperty('height', `${innerHeight}px`) 150 | } 151 | 152 | function createNumCanvas(num) { 153 | const canvas = document.createElement('canvas') 154 | const ctx = canvas.getContext('2d') 155 | canvas.width = 512 156 | canvas.height = 512 157 | // document.body.appendChild(canvas) 158 | // canvas.setAttribute( 159 | // 'style', 160 | // ` 161 | // position: fixed; 162 | // top: 24px; 163 | // left: 24px; 164 | // z-index: 999; 165 | // `, 166 | // ) 167 | 168 | ctx.fillStyle = colors[num] 169 | ctx.fillRect(0, 0, canvas.width, canvas.height) 170 | 171 | ctx.font = '256px Arial' 172 | ctx.fillStyle = 'white' 173 | ctx.textAlign = 'center' 174 | ctx.fillText(num + 1, canvas.width / 2, canvas.height / 2 + 76) 175 | return canvas 176 | } 177 | -------------------------------------------------------------------------------- /docs/examples/src/particles-01/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Particles 01 8 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/examples/src/particles-01/index.js: -------------------------------------------------------------------------------- 1 | import Stats from 'stats-js' 2 | import throttle from 'lodash.throttle' 3 | 4 | import { 5 | PerspectiveCamera, 6 | Mesh, 7 | Geometry, 8 | UNIFORM_TYPE_FLOAT, 9 | } from '../../../../dist/esm' 10 | 11 | const PARTICLE_COUNT = 500 12 | 13 | const stats = new Stats() 14 | document.body.appendChild(stats.domElement) 15 | 16 | const dpr = Math.min(devicePixelRatio, 2) 17 | const canvas = document.createElement('canvas') 18 | const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl') 19 | 20 | let oldTime = 0 21 | let spacing = 1 22 | let spacingTarget = spacing 23 | let radius = 10 24 | let radiusTarget = radius 25 | 26 | gl.enable(gl.BLEND) 27 | gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) 28 | 29 | const camera = new PerspectiveCamera( 30 | (45 * Math.PI) / 180, 31 | innerWidth / innerHeight, 32 | 0.1, 33 | 100, 34 | ) 35 | camera.position = [0, 0, 40] 36 | camera.lookAt([0, 0, 0]) 37 | 38 | const vertexArray = new Float32Array(PARTICLE_COUNT).fill(0) 39 | 40 | for (let i = 0; i < PARTICLE_COUNT; i++) { 41 | vertexArray[i] = i 42 | } 43 | 44 | const geometry = new Geometry(gl) 45 | // debugger 46 | geometry.addAttribute('position', { 47 | typedArray: vertexArray, 48 | size: 1, 49 | }) 50 | 51 | const mesh = new Mesh(gl, { 52 | geometry, 53 | vertexShaderSource: ` 54 | uniform float time; 55 | uniform float spacing; 56 | uniform float movementMaxRadius; 57 | 58 | attribute vec4 position; 59 | 60 | const vec4 cameraPosition = vec4(0.0, 0.0, 40.0, 1.0); 61 | 62 | void main () { 63 | gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4( 64 | sin(time + position.x) * movementMaxRadius, 65 | cos(time + position.x) * movementMaxRadius, 66 | cos(time + position.x * spacing * 20.0) * movementMaxRadius, 67 | position.w 68 | ); 69 | 70 | float dist = distance(cameraPosition, gl_Position); 71 | gl_PointSize = dist * 0.225 * ${devicePixelRatio}.0; 72 | } 73 | `, 74 | fragmentShaderSource: ` 75 | void main () { 76 | float dist = distance(gl_PointCoord, vec2(0.5)); 77 | float c = clamp(0.5 - dist, 0.0, 1.0); 78 | gl_FragColor = vec4(vec3(1.0), c); 79 | } 80 | `, 81 | }) 82 | 83 | mesh.use() 84 | mesh.drawMode = gl.POINTS 85 | 86 | document.body.appendChild(canvas) 87 | setInterval(() => { 88 | spacingTarget = Math.random() * 0.85 + 0.15 89 | radiusTarget = 5 + Math.random() * 15 90 | }, 5000) 91 | requestAnimationFrame(updateFrame) 92 | sizeCanvas() 93 | disableScroll() 94 | window.addEventListener('resize', throttle(resize, 100)) 95 | 96 | function updateFrame(ts) { 97 | ts /= 1000 98 | const dt = ts - oldTime 99 | oldTime = ts 100 | 101 | stats.begin() 102 | 103 | gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight) 104 | gl.clearColor(0.9, 0.9, 0.9, 1) 105 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) 106 | 107 | spacing += (spacingTarget - spacing) * (dt * 20) 108 | 109 | radius += (radiusTarget - radius) * (dt * 10) 110 | 111 | mesh 112 | .setCamera(camera) 113 | .setUniform('time', UNIFORM_TYPE_FLOAT, ts) 114 | .setUniform('spacing', UNIFORM_TYPE_FLOAT, spacing) 115 | .setUniform('movementMaxRadius', UNIFORM_TYPE_FLOAT, radius) 116 | .draw() 117 | 118 | stats.end() 119 | 120 | requestAnimationFrame(updateFrame) 121 | } 122 | 123 | function resize() { 124 | camera.aspect = innerWidth / innerHeight 125 | camera.updateProjectionMatrix() 126 | 127 | sizeCanvas() 128 | } 129 | 130 | function sizeCanvas() { 131 | canvas.width = innerWidth * dpr 132 | canvas.height = innerHeight * dpr 133 | canvas.style.setProperty('width', `${innerWidth}px`) 134 | canvas.style.setProperty('height', `${innerHeight}px`) 135 | } 136 | 137 | function preventDefault(e) { 138 | e.preventDefault() 139 | } 140 | 141 | function disableScroll() { 142 | document.body.addEventListener('touchmove', preventDefault, { 143 | passive: false, 144 | }) 145 | } 146 | -------------------------------------------------------------------------------- /docs/examples/src/particles-02/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Particles 01 8 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/examples/src/persistence/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Persistence 8 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/examples/src/point-light/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Point Light 8 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /docs/examples/src/projection-mapping/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Planar Perspective Projection 8 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /docs/examples/src/shadow/base.frag: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform vec4 color; 4 | 5 | void main() { 6 | gl_FragColor = color; 7 | } -------------------------------------------------------------------------------- /docs/examples/src/shadow/base.vert: -------------------------------------------------------------------------------- 1 | attribute vec4 position; 2 | 3 | #ifdef IS_INSTANCED 4 | attribute mat4 instanceModelMatrix; 5 | #endif 6 | 7 | #ifdef USE_PROJECTED_TEXCOORD 8 | uniform mat4 textureMatrix; 9 | 10 | varying vec4 v_projectedTexcoord; 11 | #endif 12 | 13 | #ifdef USE_VARYINGS 14 | attribute vec2 uv; 15 | 16 | varying vec2 v_uv; 17 | #endif 18 | 19 | void main() { 20 | 21 | 22 | #ifdef IS_INSTANCED 23 | vec4 worldPosition = modelMatrix * instanceModelMatrix * position; 24 | #else 25 | vec4 worldPosition = modelMatrix * position; 26 | #endif 27 | 28 | gl_Position = projectionMatrix * viewMatrix * worldPosition; 29 | 30 | #ifdef USE_VARYINGS 31 | v_uv = uv; 32 | #endif 33 | 34 | #ifdef USE_PROJECTED_TEXCOORD 35 | v_projectedTexcoord = textureMatrix * worldPosition; 36 | #endif 37 | } -------------------------------------------------------------------------------- /docs/examples/src/shadow/debug-depth.frag: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform sampler2D depthTex; 4 | 5 | varying vec2 v_uv; 6 | 7 | const float near_plane = 0.1; 8 | const float far_plane = 50.0; 9 | 10 | float LinearizeDepth(float depth) { 11 | float z = depth * 2.0 - 1.0; // Back to NDC 12 | return (2.0 * near_plane * far_plane) / (far_plane + near_plane - z * (far_plane - near_plane)); 13 | } 14 | 15 | void main () { 16 | float depth = texture2D(depthTex, v_uv).r; 17 | gl_FragColor = vec4(vec3(LinearizeDepth(depth) / far_plane), 1.0); 18 | } 19 | -------------------------------------------------------------------------------- /docs/examples/src/shadow/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Planar Perspective Projection 8 | 11 | 12 | 13 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /docs/examples/src/shadow/shaded.frag: -------------------------------------------------------------------------------- 1 | struct SpotLightInfo { 2 | float shininess; 3 | vec3 lightColor; 4 | vec3 specularColor; 5 | vec3 worldPosition; 6 | vec3 lightDirection; 7 | float innerLimit; 8 | float outerLimit; 9 | }; 10 | 11 | uniform SpotLightInfo SpotLight; 12 | uniform float shadowBias; 13 | uniform sampler2D projectedTexture; 14 | uniform vec3 eyePosition; 15 | 16 | varying vec4 v_projectedTexcoord; 17 | varying vec2 v_uv; 18 | varying vec3 v_normal; 19 | varying vec3 v_surfaceToLight; 20 | varying vec3 v_surfaceToView; 21 | 22 | void main () { 23 | // Shadow 24 | vec3 projectedTexcoord = v_projectedTexcoord.xyz / v_projectedTexcoord.w; 25 | float currentDepth = projectedTexcoord.z + shadowBias; 26 | 27 | bool inRange = 28 | projectedTexcoord.x >= 0.0 && 29 | projectedTexcoord.x <= 1.0 && 30 | projectedTexcoord.y >= 0.0 && 31 | projectedTexcoord.y <= 1.0; 32 | 33 | vec4 texColor = vec4(vec3(0.25), 1.0); 34 | float projectedDepth = texture2D(projectedTexture, projectedTexcoord.xy).r; 35 | float shadowLight = (inRange && projectedDepth <= currentDepth) ? 0.0 : 1.0; 36 | 37 | // Spot light 38 | vec3 normal = normalize(v_normal); 39 | vec3 surfaceToLightDirection = normalize(v_surfaceToLight); 40 | vec3 surfaceToViewDirection = normalize(v_surfaceToView); 41 | 42 | vec3 halfVector = normalize(surfaceToLightDirection + surfaceToViewDirection); 43 | 44 | float dotFromDirection = dot(surfaceToLightDirection, -SpotLight.lightDirection); 45 | float limitRange = SpotLight.innerLimit - SpotLight.outerLimit; 46 | float inLight = clamp((dotFromDirection - SpotLight.outerLimit) / limitRange, 0.0, 1.0); 47 | 48 | float light = inLight * dot(normal, surfaceToLightDirection); 49 | float specular = inLight * pow(dot(normal, halfVector), SpotLight.shininess); 50 | 51 | 52 | // gl_FragColor = vec4(texColor.rgb * shadowLight, texColor.a); 53 | 54 | gl_FragColor = vec4( 55 | texColor.rgb * SpotLight.lightColor * light * shadowLight + 56 | specular * SpotLight.specularColor * shadowLight, 57 | texColor.a 58 | ); 59 | } -------------------------------------------------------------------------------- /docs/examples/src/shadow/shaded.vert: -------------------------------------------------------------------------------- 1 | struct SpotLightInfo { 2 | float shininess; 3 | vec3 lightColor; 4 | vec3 specularColor; 5 | vec3 worldPosition; 6 | vec3 lightDirection; 7 | float innerLimit; 8 | float outerLimit; 9 | }; 10 | 11 | uniform SpotLightInfo SpotLight; 12 | uniform mat4 textureMatrix; 13 | uniform vec3 eyePosition; 14 | 15 | attribute vec4 position; 16 | attribute vec2 uv; 17 | attribute vec3 normal; 18 | 19 | #ifdef IS_INSTANCED 20 | attribute mat4 instanceModelMatrix; 21 | #endif 22 | 23 | varying vec4 v_projectedTexcoord; 24 | varying vec2 v_uv; 25 | varying vec3 v_normal; 26 | varying vec3 v_surfaceToLight; 27 | varying vec3 v_surfaceToView; 28 | 29 | void main() { 30 | vec4 worldPosition; 31 | 32 | #ifdef IS_INSTANCED 33 | worldPosition = modelMatrix * instanceModelMatrix * position; 34 | #else 35 | worldPosition = modelMatrix * position; 36 | #endif 37 | 38 | gl_Position = projectionMatrix * viewMatrix * worldPosition; 39 | 40 | v_uv = uv; 41 | v_projectedTexcoord = textureMatrix * worldPosition; 42 | 43 | vec3 surfaceWorldPosition = worldPosition.xyz; 44 | 45 | v_surfaceToLight = SpotLight.worldPosition - surfaceWorldPosition; 46 | v_surfaceToView = eyePosition - surfaceWorldPosition; 47 | v_uv = uv; 48 | v_normal = mat3(modelMatrix) * normal; 49 | } -------------------------------------------------------------------------------- /docs/examples/src/spot-light/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Spot Light 8 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/examples/src/swaprenderer-fluid/add-force.frag: -------------------------------------------------------------------------------- 1 | uniform sampler2D uBase; 2 | uniform vec2 velocity; 3 | uniform vec2 cursor; 4 | uniform vec2 px; 5 | 6 | varying vec2 uv; 7 | varying vec2 vPosition; 8 | 9 | float blendAdd(float base, float blend) { 10 | return min(base+blend,1.0); 11 | } 12 | 13 | vec3 blendAdd(vec3 base, vec3 blend) { 14 | return min(base+blend,vec3(1.0)); 15 | } 16 | 17 | vec3 blendAdd(vec3 base, vec3 blend, float opacity) { 18 | return (blendAdd(base, blend) * opacity + base * (1.0 - opacity)); 19 | } 20 | 21 | void main(){ 22 | float dist = distance(cursor/px, vPosition/px); 23 | vec3 color = texture2D(uBase, uv).rgb; 24 | float dx = 2.0 * px.x; 25 | float dy = 2.0 * px.y; 26 | float marginX = 1.0 - dx; 27 | float marginY = 1.0 - dy; 28 | if(dist < 20. && length(dist) > 0. && uv.x < marginX && uv.x > dx && uv.y < marginY && uv.y > dy){ 29 | color = color - vec3(velocity.xy * 10., 0.0) * clamp(2.0 - dist/40., 0.0, 1.0); 30 | } 31 | gl_FragColor = vec4(color, 1.0); 32 | } 33 | -------------------------------------------------------------------------------- /docs/examples/src/swaprenderer-fluid/advect.frag: -------------------------------------------------------------------------------- 1 | uniform sampler2D source; 2 | uniform sampler2D velocity; 3 | uniform float dt; 4 | uniform float scale; 5 | uniform vec2 px1; 6 | varying vec2 uv; 7 | 8 | void main(){ 9 | gl_FragColor = texture2D(source, uv-texture2D(velocity, uv).xy * dt * px1) * scale; 10 | } 11 | -------------------------------------------------------------------------------- /docs/examples/src/swaprenderer-fluid/base.vert: -------------------------------------------------------------------------------- 1 | attribute vec4 position; 2 | 3 | uniform vec2 px; 4 | varying vec2 uv; 5 | varying vec2 vL; 6 | varying vec2 vR; 7 | varying vec2 vT; 8 | varying vec2 vB; 9 | 10 | void main(){ 11 | gl_Position = projectionMatrix * viewMatrix * modelMatrix * position; 12 | 13 | uv = vec2(0.5)+(gl_Position.xy)*0.5; 14 | vL = uv - vec2(px.x, 0.0); 15 | vR = uv + vec2(px.x, 0.0); 16 | vT = uv + vec2(0.0, px.y); 17 | vB = uv - vec2(0.0, px.y); 18 | } 19 | -------------------------------------------------------------------------------- /docs/examples/src/swaprenderer-fluid/clear.frag: -------------------------------------------------------------------------------- 1 | uniform sampler2D pressure; 2 | uniform float value; 3 | 4 | varying vec2 uv; 5 | void main () { 6 | gl_FragColor = value * texture2D(pressure, uv); 7 | } 8 | -------------------------------------------------------------------------------- /docs/examples/src/swaprenderer-fluid/curl.frag: -------------------------------------------------------------------------------- 1 | uniform sampler2D velocity; 2 | 3 | varying vec2 uv; 4 | varying vec2 vL; 5 | varying vec2 vR; 6 | varying vec2 vT; 7 | varying vec2 vB; 8 | 9 | void main () { 10 | float L = texture2D(velocity, vL).y; 11 | float R = texture2D(velocity, vR).y; 12 | float T = texture2D(velocity, vT).x; 13 | float B = texture2D(velocity, vB).x; 14 | float vorticity = R - L - T + B; 15 | gl_FragColor = vec4(0.5 * vorticity, 0.0, 0.0, 1.0); 16 | } 17 | -------------------------------------------------------------------------------- /docs/examples/src/swaprenderer-fluid/cursor.vert: -------------------------------------------------------------------------------- 1 | uniform vec2 cursor; 2 | uniform vec2 px; 3 | 4 | attribute vec4 position; 5 | 6 | varying vec2 vPosition; 7 | varying vec2 uv; 8 | 9 | void main(){ 10 | gl_Position = projectionMatrix * viewMatrix * modelMatrix * position; 11 | vPosition = gl_Position.xy; 12 | uv = vec2(0.5) + (gl_Position.xy) * 0.5; 13 | } 14 | -------------------------------------------------------------------------------- /docs/examples/src/swaprenderer-fluid/divergence.frag: -------------------------------------------------------------------------------- 1 | precision mediump sampler2D; 2 | uniform sampler2D velocity; 3 | 4 | varying highp vec2 uv; 5 | varying highp vec2 vL; 6 | varying highp vec2 vR; 7 | varying highp vec2 vT; 8 | varying highp vec2 vB; 9 | 10 | void main () { 11 | float L = texture2D(velocity, vL).x; 12 | float R = texture2D(velocity, vR).x; 13 | float T = texture2D(velocity, vT).y; 14 | float B = texture2D(velocity, vB).y; 15 | vec2 C = texture2D(velocity, uv).xy; 16 | 17 | if (vL.x < 0.0) { L = -C.x; } 18 | if (vR.x > 1.0) { R = -C.x; } 19 | if (vT.y > 1.0) { T = -C.y; } 20 | if (vB.y < 0.0) { B = -C.y; } 21 | 22 | float div = 0.5 * (R - L + T - B); 23 | gl_FragColor = vec4(div, 0.0, 0.0, 1.0); 24 | } 25 | -------------------------------------------------------------------------------- /docs/examples/src/swaprenderer-fluid/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | GPGPU Particles 8 | 33 | 34 | 35 | 36 | 37 | 45 | 46 |
47 | 48 | 49 | -------------------------------------------------------------------------------- /docs/examples/src/swaprenderer-fluid/jacobi.frag: -------------------------------------------------------------------------------- 1 | uniform sampler2D pressure; 2 | uniform sampler2D divergence; 3 | uniform float alpha; 4 | uniform float beta; 5 | uniform vec2 px; 6 | varying vec2 uv; 7 | 8 | varying highp vec2 vL; 9 | varying highp vec2 vR; 10 | varying highp vec2 vT; 11 | varying highp vec2 vB; 12 | 13 | void main(){ 14 | float x0 = texture2D(pressure, vL).r; 15 | float x1 = texture2D(pressure, vR).r; 16 | float y0 = texture2D(pressure, vT).r; 17 | float y1 = texture2D(pressure, vB).r; 18 | float d = texture2D(divergence, uv).r; 19 | 20 | float relaxed = (x0 + x1 + y0 + y1 + alpha * d) * beta; 21 | gl_FragColor = vec4(relaxed); 22 | } -------------------------------------------------------------------------------- /docs/examples/src/swaprenderer-fluid/subtract-pressure-gradient.frag: -------------------------------------------------------------------------------- 1 | uniform sampler2D pressure; 2 | uniform sampler2D velocity; 3 | uniform float scale; 4 | uniform vec2 px; 5 | 6 | varying vec2 uv; 7 | 8 | void main(){ 9 | float x0 = texture2D(pressure, uv-vec2(px.x, 0)).r; 10 | float x1 = texture2D(pressure, uv+vec2(px.x, 0)).r; 11 | float y0 = texture2D(pressure, uv-vec2(0, px.y)).r; 12 | float y1 = texture2D(pressure, uv+vec2(0, px.y)).r; 13 | vec2 v = texture2D(velocity, uv).xy; 14 | vec4 v2 = vec4((v-(vec2(x1, y1)-vec2(x0, y0))*0.5) * scale, 1.0, 1.0); 15 | 16 | gl_FragColor = v2; 17 | } 18 | -------------------------------------------------------------------------------- /docs/examples/src/swaprenderer-fluid/visualise.frag: -------------------------------------------------------------------------------- 1 | uniform sampler2D velocity; 2 | uniform sampler2D pressure; 3 | 4 | uniform sampler2D sceneTexture; 5 | 6 | uniform float uAlpha; 7 | 8 | uniform vec2 px1; 9 | varying vec2 uv; 10 | 11 | void main(){ 12 | vec2 vel = texture2D(velocity, uv).xy * 0.5 + vec2(0.5); 13 | float pre = 0.5 - texture2D(pressure, uv).x * 0.5; 14 | 15 | vec4 color = vec4(vel, pre, 0.0); 16 | vec4 baseColor = texture2D(sceneTexture, uv + vel * 0.5 - 0.25); 17 | 18 | gl_FragColor = baseColor; 19 | } 20 | -------------------------------------------------------------------------------- /docs/examples/src/swaprenderer-fluid/vorticity.frag: -------------------------------------------------------------------------------- 1 | uniform sampler2D velocity; 2 | uniform sampler2D uCurl; 3 | uniform float curl; 4 | uniform float dt; 5 | 6 | varying vec2 uv; 7 | varying vec2 vL; 8 | varying vec2 vR; 9 | varying vec2 vT; 10 | varying vec2 vB; 11 | 12 | void main () { 13 | float L = texture2D(uCurl, vL).x; 14 | float R = texture2D(uCurl, vR).x; 15 | float T = texture2D(uCurl, vT).x; 16 | float B = texture2D(uCurl, vB).x; 17 | float C = texture2D(uCurl, uv).x; 18 | vec2 force = 0.5 * vec2(abs(T) - abs(B), abs(R) - abs(L)); 19 | force /= length(force) + 0.0001; 20 | force *= curl * C; 21 | force.y *= -1.0; 22 | vec2 vel = texture2D(velocity, uv).xy; 23 | gl_FragColor = vec4(vel + force * dt, 0.0, 1.0); 24 | } 25 | -------------------------------------------------------------------------------- /docs/examples/src/swaprenderer-image/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | GPGPU Particles 8 | 33 | 34 | 35 |
36 |
Photo by Zhang Kaiyv
37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /docs/examples/src/swaprenderer-noise-texture/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | GPGPU Particles 8 | 34 | 35 | 36 |
37 |
38 | 39 | 40 | -------------------------------------------------------------------------------- /docs/examples/src/text/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Text 8 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /docs/examples/src/texture/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Texture 8 | 18 | 19 | 20 |
Photo by Zhang Kaiyv
21 | 22 | 23 | -------------------------------------------------------------------------------- /docs/examples/src/texture/index.js: -------------------------------------------------------------------------------- 1 | import Stats from 'stats-js' 2 | import * as dat from 'dat.gui' 3 | import throttle from 'lodash.throttle' 4 | 5 | import { 6 | PerspectiveCamera, 7 | CameraController, 8 | Geometry, 9 | GeometryUtils, 10 | Mesh, 11 | Texture, 12 | getExtension, 13 | UNIFORM_TYPE_INT, 14 | } from '../../../../dist/esm' 15 | 16 | const gui = new dat.GUI() 17 | gui.width = 420 18 | 19 | const stats = new Stats() 20 | document.body.appendChild(stats.domElement) 21 | 22 | const dpr = Math.min(devicePixelRatio, 2) 23 | const canvas = document.createElement('canvas') 24 | const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl') 25 | 26 | const OPTIONS = { 27 | minFilter: 'LINEAR', 28 | magFilter: 'LINEAR', 29 | // anisotropy: 0, 30 | } 31 | 32 | gl.enable(gl.BLEND) 33 | gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) 34 | gl.enable(gl.DEPTH_TEST) 35 | 36 | const camera = new PerspectiveCamera( 37 | (45 * Math.PI) / 180, 38 | innerWidth / innerHeight, 39 | 0.1, 40 | 100, 41 | ) 42 | camera.position = [0, 0, 26] 43 | camera.lookAt([0, 0, 0]) 44 | 45 | new CameraController(camera, canvas) 46 | 47 | const { indices, vertices, uv } = GeometryUtils.createPlane({ 48 | width: 16, 49 | height: 16, 50 | }) 51 | const geometry = new Geometry(gl) 52 | geometry 53 | .addIndex({ typedArray: indices }) 54 | .addAttribute('position', { 55 | typedArray: vertices, 56 | size: 3, 57 | }) 58 | .addAttribute('uv', { 59 | typedArray: uv, 60 | size: 2, 61 | }) 62 | 63 | const mesh = new Mesh(gl, { 64 | geometry, 65 | uniforms: { 66 | diffuse: { type: UNIFORM_TYPE_INT, value: 0 }, 67 | }, 68 | vertexShaderSource: ` 69 | attribute vec4 position; 70 | attribute vec2 uv; 71 | 72 | varying vec2 v_uv; 73 | 74 | void main () { 75 | gl_Position = projectionMatrix * viewMatrix * modelMatrix * position; 76 | v_uv = uv; 77 | } 78 | `, 79 | fragmentShaderSource: ` 80 | uniform sampler2D diffuse; 81 | 82 | varying vec2 v_uv; 83 | 84 | void main () { 85 | gl_FragColor = texture2D(diffuse, v_uv); 86 | } 87 | `, 88 | }) 89 | 90 | mesh.use() 91 | 92 | const texture = new Texture(gl).bind().fromSize(1, 1).setIsFlip() 93 | 94 | const image = new Image() 95 | image.onload = () => { 96 | texture.fromImage(image).generateMipmap().setAnisotropy(1) 97 | } 98 | image.src = window.location.href.includes('github') 99 | ? '/hwoa-rang-gl/examples/dist/assets/textures/zhang-kaiyv-mh2o8DuHaMM-unsplash.png' 100 | : '/examples/dist/assets/textures/zhang-kaiyv-mh2o8DuHaMM-unsplash.png' 101 | 102 | document.body.appendChild(canvas) 103 | requestAnimationFrame(updateFrame) 104 | sizeCanvas() 105 | window.addEventListener('resize', throttle(resize, 100)) 106 | 107 | gui 108 | .add(OPTIONS, 'minFilter', [ 109 | 'NEAREST', 110 | 'LINEAR', 111 | 'NEAREST_MIPMAP_NEAREST', 112 | 'NEAREST_MIPMAP_LINEAR', 113 | 'LINEAR_MIPMAP_NEAREST', 114 | 'LINEAR_MIPMAP_LINEAR', 115 | ]) 116 | .onChange((val) => { 117 | texture.setMinFilter(gl[val]) 118 | }) 119 | gui.add(OPTIONS, 'magFilter', ['NEAREST', 'LINEAR']).onChange((val) => { 120 | texture.setMinFilter(gl[val]) 121 | }) 122 | 123 | { 124 | getExtension(gl, 'EXT_texture_filter_anisotropic') || 125 | getExtension(gl, 'MOZ_EXT_texture_filter_anisotropic') || 126 | getExtension(gl, 'WEBKIT_EXT_texture_filter_anisotropic') 127 | } 128 | 129 | function updateFrame() { 130 | stats.begin() 131 | 132 | gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight) 133 | gl.clearColor(0.9, 0.9, 0.9, 1) 134 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) 135 | 136 | mesh.setCamera(camera).draw() 137 | 138 | stats.end() 139 | 140 | requestAnimationFrame(updateFrame) 141 | } 142 | 143 | function resize() { 144 | camera.aspect = innerWidth / innerHeight 145 | camera.updateProjectionMatrix() 146 | 147 | sizeCanvas() 148 | } 149 | 150 | function sizeCanvas() { 151 | canvas.width = innerWidth * dpr 152 | canvas.height = innerHeight * dpr 153 | canvas.style.setProperty('width', `${innerWidth}px`) 154 | canvas.style.setProperty('height', `${innerHeight}px`) 155 | } 156 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hwoa-rang-gl", 3 | "version": "1.0.5", 4 | "description": "WebGL libary", 5 | "main": "dist/cjs/index.js", 6 | "module": "dist/esm/index.js", 7 | "types": "dist/@types", 8 | "files": [ 9 | "dist" 10 | ], 11 | "exports": { 12 | "require": "./dist/cjs/index.js", 13 | "import": "./dist/esm/index.js" 14 | }, 15 | "scripts": { 16 | "lint": "eslint src", 17 | "watch": "rollup -c -w", 18 | "build": "rollup -c", 19 | "serve:examples": "cd docs && http-serve .", 20 | "watch:examples": "cd docs/examples && npm run start:dev", 21 | "build:examples": "cd docs/examples && npm run start", 22 | "start:examples:dev": "run-p watch watch:examples serve:examples", 23 | "start:examples": "run-s build build:examples serve:examples", 24 | "lint:examples": "eslint docs/examples", 25 | "build:docs": "typedoc --out docs/docs src/ --readme docs/README.md", 26 | "serve:docs": "http-serve docs/docs -p 8081", 27 | "start:docs": "run-p build:docs serve:docs" 28 | }, 29 | "keywords": [ 30 | "webgl", 31 | "glsl", 32 | "3d" 33 | ], 34 | "author": "Georgi Nikolov", 35 | "license": "MIT", 36 | "devDependencies": { 37 | "@rollup/plugin-json": "^4.1.0", 38 | "@rollup/plugin-node-resolve": "^9.0.0", 39 | "@typescript-eslint/eslint-plugin": "^4.21.0", 40 | "@typescript-eslint/parser": "^4.15.0", 41 | "eslint": "^7.19.0", 42 | "eslint-config-prettier": "^7.2.0", 43 | "eslint-plugin-prettier": "^3.3.1", 44 | "eslint-plugin-tsdoc": "^0.2.11", 45 | "npm-run-all": "^4.1.5", 46 | "prettier": "^2.2.1", 47 | "rollup": "^2.56.3", 48 | "rollup-plugin-commonjs": "^10.1.0", 49 | "rollup-plugin-copy": "^3.4.0", 50 | "rollup-plugin-glslify": "^1.2.0", 51 | "rollup-plugin-sourcemaps": "^0.6.3", 52 | "rollup-plugin-typescript2": "^0.29.0", 53 | "tslib": "^2.3.1", 54 | "tslint-config-prettier": "^1.18.0", 55 | "typescript": "^4.1.3" 56 | }, 57 | "dependencies": { 58 | "@types/webgl-ext": "0.0.32", 59 | "dat.gui": "^0.7.7", 60 | "gl-matrix": "^3.3.0", 61 | "http-serve": "^1.0.1", 62 | "lodash.throttle": "^4.1.1", 63 | "stats-js": "^1.0.1", 64 | "typedoc": "^0.20.28" 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import { nodeResolve } from '@rollup/plugin-node-resolve' 2 | import commonjs from 'rollup-plugin-commonjs' 3 | import typescript from 'rollup-plugin-typescript2' 4 | import sourcemaps from 'rollup-plugin-sourcemaps' 5 | 6 | import pkg from './package.json' 7 | 8 | const input = ['src/index.ts'] 9 | 10 | export default { 11 | input, 12 | output: [ 13 | { file: pkg.main, name: 'hwoaRangGL', format: 'umd', sourcemap: true }, 14 | { file: pkg.module, format: 'es', sourcemap: true }, 15 | ], 16 | // Indicate here external modules you don't wanna include in your bundle (i.e.: 'lodash') 17 | external: [], 18 | watch: { 19 | include: 'src/**', 20 | }, 21 | plugins: [ 22 | typescript({ 23 | useTsconfigDeclarationDir: true, 24 | declarationDir: 'dist/src', 25 | }), 26 | commonjs(), 27 | nodeResolve(), 28 | sourcemaps(), 29 | ], 30 | } 31 | -------------------------------------------------------------------------------- /src/camera/orthographic-camera.ts: -------------------------------------------------------------------------------- 1 | import { ReadonlyVec3, mat4 } from 'gl-matrix' 2 | 3 | export class OrthographicCamera { 4 | public static UP_VECTOR: ReadonlyVec3 = [0, 1, 0] 5 | 6 | public left = -1 7 | public right = 1 8 | public top = 1 9 | public bottom = -1 10 | public near = 0.1 11 | public far = 2000 12 | 13 | public zoom = 1 14 | 15 | public position: [number, number, number] = [0, 0, 0] 16 | public lookAtPosition: [number, number, number] = [0, 0, 0] 17 | 18 | public projectionMatrix: mat4 = mat4.create() 19 | public viewMatrix: mat4 = mat4.create() 20 | 21 | constructor( 22 | left: number, 23 | right: number, 24 | top: number, 25 | bottom: number, 26 | near: number, 27 | far: number, 28 | ) { 29 | this.left = left 30 | this.right = right 31 | this.top = top 32 | this.bottom = bottom 33 | 34 | this.near = near 35 | this.far = far 36 | 37 | this.updateProjectionMatrix() 38 | } 39 | 40 | setPosition({ 41 | x = this.position[0], 42 | y = this.position[1], 43 | z = this.position[2], 44 | }): this { 45 | this.position = [x, y, z] 46 | return this 47 | } 48 | 49 | updateViewMatrix(): this { 50 | mat4.lookAt( 51 | this.viewMatrix, 52 | this.position, 53 | this.lookAtPosition, 54 | OrthographicCamera.UP_VECTOR, 55 | ) 56 | return this 57 | } 58 | 59 | updateProjectionMatrix(): this { 60 | mat4.ortho( 61 | this.projectionMatrix, 62 | this.left, 63 | this.right, 64 | this.bottom, 65 | this.top, 66 | this.near, 67 | this.far, 68 | ) 69 | return this 70 | } 71 | 72 | lookAt(target: [number, number, number]): this { 73 | this.lookAtPosition = target 74 | this.updateViewMatrix() 75 | return this 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/camera/perspective-camera.ts: -------------------------------------------------------------------------------- 1 | import { ReadonlyVec3, mat4 } from 'gl-matrix' 2 | 3 | export class PerspectiveCamera { 4 | public static UP_VECTOR: ReadonlyVec3 = [0, 1, 0] 5 | 6 | public position: [number, number, number] = [0, 0, 0] 7 | public lookAtPosition: [number, number, number] = [0, 0, 0] 8 | 9 | public projectionMatrix: mat4 = mat4.create() 10 | public viewMatrix: mat4 = mat4.create() 11 | 12 | public zoom = 1 13 | 14 | public fieldOfView: number 15 | public aspect: number 16 | public near: number 17 | public far: number 18 | 19 | constructor(fieldOfView: number, aspect: number, near: number, far: number) { 20 | this.fieldOfView = fieldOfView 21 | this.aspect = aspect 22 | this.near = near 23 | this.far = far 24 | 25 | this.updateProjectionMatrix() 26 | } 27 | 28 | setPosition({ 29 | x = this.position[0], 30 | y = this.position[1], 31 | z = this.position[2], 32 | }) { 33 | this.position = [x, y, z] 34 | return this 35 | } 36 | 37 | updateViewMatrix(): this { 38 | mat4.lookAt( 39 | this.viewMatrix, 40 | this.position, 41 | this.lookAtPosition, 42 | PerspectiveCamera.UP_VECTOR, 43 | ) 44 | return this 45 | } 46 | 47 | updateProjectionMatrix(): this { 48 | mat4.perspective( 49 | this.projectionMatrix, 50 | this.fieldOfView, 51 | this.aspect, 52 | this.near, 53 | this.far, 54 | ) 55 | return this 56 | } 57 | 58 | lookAt(target: [number, number, number]): this { 59 | this.lookAtPosition = target 60 | this.updateViewMatrix() 61 | return this 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/core/cube-texture.ts: -------------------------------------------------------------------------------- 1 | import { Texture, TextureInterface } from './texture' 2 | 3 | export class CubeTexture extends Texture { 4 | #targets = [ 5 | this.gl.TEXTURE_CUBE_MAP_POSITIVE_X, 6 | this.gl.TEXTURE_CUBE_MAP_NEGATIVE_X, 7 | this.gl.TEXTURE_CUBE_MAP_POSITIVE_Y, 8 | this.gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, 9 | this.gl.TEXTURE_CUBE_MAP_POSITIVE_Z, 10 | this.gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, 11 | ] 12 | 13 | constructor( 14 | gl: WebGLRenderingContext, 15 | { 16 | format = gl.RGB, 17 | internalFormat = format, 18 | type = gl.UNSIGNED_BYTE, 19 | unpackAlignment = 1, 20 | wrapS = gl.CLAMP_TO_EDGE, 21 | wrapT = gl.CLAMP_TO_EDGE, 22 | minFilter = gl.LINEAR, 23 | magFilter = gl.LINEAR, 24 | }: TextureInterface = {}, 25 | ) { 26 | super(gl, { 27 | format, 28 | internalFormat, 29 | type, 30 | unpackAlignment, 31 | wrapS, 32 | wrapT, 33 | minFilter, 34 | magFilter, 35 | target: gl.TEXTURE_CUBE_MAP, 36 | }) 37 | } 38 | /** 39 | * 40 | * @param {Array.} sidesImages 41 | * @returns {this} 42 | */ 43 | addSides(sidesImages: Array): this { 44 | const gl = this.gl 45 | 46 | sidesImages.forEach((image, i) => { 47 | const target = this.#targets[i] 48 | const level = 0 49 | gl.texImage2D( 50 | target, 51 | level, 52 | this.internalFormat, 53 | this.format, 54 | this.type, 55 | image, 56 | ) 57 | }) 58 | 59 | return this 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/core/geometry.ts: -------------------------------------------------------------------------------- 1 | import { createBuffer, createIndexBuffer } from '../utils/gl-utils' 2 | 3 | import { INDEX_ATTRIB_NAME, POSITION_ATTRIB_NAME } from '../utils/gl-constants' 4 | 5 | /** 6 | * Geometry class to hold buffers and attributes for a mesh. 7 | * Accepts the data that makes up your model - indices, vertices, uvs, normals, etc. 8 | * The only required attribute & buffer to render is "position" 9 | * 10 | * @public 11 | */ 12 | export class Geometry { 13 | #gl: WebGLRenderingContext 14 | 15 | public attributes = new Map() 16 | public vertexCount = 0 17 | 18 | constructor(gl: WebGLRenderingContext) { 19 | this.#gl = gl 20 | } 21 | 22 | /** 23 | * @description Set data into element array buffer 24 | * @param {WebGLElementBufferInterface} params 25 | * @returns {this} 26 | */ 27 | addIndex(params: WebGLElementBufferInterface): this { 28 | const { typedArray } = params 29 | const buffer = createIndexBuffer(this.#gl, typedArray) 30 | this.vertexCount = typedArray.length 31 | this.attributes.set(INDEX_ATTRIB_NAME, { typedArray, buffer }) 32 | return this 33 | } 34 | 35 | /** 36 | * @description Add attribute as array buffer 37 | * @param {string} key - Name of attribute. Must match attribute name in your GLSL program 38 | * @param {WebGLArrayBufferInterface} params 39 | * @returns {this} 40 | */ 41 | addAttribute(key: string, params: WebGLArrayBufferInterface): this { 42 | const { 43 | typedArray, 44 | size = 1, 45 | type = this.#gl.FLOAT, 46 | normalized = false, 47 | stride = 0, 48 | offset = 0, 49 | instancedDivisor, 50 | } = params 51 | 52 | const buffer = createBuffer(this.#gl, typedArray) 53 | 54 | if (key === POSITION_ATTRIB_NAME && !this.vertexCount) { 55 | this.vertexCount = typedArray.length / size 56 | } 57 | 58 | this.attributes.set(key, { 59 | typedArray, 60 | size, 61 | type, 62 | normalized, 63 | stride, 64 | offset, 65 | buffer, 66 | instancedDivisor, 67 | }) 68 | return this 69 | } 70 | 71 | /** 72 | * 73 | * @param {string} key - Name of attribute. Must match attribute name in your GLSL program 74 | * @param {number} index - Index to start updating your typed array from 75 | * @param {number} size - How many items are to be updated 76 | * @param {Float32Array} subTypeArray - The whole or partial array to update your attribute with 77 | * @returns {this} 78 | */ 79 | updateAttribute( 80 | key: string, 81 | index: number, 82 | size: number, 83 | subTypeArray: Float32Array, 84 | ): this { 85 | const foundAttrib = this.attributes.get(key) 86 | if (!foundAttrib) { 87 | console.error('Could not locate an attribute to update') 88 | } 89 | 90 | const { buffer } = foundAttrib 91 | 92 | // TODO: Move updating buffer to a helper method 93 | this.#gl.bindBuffer(this.#gl.ARRAY_BUFFER, buffer) 94 | this.#gl.bufferSubData( 95 | this.#gl.ARRAY_BUFFER, 96 | index * size * Float32Array.BYTES_PER_ELEMENT, 97 | subTypeArray, 98 | ) 99 | 100 | return this 101 | } 102 | 103 | /** 104 | * @description Delete all buffers associated with this geometry 105 | */ 106 | delete(): void { 107 | this.attributes.forEach(({ buffer }) => { 108 | this.#gl.deleteBuffer(buffer) 109 | }) 110 | this.attributes.clear() 111 | } 112 | } 113 | 114 | interface WebGLElementBufferInterface { 115 | /** 116 | * Indices as typed array 117 | */ 118 | typedArray: Uint32Array | Uint16Array 119 | } 120 | 121 | interface WebGLArrayBufferInterface { 122 | /** 123 | * Data as typed array 124 | */ 125 | typedArray: Float32Array | Float64Array 126 | /** 127 | * @defaultValue 1 128 | */ 129 | size?: number 130 | /** 131 | * @defaultValue 1 132 | */ 133 | type?: number 134 | /** 135 | * @defaultValue false 136 | */ 137 | normalized?: boolean 138 | /** 139 | * @defaultValue 0 140 | */ 141 | stride?: number 142 | /** 143 | * @defaultValue 1 144 | */ 145 | offset?: number 146 | instancedDivisor?: number 147 | } 148 | -------------------------------------------------------------------------------- /src/core/scene-object.ts: -------------------------------------------------------------------------------- 1 | import { mat4 } from 'gl-matrix' 2 | import { uid } from 'uid' 3 | import { Transform } from '..' 4 | 5 | export class SceneObject extends Transform { 6 | parentNode: SceneObject | null = null 7 | 8 | protected _children: SceneObject[] = [] 9 | protected _visible = true 10 | 11 | worldMatrix = mat4.create() 12 | normalMatrix = mat4.create() 13 | 14 | uid = uid(9) 15 | name?: string 16 | 17 | get visible() { 18 | return this._visible 19 | } 20 | 21 | set visible(v: boolean) { 22 | this._visible = v 23 | } 24 | 25 | get children(): SceneObject[] { 26 | return this._children 27 | } 28 | 29 | get siblings(): SceneObject[] { 30 | if (!this.parentNode) { 31 | return [] 32 | } 33 | return this.parentNode._children 34 | } 35 | 36 | constructor(name: string | undefined = undefined) { 37 | super() 38 | this.name = name 39 | } 40 | 41 | get levelIndex(): number { 42 | let levelIndex = 0 43 | let parentNode = this.parentNode 44 | while (parentNode) { 45 | levelIndex++ 46 | parentNode = parentNode.parentNode 47 | } 48 | return levelIndex 49 | } 50 | 51 | setParent(parentNode: SceneObject | null = null): this { 52 | if (this.parentNode) { 53 | const idx = this.parentNode._children.indexOf(this) 54 | if (idx >= 0) { 55 | this.parentNode._children.splice(idx, 1) 56 | } 57 | } 58 | if (parentNode) { 59 | parentNode.addChild(this) 60 | } 61 | this.parentNode = parentNode 62 | return this 63 | } 64 | 65 | addChild(childNode: SceneObject): this { 66 | this._children.push(childNode) 67 | return this 68 | } 69 | 70 | updateWorldMatrix(parentWorldMatrix: mat4 | null = null): this { 71 | if (this.shouldUpdate) { 72 | this.updateModelMatrix() 73 | } 74 | if (parentWorldMatrix) { 75 | mat4.mul(this.worldMatrix, parentWorldMatrix, this.modelMatrix) 76 | } else { 77 | mat4.copy(this.worldMatrix, this.modelMatrix) 78 | } 79 | mat4.invert(this.normalMatrix, this.worldMatrix) 80 | mat4.transpose(this.normalMatrix, this.normalMatrix) 81 | for (let i = 0; i < this._children.length; i++) { 82 | this._children[i].updateWorldMatrix(this.worldMatrix) 83 | } 84 | // console.log(this.worldMatrix) 85 | return this 86 | } 87 | 88 | traverse( 89 | callback: (node: SceneObject, depthLevel: number) => void, 90 | depth = 0, 91 | ): void { 92 | callback(this, depth) 93 | depth++ 94 | for (let i = 0; i < this._children.length; i++) { 95 | const child = this._children[i] 96 | child.traverse(callback, depth) 97 | } 98 | } 99 | 100 | findChild( 101 | callback: (node: SceneObject) => SceneObject | boolean | null, 102 | ): SceneObject | null { 103 | if (callback(this)) { 104 | return this 105 | } 106 | let outNode: SceneObject | null = null 107 | for (let i = 0; i < this._children.length; i++) { 108 | const child = this._children[i] 109 | if ((outNode = child.findChild(callback))) { 110 | break 111 | } 112 | } 113 | return outNode 114 | } 115 | 116 | findChildByName(name: string): SceneObject | null { 117 | if (this.name === name) { 118 | return this 119 | } 120 | let outNode: SceneObject | null = null 121 | for (let i = 0; i < this._children.length; i++) { 122 | const child = this._children[i] 123 | if ((outNode = child.findChildByName(name))) { 124 | break 125 | } 126 | } 127 | return outNode 128 | } 129 | 130 | findParent( 131 | callback: (node: SceneObject) => SceneObject | boolean | null, 132 | ): SceneObject | null { 133 | if (callback(this)) { 134 | return this 135 | } 136 | let outNode: SceneObject | null = null 137 | let parentNode = this.parentNode 138 | while (parentNode) { 139 | if ((outNode = parentNode.findParent(callback))) { 140 | break 141 | } 142 | parentNode = parentNode?.parentNode 143 | } 144 | return outNode 145 | } 146 | 147 | findParentByName(name: string): SceneObject | null { 148 | if (this.name === name) { 149 | return this 150 | } 151 | let outNode: SceneObject | null = null 152 | let parentNode = this.parentNode 153 | while (parentNode) { 154 | if ((outNode = parentNode.findParentByName(name))) { 155 | break 156 | } 157 | parentNode = parentNode?.parentNode 158 | } 159 | return outNode 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/core/transform.ts: -------------------------------------------------------------------------------- 1 | import { mat4, ReadonlyMat4, vec3 } from 'gl-matrix' 2 | 3 | /** 4 | * Base transform class to handle vectors and matrices 5 | * 6 | * @public 7 | */ 8 | export class Transform { 9 | public position: vec3 = vec3.fromValues(0, 0, 0) 10 | public rotation: vec3 = vec3.fromValues(0, 0, 0) 11 | public scale: vec3 = vec3.fromValues(1, 1, 1) 12 | 13 | public modelMatrix = mat4.create() 14 | 15 | public shouldUpdate = true 16 | 17 | /** 18 | * @returns {this} 19 | */ 20 | copyFromMatrix(matrix: ReadonlyMat4) { 21 | mat4.copy(this.modelMatrix, matrix) 22 | this.shouldUpdate = false 23 | return this 24 | } 25 | 26 | /** 27 | * @returns {this} 28 | */ 29 | setPosition(position: { x?: number; y?: number; z?: number }): this { 30 | const { 31 | x = this.position[0], 32 | y = this.position[1], 33 | z = this.position[2], 34 | } = position 35 | vec3.set(this.position, x, y, z) 36 | this.shouldUpdate = true 37 | return this 38 | } 39 | 40 | /** 41 | * Sets scale 42 | * @returns {this} 43 | */ 44 | setScale(scale: { x?: number; y?: number; z?: number }): this { 45 | const { x = this.scale[0], y = this.scale[1], z = this.scale[2] } = scale 46 | vec3.set(this.scale, x, y, z) 47 | this.shouldUpdate = true 48 | return this 49 | } 50 | 51 | /** 52 | * Sets rotation 53 | * @returns {this} 54 | */ 55 | setRotation(rotation: { x?: number; y?: number; z?: number }): this { 56 | const { 57 | x = this.rotation[0], 58 | y = this.rotation[1], 59 | z = this.rotation[2], 60 | } = rotation 61 | vec3.set(this.rotation, x, y, z) 62 | this.shouldUpdate = true 63 | return this 64 | } 65 | 66 | /** 67 | * Update model matrix with scale, rotation and translation 68 | * @returns {this} 69 | */ 70 | updateModelMatrix(): this { 71 | mat4.identity(this.modelMatrix) 72 | mat4.translate(this.modelMatrix, this.modelMatrix, this.position) 73 | mat4.rotateX(this.modelMatrix, this.modelMatrix, this.rotation[0]) 74 | mat4.rotateY(this.modelMatrix, this.modelMatrix, this.rotation[1]) 75 | mat4.rotateZ(this.modelMatrix, this.modelMatrix, this.rotation[2]) 76 | mat4.scale(this.modelMatrix, this.modelMatrix, this.scale) 77 | this.shouldUpdate = false 78 | return this 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/geometry-utils/build-plane.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @private 3 | */ 4 | export function buildPlane( 5 | vertices: Float32Array, 6 | normal: Float32Array, 7 | uv: Float32Array, 8 | indices: Uint16Array|Uint32Array, 9 | width: number, 10 | height: number, 11 | depth: number, 12 | wSegs: number, 13 | hSegs: number, 14 | u = 0, 15 | v = 1, 16 | w = 2, 17 | uDir = 1, 18 | vDir = -1, 19 | i = 0, 20 | ii = 0, 21 | ) { 22 | const io = i 23 | const segW = width / wSegs 24 | const segH = height / hSegs 25 | 26 | for (let iy = 0; iy <= hSegs; iy++) { 27 | const y = iy * segH - height / 2 28 | for (let ix = 0; ix <= wSegs; ix++, i++) { 29 | const x = ix * segW - width / 2 30 | 31 | vertices[i * 3 + u] = x * uDir 32 | vertices[i * 3 + v] = y * vDir 33 | vertices[i * 3 + w] = depth / 2 34 | 35 | normal[i * 3 + u] = 0 36 | normal[i * 3 + v] = 0 37 | normal[i * 3 + w] = depth >= 0 ? 1 : -1 38 | 39 | uv[i * 2] = ix / wSegs 40 | uv[i * 2 + 1] = 1 - iy / hSegs 41 | 42 | if (iy === hSegs || ix === wSegs) continue 43 | const a = io + ix + iy * (wSegs + 1) 44 | const b = io + ix + (iy + 1) * (wSegs + 1) 45 | const c = io + ix + (iy + 1) * (wSegs + 1) + 1 46 | const d = io + ix + iy * (wSegs + 1) + 1 47 | 48 | indices[ii * 6] = a 49 | indices[ii * 6 + 1] = b 50 | indices[ii * 6 + 2] = d 51 | indices[ii * 6 + 3] = b 52 | indices[ii * 6 + 4] = c 53 | indices[ii * 6 + 5] = d 54 | ii++ 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /src/geometry-utils/create-box.ts: -------------------------------------------------------------------------------- 1 | import { buildPlane } from './build-plane' 2 | 3 | export interface Box { 4 | /** 5 | * @defaultValue 1 6 | */ 7 | width?: number 8 | /** 9 | * @defaultValue 1 10 | */ 11 | height?: number 12 | /** 13 | * @defaultValue 1 14 | */ 15 | depth?: number 16 | /** 17 | * @defaultValue 1 18 | */ 19 | widthSegments?: number 20 | /** 21 | * @defaultValue 1 22 | */ 23 | heightSegments?: number 24 | /** 25 | * @defaultValue 1 26 | */ 27 | depthSegments?: number 28 | /** 29 | * @defaultValue false 30 | */ 31 | separateFaces?: boolean 32 | } 33 | 34 | /** 35 | * Generates geometry data for a box 36 | * @param {Box} params 37 | * @returns {{ vertices, normal, uv, indices }} 38 | */ 39 | export function createBox(params: Box = {}) { 40 | const { 41 | width = 1, 42 | height = 1, 43 | depth = 1, 44 | widthSegments = 1, 45 | heightSegments = 1, 46 | depthSegments = 1, 47 | } = params 48 | 49 | const wSegs = widthSegments 50 | const hSegs = heightSegments 51 | const dSegs = depthSegments 52 | 53 | const num = 54 | (wSegs + 1) * (hSegs + 1) * 2 + 55 | (wSegs + 1) * (dSegs + 1) * 2 + 56 | (hSegs + 1) * (dSegs + 1) * 2 57 | const numIndices = 58 | (wSegs * hSegs * 2 + wSegs * dSegs * 2 + hSegs * dSegs * 2) * 6 59 | 60 | const vertices = new Float32Array(num * 3) 61 | const normal = new Float32Array(num * 3) 62 | const uv = new Float32Array(num * 2) 63 | const indices = 64 | num > 65536 ? new Uint32Array(numIndices) : new Uint16Array(numIndices) 65 | 66 | let i = 0 67 | let ii = 0 68 | 69 | { 70 | // RIGHT 71 | buildPlane( 72 | vertices, 73 | normal, 74 | uv, 75 | indices, 76 | depth, 77 | height, 78 | width, 79 | dSegs, 80 | hSegs, 81 | 2, 82 | 1, 83 | 0, 84 | -1, 85 | -1, 86 | i, 87 | ii, 88 | ) 89 | } 90 | { 91 | // LEFT 92 | 93 | buildPlane( 94 | vertices, 95 | normal, 96 | uv, 97 | indices, 98 | depth, 99 | height, 100 | -width, 101 | dSegs, 102 | hSegs, 103 | 2, 104 | 1, 105 | 0, 106 | 1, 107 | -1, 108 | (i += (dSegs + 1) * (hSegs + 1)), 109 | (ii += dSegs * hSegs), 110 | ) 111 | } 112 | { 113 | // TOP 114 | 115 | buildPlane( 116 | vertices, 117 | normal, 118 | uv, 119 | indices, 120 | width, 121 | depth, 122 | height, 123 | dSegs, 124 | hSegs, 125 | 0, 126 | 2, 127 | 1, 128 | 1, 129 | 1, 130 | (i += (dSegs + 1) * (hSegs + 1)), 131 | (ii += dSegs * hSegs), 132 | ) 133 | } 134 | { 135 | // BOTTOM 136 | 137 | buildPlane( 138 | vertices, 139 | normal, 140 | uv, 141 | indices, 142 | width, 143 | depth, 144 | -height, 145 | dSegs, 146 | hSegs, 147 | 0, 148 | 2, 149 | 1, 150 | 1, 151 | -1, 152 | (i += (wSegs + 1) * (dSegs + 1)), 153 | (ii += wSegs * dSegs), 154 | ) 155 | } 156 | { 157 | // BACK 158 | 159 | buildPlane( 160 | vertices, 161 | normal, 162 | uv, 163 | indices, 164 | width, 165 | height, 166 | -depth, 167 | wSegs, 168 | hSegs, 169 | 0, 170 | 1, 171 | 2, 172 | -1, 173 | -1, 174 | (i += (wSegs + 1) * (dSegs + 1)), 175 | (ii += wSegs * dSegs), 176 | ) 177 | } 178 | 179 | { 180 | // FRONT 181 | 182 | buildPlane( 183 | vertices, 184 | normal, 185 | uv, 186 | indices, 187 | width, 188 | height, 189 | depth, 190 | wSegs, 191 | hSegs, 192 | 0, 193 | 1, 194 | 2, 195 | 1, 196 | -1, 197 | (i += (wSegs + 1) * (hSegs + 1)), 198 | (ii += wSegs * hSegs), 199 | ) 200 | } 201 | 202 | return { 203 | vertices, 204 | normal, 205 | uv, 206 | indices, 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /src/geometry-utils/create-circle.ts: -------------------------------------------------------------------------------- 1 | import { vec2, vec3 } from 'gl-matrix' 2 | 3 | interface Circle { 4 | /** 5 | * @default 1 6 | */ 7 | radius?: number 8 | /** 9 | * @default 8 10 | */ 11 | segments?: number 12 | /** 13 | * @default 0 14 | */ 15 | thetaStart?: number 16 | /** 17 | * @default Math.PI * 2 18 | */ 19 | thetaLength?: number 20 | } 21 | 22 | /** 23 | * @description Generate circle geometry 24 | * @param {Circle} params 25 | * @returns {{ vertices, normal, uv, indices }} 26 | */ 27 | export function createCircle (params: Circle = {}) { 28 | const { 29 | radius = 1, 30 | segments = 8, 31 | thetaStart = 0, 32 | thetaLength = Math.PI * 2, 33 | } = params 34 | 35 | const indices: number[] = [] 36 | const vertices: number[] = [] 37 | const normals: number[] = [] 38 | const uvs: number[] = [] 39 | 40 | // helper variables 41 | 42 | const vertex = vec3.create() 43 | const uv = vec2.create() 44 | 45 | // center point 46 | 47 | vertices.push( 0, 0, 0 ) 48 | normals.push( 0, 0, 1 ) 49 | uvs.push( 0.5, 0.5 ) 50 | 51 | for ( let s = 0, i = 3; s <= segments; s ++, i += 3 ) { 52 | 53 | const segment = thetaStart + s / segments * thetaLength 54 | 55 | // vertex 56 | 57 | vertex[0] = radius * Math.cos( segment ) 58 | vertex[1] = radius * Math.sin( segment ) 59 | 60 | vertices.push(...vertex) 61 | 62 | // normal 63 | 64 | normals.push( 0, 0, 1 ) 65 | 66 | // uvs 67 | 68 | uv[0] = ( vertices[ i ] / radius + 1 ) / 2 69 | uv[1] = ( vertices[ i + 1 ] / radius + 1 ) / 2 70 | uvs.push( uv[0], uv[1] ) 71 | 72 | } 73 | 74 | // indices 75 | 76 | for ( let i = 1; i <= segments; i ++ ) { 77 | 78 | indices.push( i, i + 1, 0 ) 79 | 80 | } 81 | 82 | 83 | return { 84 | indices: segments > 65536 ? new Uint32Array(indices) : new Uint16Array(indices), 85 | vertices: new Float32Array(vertices), 86 | normal: new Float32Array(normals), 87 | uv: new Float32Array(uvs), 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/geometry-utils/create-interleaved-plane.ts: -------------------------------------------------------------------------------- 1 | import { Plane } from './create-plane' 2 | 3 | export const createInterleavedPlane = (params: Plane = {}): PlaneGeometry => { 4 | const { 5 | width = 1, 6 | height = 1, 7 | widthSegments = 1, 8 | heightSegments = 1, 9 | } = params 10 | 11 | const wSegs = widthSegments 12 | const hSegs = heightSegments 13 | 14 | // Determine length of arrays 15 | const num = (wSegs + 1) * (hSegs + 1) 16 | const numIndices = wSegs * hSegs * 6 17 | 18 | // Generate interleaved array 19 | const interleavedArray = new Float32Array(num * 3 + num * 2) 20 | const indicesArray = 21 | num > 65536 ? new Uint32Array(numIndices) : new Uint16Array(numIndices) 22 | 23 | let i = 0 24 | let ii = 0 25 | const io = i 26 | const segW = width / wSegs 27 | const segH = height / hSegs 28 | const uDir = 1 29 | const vDir = -1 30 | const depth = 0 31 | // pos + uv 32 | const vertexStride = 3 + 2 33 | 34 | for (let iy = 0; iy <= hSegs; iy++) { 35 | const y = iy * segH - height / 2 36 | for (let ix = 0; ix <= wSegs; ix++, i++) { 37 | const x = ix * segW - width / 2 38 | 39 | interleavedArray[i * vertexStride + 0] = x * uDir 40 | interleavedArray[i * vertexStride + 1] = y * vDir 41 | interleavedArray[i * vertexStride + 2] = depth / 2 42 | 43 | interleavedArray[i * vertexStride + 3] = ix / wSegs 44 | interleavedArray[i * vertexStride + 4] = 1 - iy / hSegs 45 | // interleavedArray[i * vertexStride + 4] = flipUVy 46 | // ? 1 - iy / hSegs 47 | // : iy / hSegs 48 | 49 | if (iy === hSegs || ix === wSegs) continue 50 | const a = io + ix + iy * (wSegs + 1) 51 | const b = io + ix + (iy + 1) * (wSegs + 1) 52 | const c = io + ix + (iy + 1) * (wSegs + 1) + 1 53 | const d = io + ix + iy * (wSegs + 1) + 1 54 | 55 | indicesArray[ii * 6] = a 56 | indicesArray[ii * 6 + 1] = b 57 | indicesArray[ii * 6 + 2] = d 58 | indicesArray[ii * 6 + 3] = b 59 | indicesArray[ii * 6 + 4] = c 60 | indicesArray[ii * 6 + 5] = d 61 | ii++ 62 | } 63 | } 64 | 65 | return { 66 | width, 67 | height, 68 | vertexCount: indicesArray.length, 69 | vertexStride, 70 | interleavedArray, 71 | indicesArray, 72 | } 73 | } 74 | 75 | export interface Geometry { 76 | vertexCount: number 77 | vertexStride: number 78 | interleavedArray: Float32Array 79 | indicesArray: Uint16Array | Uint32Array 80 | } 81 | 82 | export interface PlaneGeometry extends Geometry { 83 | width: number 84 | height: number 85 | } 86 | -------------------------------------------------------------------------------- /src/geometry-utils/create-plane.ts: -------------------------------------------------------------------------------- 1 | import { buildPlane } from './build-plane' 2 | 3 | export interface Plane { 4 | /** 5 | * @defaultValue 1 6 | */ 7 | width?: number 8 | /** 9 | * @defaultValue 1 10 | */ 11 | height?: number 12 | /** 13 | * @defaultValue 1 14 | */ 15 | widthSegments?: number 16 | /** 17 | * @defaultValue 1 18 | */ 19 | heightSegments?: number 20 | } 21 | 22 | /** 23 | * Generates geometry data for a quad 24 | * @param {PlaneInterface} params 25 | * @returns {{ vertices, normal, uv, indices }} 26 | */ 27 | export function createPlane(params: Plane = {}) { 28 | const { 29 | width = 1, 30 | height = 1, 31 | widthSegments = 1, 32 | heightSegments = 1, 33 | } = params 34 | 35 | const wSegs = widthSegments 36 | const hSegs = heightSegments 37 | 38 | // Determine length of arrays 39 | const num = (wSegs + 1) * (hSegs + 1) 40 | const numIndices = wSegs * hSegs * 6 41 | 42 | // Generate empty arrays once 43 | const position = new Float32Array(num * 3) 44 | const normal = new Float32Array(num * 3) 45 | const uv = new Float32Array(num * 2) 46 | const index = 47 | num > 65536 ? new Uint32Array(numIndices) : new Uint16Array(numIndices) 48 | 49 | buildPlane(position, normal, uv, index, width, height, 0, wSegs, hSegs) 50 | return { 51 | vertices: position, 52 | normal, 53 | uv, 54 | indices: index, 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/geometry-utils/create-sphere.ts: -------------------------------------------------------------------------------- 1 | import { vec3 } from 'gl-matrix' 2 | 3 | export interface Sphere { 4 | /** 5 | * @defaultValue 0.5 6 | */ 7 | radius?: number 8 | /** 9 | * @defaultValue 16 10 | */ 11 | widthSegments?: number 12 | /** 13 | * @defaultValue Math.ceil(widthSegments * 0.5) 14 | */ 15 | heightSegments?: number 16 | /** 17 | * @defaultValue 0 18 | */ 19 | phiStart?: number 20 | /** 21 | * @defaultValue Math.PI * 2 22 | */ 23 | phiLength?: number 24 | /** 25 | * @defaultValue 0 26 | */ 27 | thetaStart?: number 28 | /** 29 | * @defaultValue Math.PI 30 | */ 31 | thetaLength?: number 32 | } 33 | 34 | /** 35 | * Generates geometry data for a sphere 36 | * @param {Sphere} params 37 | * @returns {{ vertices, normal, uv, indices }} 38 | */ 39 | export function createSphere(params: Sphere = {}) { 40 | const { 41 | radius = 0.5, 42 | widthSegments = 16, 43 | heightSegments = Math.ceil(widthSegments * 0.5), 44 | phiStart = 0, 45 | phiLength = Math.PI * 2, 46 | thetaStart = 0, 47 | thetaLength = Math.PI, 48 | } = params 49 | 50 | const wSegs = widthSegments 51 | const hSegs = heightSegments 52 | const pStart = phiStart 53 | const pLength = phiLength 54 | const tStart = thetaStart 55 | const tLength = thetaLength 56 | 57 | const num = (wSegs + 1) * (hSegs + 1) 58 | const numIndices = wSegs * hSegs * 6 59 | 60 | const position = new Float32Array(num * 3) 61 | const normal = new Float32Array(num * 3) 62 | const uv = new Float32Array(num * 2) 63 | const index = 64 | num > 65536 ? new Uint32Array(numIndices) : new Uint16Array(numIndices) 65 | 66 | let i = 0 67 | let iv = 0 68 | let ii = 0 69 | const te = tStart + tLength 70 | const grid: Array = [] 71 | 72 | const n = vec3.create() 73 | 74 | for (let iy = 0; iy <= hSegs; iy++) { 75 | const vRow: number[] = [] 76 | const v = iy / hSegs 77 | for (let ix = 0; ix <= wSegs; ix++, i++) { 78 | const u = ix / wSegs 79 | const x = 80 | -radius * 81 | Math.cos(pStart + u * pLength) * 82 | Math.sin(tStart + v * tLength) 83 | const y = radius * Math.cos(tStart + v * tLength) 84 | const z = 85 | radius * Math.sin(pStart + u * pLength) * Math.sin(tStart + v * tLength) 86 | 87 | position[i * 3] = x 88 | position[i * 3 + 1] = y 89 | position[i * 3 + 2] = z 90 | 91 | vec3.set(n, x, y, z) 92 | vec3.normalize(n, n) 93 | 94 | normal[i * 3] = n[0] 95 | normal[i * 3 + 1] = n[1] 96 | normal[i * 3 + 2] = n[2] 97 | 98 | uv[i * 2] = u 99 | uv[i * 2 + 1] = 1 - v 100 | 101 | vRow.push(iv++) 102 | } 103 | 104 | grid.push(vRow) 105 | } 106 | 107 | for (let iy = 0; iy < hSegs; iy++) { 108 | for (let ix = 0; ix < wSegs; ix++) { 109 | const a = grid[iy][ix + 1] 110 | const b = grid[iy][ix] 111 | const c = grid[iy + 1][ix] 112 | const d = grid[iy + 1][ix + 1] 113 | 114 | if (iy !== 0 || tStart > 0) { 115 | index[ii * 3] = a 116 | index[ii * 3 + 1] = b 117 | index[ii * 3 + 2] = d 118 | ii++ 119 | } 120 | if (iy !== hSegs - 1 || te < Math.PI) { 121 | index[ii * 3] = b 122 | index[ii * 3 + 1] = c 123 | index[ii * 3 + 2] = d 124 | ii++ 125 | } 126 | } 127 | } 128 | return { 129 | vertices: position, 130 | normal, 131 | uv, 132 | indices: index, 133 | } 134 | } -------------------------------------------------------------------------------- /src/geometry-utils/create-torus.ts: -------------------------------------------------------------------------------- 1 | import { vec3 } from 'gl-matrix' 2 | 3 | interface Torus { 4 | /** 5 | * @defaultValue 0.5 6 | */ 7 | radius?: number 8 | /** 9 | * @defaultValue 0.35 10 | */ 11 | tube?: number 12 | /** 13 | * @defaultValue Math.PI * 2 14 | */ 15 | arc?: number 16 | /** 17 | * @defaultValue Math.PI * 2 18 | */ 19 | radialSegments?: number 20 | /** 21 | * @defaultValue Math.PI * 2 22 | */ 23 | tubularSegments?: number 24 | } 25 | 26 | /** 27 | * @description Generate torus geometry 28 | * @param {Torus} params 29 | * @returns {{ vertices, normal, uv, indices }} 30 | */ 31 | export function createTorus(params: Torus = {}) { 32 | const { 33 | radius = 0.5, 34 | tube = 0.35, 35 | arc = Math.PI * 2, 36 | radialSegments: inputRadialSegments = 8, 37 | tubularSegments: inputTubularSegments = 6, 38 | } = params 39 | 40 | const radialSegments = Math.floor(inputRadialSegments) 41 | const tubularSegments = Math.floor(inputTubularSegments) 42 | 43 | const indices: number[] = [] 44 | const vertices: number[] = [] 45 | const normals: number[] = [] 46 | const uvs: number[] = [] 47 | 48 | const center = vec3.create() 49 | const vertex = vec3.create() 50 | const normal = vec3.create() 51 | 52 | for (let j = 0; j <= radialSegments; j++) { 53 | for (let i = 0; i <= tubularSegments; i++) { 54 | const u = (i / tubularSegments) * arc 55 | const v = (j / radialSegments) * Math.PI * 2 56 | 57 | // vertex 58 | 59 | vertex[0] = (radius + tube * Math.cos(v)) * Math.cos(u) 60 | vertex[1] = (radius + tube * Math.cos(v)) * Math.sin(u) 61 | vertex[2] = tube * Math.sin(v) 62 | 63 | vertices.push(vertex[0], vertex[1], vertex[2]) 64 | 65 | // normal 66 | 67 | center[0] = radius * Math.cos(u) 68 | center[1] = radius * Math.sin(u) 69 | 70 | vec3.sub(normal, vertex, center) 71 | vec3.normalize(normal, normal) 72 | 73 | normals.push(normal[0], normal[1], normal[0]) 74 | 75 | // uv 76 | 77 | uvs.push(i / tubularSegments, j / radialSegments) 78 | } 79 | } 80 | 81 | // generate indices 82 | 83 | for (let j = 1; j <= radialSegments; j++) { 84 | for (let i = 1; i <= tubularSegments; i++) { 85 | // indices 86 | 87 | const a = (tubularSegments + 1) * j + i - 1 88 | const b = (tubularSegments + 1) * (j - 1) + i - 1 89 | const c = (tubularSegments + 1) * (j - 1) + i 90 | const d = (tubularSegments + 1) * j + i 91 | 92 | // faces 93 | 94 | indices.push(a, b, d) 95 | indices.push(b, c, d) 96 | } 97 | } 98 | 99 | const num = (radialSegments + 1) * (tubularSegments + 1) 100 | 101 | return { 102 | indices: num > 65536 ? new Uint32Array(indices) : new Uint16Array(indices), 103 | vertices: new Float32Array(vertices), 104 | normal: new Float32Array(normals), 105 | uv: new Float32Array(uvs), 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/geometry-utils/index.ts: -------------------------------------------------------------------------------- 1 | import { createBox } from './create-box' 2 | import { createBoxSeparateFace } from './create-box-separate-faces' 3 | import { createRoundedBox } from './create-rounded-box' 4 | import { createRoundedBoxSeparateFace } from './create-rounded-box-separate-faces' 5 | import { createCircle } from './create-circle' 6 | import { createPlane } from './create-plane' 7 | import { createInterleavedPlane } from './create-interleaved-plane' 8 | import { createSphere } from './create-sphere' 9 | import { createTorus } from './create-torus' 10 | 11 | export { createBox } 12 | export { createBoxSeparateFace } 13 | export { createRoundedBoxSeparateFace } 14 | export { createRoundedBox } 15 | export { createCircle } 16 | export { createPlane } 17 | export { createInterleavedPlane } 18 | export { createSphere } 19 | export { createTorus } 20 | 21 | /** 22 | * @namespace GeometryUtils 23 | */ 24 | export const GeometryUtils = { 25 | createBox, 26 | createBoxSeparateFace, 27 | createRoundedBoxSeparateFace, 28 | createRoundedBox, 29 | createCircle, 30 | createPlane, 31 | createInterleavedPlane, 32 | createSphere, 33 | createTorus, 34 | } 35 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export { Program } from './core/program' 2 | export { Geometry } from './core/geometry' 3 | export { Transform } from './core/transform' 4 | export { SceneObject } from './core/scene-object' 5 | export { Mesh } from './core/mesh' 6 | export { InstancedMesh } from './core/instanced-mesh' 7 | export { Texture } from './core/texture' 8 | export { CubeTexture } from './core/cube-texture' 9 | export { Framebuffer } from './core/framebuffer' 10 | 11 | export { CameraController } from './camera/camera-controller' 12 | export { PerspectiveCamera } from './camera/perspective-camera' 13 | export { OrthographicCamera } from './camera/orthographic-camera' 14 | 15 | export { SwapRenderer } from './extra/swap-renderer' 16 | 17 | export * from './utils/gl-utils' 18 | export * from './utils/gl-constants' 19 | export * from './utils/math' 20 | 21 | export * as GeometryUtils from './geometry-utils' 22 | -------------------------------------------------------------------------------- /src/utils/gl-constants.js: -------------------------------------------------------------------------------- 1 | export const MODEL_MATRIX_UNIFORM_NAME = 'modelMatrix' 2 | export const VIEW_MATRIX_UNIFORM_NAME = 'viewMatrix' 3 | export const PROJECTION_MATRIX_UNIFORM_NAME = 'projectionMatrix' 4 | 5 | export const INDEX_ATTRIB_NAME = 'index' 6 | export const POSITION_ATTRIB_NAME = 'position' 7 | export const INSTANCED_OFFSET_MODEL_MATRIX = 'instanceModelMatrix' 8 | 9 | export const UNIFORM_TYPE_INT = 'int' 10 | export const UNIFORM_TYPE_FLOAT = 'float' 11 | export const UNIFORM_TYPE_VEC2 = 'vec2' 12 | export const UNIFORM_TYPE_VEC3 = 'vec3' 13 | export const UNIFORM_TYPE_VEC4 = 'vec4' 14 | export const UNIFORM_TYPE_MATRIX4X4 = 'mat4' 15 | 16 | export const CUBE_SIDE_FRONT = 'front' 17 | export const CUBE_SIDE_BACK = 'back' 18 | export const CUBE_SIDE_TOP = 'top' 19 | export const CUBE_SIDE_BOTTOM = 'bottom' 20 | export const CUBE_SIDE_LEFT = 'left' 21 | export const CUBE_SIDE_RIGHT = 'right' 22 | 23 | export const POINTS = 0x0000 24 | export const LINES = 0x0001 25 | export const TRIANGLES = 0x0004 26 | 27 | export const STATIC_DRAW = 0x88e4 28 | 29 | export const TEXTURE_FILTER_NEAREST = 0x2600 30 | export const TEXTURE_FILTER_LINEAR = 0x2601 31 | -------------------------------------------------------------------------------- /src/utils/gl-utils.ts: -------------------------------------------------------------------------------- 1 | import { STATIC_DRAW } from './gl-constants' 2 | 3 | /** 4 | * Create and compile WebGLShader 5 | * @param {WebGLRenderingContext)} gl 6 | * @param {GLenum} shaderType 7 | * @param {string} shaderSource 8 | * @returns {WebGLShader} 9 | */ 10 | export function compileShader( 11 | gl: WebGLRenderingContext, 12 | shaderType: GLenum, 13 | shaderSource: string, 14 | ): WebGLShader | null { 15 | const shader: WebGLShader | null = gl.createShader(shaderType) 16 | if (!shader) { 17 | console.error('Failed to create WebGL shader') 18 | return null 19 | } 20 | gl.shaderSource(shader, shaderSource) 21 | gl.compileShader(shader) 22 | if (gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { 23 | return shader 24 | } 25 | console.error(` 26 | Error in ${shaderType === gl.VERTEX_SHADER ? 'Vertex' : 'Fragment'} shader: 27 | ${gl.getShaderInfoLog(shader)} 28 | `) 29 | gl.deleteShader(shader) 30 | return null 31 | } 32 | 33 | /** 34 | * Create and link WebGLProgram with provided shader strings 35 | * @param {(WebGLRenderingContext)} gl 36 | * @param {string} vertexShaderSource 37 | * @param {string} fragmentShaderSource 38 | * @returns {WebGLProgram} 39 | */ 40 | export function createProgram( 41 | gl: WebGLRenderingContext, 42 | vertexShaderSource: string, 43 | fragmentShaderSource: string, 44 | ): WebGLProgram | null { 45 | const vertexShader: WebGLShader | null = compileShader( 46 | gl, 47 | gl.VERTEX_SHADER, 48 | vertexShaderSource, 49 | ) 50 | 51 | if (!vertexShader) { 52 | return null 53 | } 54 | 55 | const fragmentShader: WebGLShader | null = compileShader( 56 | gl, 57 | gl.FRAGMENT_SHADER, 58 | fragmentShaderSource, 59 | ) 60 | 61 | if (!fragmentShader) { 62 | return null 63 | } 64 | 65 | const program: WebGLProgram | null = gl.createProgram() 66 | if (!program) { 67 | console.error('failed to create a WebGL program') 68 | return null 69 | } 70 | gl.attachShader(program, vertexShader) 71 | gl.attachShader(program, fragmentShader) 72 | gl.linkProgram(program) 73 | 74 | // It is safe to detach and delete shaders once a program is linked 75 | gl.detachShader(program, vertexShader) 76 | gl.deleteShader(vertexShader) 77 | gl.detachShader(program, fragmentShader) 78 | gl.deleteShader(fragmentShader) 79 | 80 | if (gl.getProgramParameter(program, gl.LINK_STATUS)) { 81 | return program 82 | } 83 | console.error('Error linking program', gl.getProgramInfoLog(program)) 84 | gl.deleteProgram(program) 85 | return null 86 | } 87 | 88 | /** 89 | * Create a ARRAY_BUFFER buffer 90 | * @param {WebGLRenderingContext)} gl 91 | * @param {ArrayBuffer} data - Typed array types that will be copied into the data store 92 | * @param {GLenum} [usage = gl.STATIC_DRAW] - A GLenum specifying the intended usage pattern of the data store for optimization purposes 93 | * @returns {WebGLBuffer} 94 | */ 95 | export function createBuffer( 96 | gl: WebGLRenderingContext, 97 | data: Float32Array | Float64Array, 98 | usage: GLenum = STATIC_DRAW, 99 | ): WebGLBuffer | null { 100 | const buffer = gl.createBuffer() 101 | gl.bindBuffer(gl.ARRAY_BUFFER, buffer) 102 | gl.bufferData(gl.ARRAY_BUFFER, data, usage) 103 | 104 | return buffer 105 | } 106 | 107 | /** 108 | * Create a ELEMENT_ARRAY_BUFFER buffer 109 | * @param {WebGLRenderingContext)} gl 110 | * @param {ArrayBuffer} data - Typed array types that will be copied into the data store 111 | * @param {GLenum} [usage=STATIC_DRAW] - A GLenum specifying the intended usage pattern of the data store for optimization purposes 112 | * @returns {WebGLBuffer} 113 | */ 114 | export function createIndexBuffer( 115 | gl: WebGLRenderingContext, 116 | indices: Uint16Array | Uint32Array, 117 | usage: GLenum = gl.STATIC_DRAW, 118 | ): WebGLBuffer | null { 119 | const buffer = gl.createBuffer() 120 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer) 121 | gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, usage) 122 | return buffer 123 | } 124 | 125 | const cachedExtensions = new Map() 126 | /** 127 | * Obtains and returns a WebGL extension if available. Caches it in-memory for future use. 128 | * @param {WebGLRenderingContext)} gl 129 | * @param {string} extensionName 130 | * @param {boolean} caching 131 | */ 132 | export function getExtension( 133 | gl: WebGLRenderingContext, 134 | extensionName: string, 135 | caching: boolean = false, 136 | ) { 137 | if (caching && cachedExtensions.has(extensionName)) { 138 | return cachedExtensions.get(extensionName) 139 | } 140 | const extension = gl.getExtension(extensionName) 141 | if (caching) { 142 | cachedExtensions.set(extensionName, extension) 143 | } 144 | return extension 145 | } 146 | -------------------------------------------------------------------------------- /src/utils/math.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Clamp number to a given range 3 | * @param {number} num 4 | * @param {number} min 5 | * @param {number} max 6 | * @returns {number} 7 | */ 8 | export const clamp = (num: number, min: number, max: number): number => 9 | Math.min(Math.max(num, min), max) 10 | 11 | /** 12 | * 13 | * @param {number} val 14 | * @param {number} inMin 15 | * @param {number} inMax 16 | * @param {number} outMin 17 | * @param {number} outMax 18 | * @returns {number} 19 | */ 20 | export const mapNumberRange = ( 21 | val: number, 22 | inMin: number, 23 | inMax: number, 24 | outMin: number, 25 | outMax: number, 26 | ): number => { 27 | return ((val - inMin) * (outMax - outMin)) / (inMax - inMin) + outMin 28 | } 29 | 30 | /** 31 | * Check if number is power of 2 32 | * @param {number} value 33 | * @returns {number} 34 | */ 35 | export const isPowerOf2 = (value: number): boolean => 36 | (value & (value - 1)) === 0 37 | 38 | /** 39 | * Normalizes a number 40 | * @param {number} min 41 | * @param {number} max 42 | * @param {number} val 43 | * @returns {number} 44 | */ 45 | export const normalizeNumber = ( 46 | min: number, 47 | max: number, 48 | val: number, 49 | ): number => (val - min) / (max - min) 50 | 51 | /** 52 | * 53 | * @param {number} t 54 | * @returns {number} 55 | */ 56 | export const triangleWave = (t: number): number => { 57 | t -= Math.floor(t * 0.5) * 2 58 | t = Math.min(Math.max(t, 0), 2) 59 | return 1 - Math.abs(t - 1) 60 | } 61 | -------------------------------------------------------------------------------- /src/utils/shader-snippets.js: -------------------------------------------------------------------------------- 1 | import { 2 | MODEL_MATRIX_UNIFORM_NAME, 3 | VIEW_MATRIX_UNIFORM_NAME, 4 | PROJECTION_MATRIX_UNIFORM_NAME, 5 | } from './gl-constants' 6 | 7 | export const vertexShaderSourceHead = ` 8 | uniform mat4 ${MODEL_MATRIX_UNIFORM_NAME}; 9 | uniform mat4 ${VIEW_MATRIX_UNIFORM_NAME}; 10 | uniform mat4 ${PROJECTION_MATRIX_UNIFORM_NAME}; 11 | ` 12 | 13 | export const fragmentShaderSourceHead = ` 14 | precision highp float; 15 | ` 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "ES6", 4 | "target": "ES6", 5 | "allowJs": true, 6 | "outDir": "dist", 7 | "strict": true, 8 | // "inlineSourceMap": true, 9 | "allowSyntheticDefaultImports": true, 10 | "strictNullChecks": true, 11 | "lib": ["ES2016", "ES2017", "DOM"], 12 | "noImplicitAny": false, 13 | "declaration": true, 14 | "declarationDir": "./dist/@types", 15 | "moduleResolution": "node", 16 | }, 17 | "include": [ 18 | "src/**/*", 19 | "node_modules/webgl-strict-types/index.d.ts" 20 | ] 21 | } --------------------------------------------------------------------------------