gsots3d
Version:
Getting S**t On The Screen in 3D. A library for doing 3D graphics in the browser.
1,308 lines (1,292 loc) • 55.9 kB
TypeScript
import { mat4, vec3, quat } from 'gl-matrix';
import log from 'loglevel';
import * as CANNON from 'cannon-es';
import * as twgl from 'twgl.js';
import { ProgramInfo, TextureOptions as TextureOptions$1 } from 'twgl.js';
import { M as MtlMaterial } from './mtl-parser-Cw8gA4Aw.js';
/** A map of uniforms that can be used when WebGL rendering, typically applied with twlg.setUniforms() */
type UniformSet = {
[key: string]: number | number[] | mat4 | WebGLTexture | null;
};
/** This type https://twgljs.org/docs/module-twgl.html#.TextureOptions without exposing twgl types directly */
type TextureOptions = {
[key: string]: number | string | boolean | number[];
};
/**
* Get the WebGL2 context, if it doesn't exist it will be created for the provided canvas element, and memoized
* @returns {WebGL2RenderingContext} - Global WebGL2 context
* @param {boolean} aa - Enable antialiasing
* @param {string} selector - CSS selector for locating the canvas element
*/
declare function getGl(selector?: string, aa?: boolean): WebGL2RenderingContext | undefined;
/** A simple 3D position or vector tuple */
type XYZ = [number, number, number];
/** A simple 4D position or vector tuple */
type XYZW = [number, number, number, number];
/** A simple RGB colour tuple */
type RGB = [number, number, number];
/** A simple RGBA colour tuple */
type RGBA = [number, number, number, number];
/**
* Normalizes a 3-tuple to a unit vector.
* @param tuple The tuple to normalize
*/
declare function normalize(tuple: XYZ | RGB | number[]): XYZ;
/**
* Scales a 3-tuple by a scalar.
* @param tuple The tuple to scale
* @param scale The scalar to scale by
*/
declare function scale(tuple: XYZ | RGB | RGBA | number[], amount: number): XYZ;
/**
* Scales a 3-tuple by a scalar, clamping the result to 0-1.
* @param tuple The tuple to scale
* @param scale The scalar to scale by
*/
declare function scaleClamped(colour: RGB | RGBA, amount: number): RGB | RGBA;
/**
* Converts a 3-tuple to a gl-matrix vec3
* @param tuple The tuple to convert
*/
declare function toVec3(tuple: XYZ): vec3;
/**
* Calculates the distance between two 3-tuples
* @param a First tuple
* @param b Second tuple
*/
declare function distance(a: XYZ, b: XYZ): number;
declare function add(a: XYZ, b: XYZ): XYZ;
/**
* Converts a Cannon.js vector or quaternion to a tuple
* @param value The Cannon.js vector or quaternion to convert
*/
declare function fromCannon(value: CANNON.Vec3 | CANNON.Quaternion): XYZ | XYZW;
/**
* Creates a RGB 3-tuple from 0-255 values.
* @param r Red value (0-255)
* @param g Green value (0-255)
* @param b Blue value (0-255)
*/
declare function rgbColour255(r: number, g: number, b: number): RGB;
/**
* Converts a hex string to an RGB 3-tuple.
* @param hexString
*/
declare function rgbColourHex(hexString: string): RGB;
/**
* A set of common colours as RGB tuples
*/
declare const Colours: {
RED: RGB;
GREEN: RGB;
BLUE: RGB;
YELLOW: RGB;
CYAN: RGB;
MAGENTA: RGB;
BLACK: RGB;
WHITE: RGB;
};
declare const Tuples: {
normalize: typeof normalize;
scale: typeof scale;
scaleClamped: typeof scaleClamped;
rgbColour255: typeof rgbColour255;
rgbColourHex: typeof rgbColourHex;
toVec3: typeof toVec3;
distance: typeof distance;
fromCannon: typeof fromCannon;
add: typeof add;
};
declare enum CameraType {
PERSPECTIVE = 0,
ORTHOGRAPHIC = 1
}
declare class Camera {
/** Camera position */
position: XYZ;
/** Camera look at point, default: [0, 0, 0] */
lookAt: XYZ;
/** Field of view in degrees, default: 45 */
fov: number;
/** Near clipping plane, default: 0.1 */
near: number;
/** Far clipping plane, default: 100 */
far: number;
/** Camera up vector, default: [0, 1, 0] */
up: XYZ;
/** Change camera projection, default: CameraType.PERSPECTIVE */
type: CameraType;
/** Is this camera active, default: true */
active: boolean;
/** Orthographic zoom level, only used when type is orthographic, default: 20 */
orthoZoom: number;
/** Is this camera used for a dynamic environment map, default: false */
usedForEnvMap: boolean;
/** Is this camera used for a shadow map, default: false */
usedForShadowMap: boolean;
/** Aspect ratio of the camera, default: 1 */
aspectRatio: number;
private fpAngleY;
private fpAngleX;
private fpMode;
private fpHandlersAdded;
private fpTurnSpeed;
fpMoveSpeed: number;
private fpFly;
private maxAngleUp;
private maxAngleDown;
private keysDown;
private touches;
/**
* Create a new default camera
*/
constructor(type?: CameraType, aspectRatio?: number);
/**
* Get the current view matrix for the camera
*/
get matrix(): mat4;
/**
* Get the projection matrix for this camera
* @param aspectRatio Aspect ratio of the canvas
*/
get projectionMatrix(): mat4;
/**
* Get the center of the camera view frustum
* @param scale how much to scale the frustum towards the far plane, default: 1
* @returns Point in world space
*/
getFrustumCenter(scaleFar?: number): XYZ;
/**
* Get the corners of the view frustum for this camera in world space
* @param scaleFar Scale the far plane to bring the frustum closer, default: 1
*/
frustumCornersWorld(scaleFar?: number): {
nearTopLeftWorld: vec3;
nearTopRightWorld: vec3;
nearBottomLeftWorld: vec3;
nearBottomRightWorld: vec3;
farTopLeftWorld: vec3;
farTopRightWorld: vec3;
farBottomLeftWorld: vec3;
farBottomRightWorld: vec3;
center: vec3;
};
/**
* Get the camera position as a string for debugging
*/
toString(): string;
/**
* Switches the camera to first person mode, where the camera is controlled by
* the mouse and keyboard. The mouse controls look direction and the keyboard
* controls movement.
* @param angleY Starting look up/down angle in radians, default 0
* @param angleX Starting look left/right angle in radians, default 0
* @param turnSpeed Speed of looking in radians, default 0.001
* @param moveSpeed Speed of moving in units, default 1.0
*/
enableFPControls(angleY?: number, angleX?: number, turnSpeed?: number, moveSpeed?: number, fly?: boolean): void;
/**
* Disable FP mode
*/
disableFPControls(): void;
/**
* Get FP mode state
*/
get fpModeEnabled(): boolean;
/**
* Called every frame to update the camera, currently only used for movement in FP mode
*/
update(): void;
}
/**
* Options to configure how shadows are calculated & rendered
*/
type ShadowOptions = {
/** Size of the shadow map texture. Default: 512 */
mapSize: number;
/** Zoom level of the shadow map camera, larger will cover more of the scene, but results in more blocky shadows. Default 120 */
zoom: number;
/** Far clipping pane of shadow map camera, default 1000 */
distance: number;
/** Blur the edges of shadows, higher values them more random, default 0.2 */
/** Offset used to reduce shadow acne especially when self shadowing */
polygonOffset: number;
};
/**
* A directional light source, typically global with the context having only a single instance
* Having multiple directional lights is not supported
*/
declare class LightDirectional {
private _direction;
private _shadowMapProgram?;
private _shadowMapFB?;
private _shadowMapTex?;
private _shadowOptions?;
/** Colour of the light, used for both diffuse and specular. Default: [0, 0, 0] */
colour: RGB;
/** Ambient colour of the light. Default: [0, 0, 0] */
ambient: RGB;
/** Is this light enabled. Default: true */
enabled: boolean;
/** Create a default directional light, pointing downward */
constructor();
/**
* Set the direction of the light ensuring it is normalized
* @param direction - Direction vector
*/
set direction(direction: XYZ);
/**
* Get the direction of the light
*/
get direction(): XYZ;
/**
* Convenience method allows setting the direction as a point relative to the world origin
* Values are always converted to a normalized unit direction vector
* @param x - X position
* @param y - Y position
* @param z - Z position
*/
setAsPosition(x: number, y: number, z: number): void;
/**
* Return the base set of uniforms for this light
*/
get uniforms(): UniformSet;
/**
* Enable shadows for this light, this will create a shadow map texture and framebuffer
* There is no way to disabled shadows once enabled
* @param options A set of ShadowOptions to configure how shadows are calculated
*/
enableShadows(options?: ShadowOptions): void;
/**
* Get a virtual camera that can be used to render a shadow map for this light
* @param viewCam - The main camera used to view the scene, needed to get a good shadow view
*/
getShadowCamera(viewCam: Camera): Camera | undefined;
/**
* Get the forward view matrix for the virtual camera used to render the shadow map.
* Returns undefined if shadows are not enabled
* @param viewCam - The main camera used to view the scene, needed to get a good shadow view
*/
getShadowMatrix(viewCam: Camera): mat4 | undefined;
/**
* Are shadows enabled for this light?
*/
get shadowsEnabled(): boolean;
/**
* Get the shadow map program, will be undefined if shadows are not enabled
*/
get shadowMapProgram(): twgl.ProgramInfo | undefined;
/**
* Get the shadow map framebuffer, will be undefined if shadows are not enabled
*/
get shadowMapFrameBufffer(): twgl.FramebufferInfo | undefined;
/**
* Get the shadow map texture, will be undefined if shadows are not enabled
*/
get shadowMapTexture(): WebGLTexture | undefined;
/**
* Get the shadow map options, will be undefined if shadows are not enabled
*/
get shadowMapOptions(): ShadowOptions | undefined;
}
declare class LightPoint {
/** Position of the light in world space. */
position: XYZ;
/** Colour of the light. Default: [1, 1, 1] */
colour: RGB;
/** Ambient colour of the light. Normally none for point lights. Default [0, 0, 0] */
ambient: RGB;
/** Light attenuation parameter for constant drop off rate. Default: 0.5 */
constant: number;
/** Light attenuation parameter for linear drop off rate. Default: 0.018 */
linear: number;
/** Light attenuation parameter for quadratic drop off rate. Default: 0.0003 */
quad: number;
/** Is this light enabled? Default: true */
enabled: boolean;
/** Metadata is a key/value store for any extra data you want to store on a node */
metadata: Record<string, string | number | boolean>;
/**
* Create a default point light, positioned at the world origin
* @param position - Position of the light in world space
* @param colour - Colour of the light
* @param constant - Attenuation constant drop off rate, default 0.5
* @param linear - Attenuation linear drop off rate, default 0.018
* @param quad - Attenuation quadratic drop off rate, default 0.0003
*/
constructor(position: XYZ, colour: RGB, constant?: number, linear?: number, quad?: number);
/**
* Return the base set of uniforms for this light
*/
get uniforms(): UniformSet;
}
declare class Material {
/**
* Ambient colour will be multiplied with the ambient light level & colour
*/
ambient: RGB;
/**
* Diffuse colour will be multiplied with the diffuse texture
* @default [1, 1, 1]
*/
diffuse: RGB;
/**
* Specular colour will be multiplied with the specular texture
* @default [0, 0, 0]
*/
specular: RGB;
/**
* Emissive colour will be added to the final colour, use for glowing materials
*/
emissive: RGB;
/**
* Shininess, for size of specular highlights
* @default 20
*/
shininess: number;
/**
* Opacity, 0.0 to 1.0
* @default 1.0
*/
opacity: number;
/**
* Reflectivity, 0.0 to 1.0
* @default 0.0
*/
reflectivity: number;
/**
* Diffuse texture map
* @default "1 pixel white texture"
*/
diffuseTex?: WebGLTexture;
/**
* Specular texture map
* @default "1 pixel white texture"
*/
specularTex?: WebGLTexture;
/**
* Normal texture map
* @default "1 pixel white texture"
*/
normalTex?: WebGLTexture;
/**
* Transparency threshold, pixels with alpha below this value will be discarded
* @default 0.0
*/
alphaCutoff: number;
additiveBlend: boolean;
/**
* Create a new default material with diffuse white colour, all all default properties
*/
constructor();
/**
* Create a new material from a raw MTL material. Users are not expected to call this directly as it is used internally by the OBJ parser
* @param rawMtl Raw MTL material
* @param basePath Base path for locating & loading textures in MTL file
* @param filter Apply texture filtering to textures, default: true
* @param flipY Flip the Y axis of textures, default: false
*/
static fromMtl(rawMtl: MtlMaterial, basePath: string, filter?: boolean, flipY?: boolean): Material;
/**
* Create a basic Material with a solid/flat diffuse colour
* @param r Red component, 0.0 to 1.0
* @param g Green component, 0.0 to 1.0
* @param b Blue component, 0.0 to 1.0
*/
static createSolidColour(r: number, g: number, b: number): Material;
/**
* Create a new Material with a texture map loaded from a URL/filepath or Buffer
* @param src URL or filename path of texture image, or ArrayBufferView holding texture
* @param filter Enable texture filtering and mipmaps (default true)
* @param flipY Flip the texture vertically (default false)
* @param extraOptions Extra options to pass to twgl.createTexture, see https://twgljs.org/docs/module-twgl.html#.TextureOptions
*/
static createBasicTexture(src: string | ArrayBufferView, filter?: boolean, flipY?: boolean, extraOptions?: TextureOptions): Material;
/**
* Add a specular texture map to existing material, probably created with createBasicTexture
* @param url
* @param filter
*/
addSpecularTexture(url: string, filter?: boolean, flipY?: boolean): void;
/**
* Add a normal texture map to existing material, probably created with createBasicTexture
* @param url
* @param filter
*/
addNormalTexture(url: string, filter?: boolean, flipY?: boolean): void;
/** Create a simple diffuse red Material */
static get RED(): Material;
/** Create a simple diffuse green Material */
static get GREEN(): Material;
/** Create a simple diffuse blue Material */
static get BLUE(): Material;
/** Create a simple diffuse white Material */
static get WHITE(): Material;
/** Create a simple diffuse black Material */
static get BLACK(): Material;
/** Create a simple diffuse yellow Material */
static get YELLOW(): Material;
/** Create a simple diffuse magenta Material */
static get MAGENTA(): Material;
/** Create a simple diffuse cyan Material */
static get CYAN(): Material;
/**
* Adds this material to a program, as a set of uniforms
* @param programInfo ProgramInfo object to update with uniforms
* @param uniformSuffix Optional suffix to add to uniform names
*/
apply(programInfo: twgl.ProgramInfo, uniformSuffix?: string): void;
/**
* Return the base set of uniforms for this material
* @returns UniformSet object with all material properties
*/
get uniforms(): UniformSet;
/**
* Clone this material, returns a new material with the same properties
*/
clone(): Material;
}
declare class EnvironmentMap {
private programInfo;
private gl;
private _texture;
private cube;
/**
* Render the environment map as a background, like a skybox
*/
renderAsBackground: boolean;
/**
* Create a new environment map with 6 textures for each side
* @param gl GL context
* @param textureURLs Array of 6 texture URLs, in order: +x, -x, +y, -y, +z, -z
*/
constructor(gl: WebGL2RenderingContext, textureURLs: string[]);
/**
* Render this envmap as a cube around the given camera & matrices
* This is used for rendering the envmap as a background and skybox around the scene
* @param viewMatrix View matrix
* @param projMatrix Projection matrix
* @param camera Camera
*/
render(viewMatrix: mat4, projMatrix: mat4, camera: Camera): void;
get texture(): WebGLTexture;
}
/**
* Used for rendering a dynamic environment map, to create realtime reflections
* For performance reasons, there is only one dynamic envmap per scene context
*/
declare class DynamicEnvironmentMap {
private _texture;
private facings;
private camera;
/**
* Create a new dynamic environment map
* @param gl GL context
* @param size Size of each face of the cube map
* @param position Position of the center of the cube map, reflections will be rendered from here
*/
constructor(gl: WebGL2RenderingContext, size: number, position: XYZ, far: number);
/** Get the texture of the environment cubemap */
get texture(): WebGLTexture;
/**
* This is used to position the camera for creating the reflection map
* @param position Position of the center of the cube map
*/
set position(pos: XYZ);
/**
* Update the environment map, by rendering the scene from the given position into the cubemap texture
* @param ctx GSOTS Context
*/
update(gl: WebGL2RenderingContext, ctx: Context): void;
}
/**
* Models and primitives implement this interface to be rendered
*/
interface Renderable {
/** Called to render this render-able thing */
render(gl: WebGL2RenderingContext, uniforms: UniformSet, materialOverride?: Material, programOverride?: ProgramInfo): void;
}
/** Event triggered when a node position, rotation or scale changes */
type NodeEvent = {
position: XYZ;
rotation: XYZW;
scale: XYZ;
nodeId: string;
};
/**
* A Node with position, rotation, scale, all Instances extend this class.
* But Nodes also be created to group instances and simplify transformations.
*/
declare class Node {
/** Unique ID for this node */
readonly id: string;
/** Position of this Node in world space, relative to any parent nodes (if any) */
position: XYZ;
/** Scale of this Node in world space, relative to any parent nodes (if any) */
scale: XYZ;
/** Rotation quaternion of this Node in world space, relative to any parent nodes (if any) */
quaternion: quat;
/** Metadata is a key/value store for any extra data you want to store on a node */
metadata: Record<string, string | number | boolean>;
private _receiveShadow;
private _castShadow;
private _enabled;
private _parent?;
private _children;
private _physicsBody?;
private eventHandlers;
/** Create a default node, at origin with scale of [1,1,1] and no rotation */
constructor();
/** Rotate this instance around the X, Y and Z axis in radians */
rotate(ax: number, ay: number, az: number): void;
/** Rotate this instance around the X axis*/
rotateX(angle: number): void;
/** Rotate this instance around the Y axis*/
rotateY(angle: number): void;
/** Rotate this instance around the Z axis, in radians*/
rotateZ(angle: number): void;
/** Rotate this instance around the X axis by a given angle in degrees */
rotateZDeg(angle: number): void;
/** Rotate this instance around the Y axis by a given angle in degrees */
rotateYDeg(angle: number): void;
/** Rotate this instance around the Z axis by a given angle in degrees */
rotateXDeg(angle: number): void;
/** Set the rotation quaternion directly, normally users should use the rotate methods.
* This method is for advanced uses, like integration with an external physics system */
setQuaternion(quatArray: XYZW): void;
/** Get the rotation quaternion as a XYZW 4-tuple */
getQuaternion(): XYZW;
/**
* Return the world or model matrix for this node, this is the matrix that places this node in the world.
* This will be in relation to the parent node, if there is one.
*/
get modelMatrix(): mat4;
/** Convenience method to make another Node a child of this one */
addChild(node: Node): void;
/** Convenience method to remove a child Node */
removeChild(node: Node): void;
/** Convenience method to remove all child Nodes */
removeAllChildren(): void;
/** Sets the parent this Node, to the provided Node */
set parent(node: Node | undefined);
/** Fetch all child Nodes of this Node */
get children(): Node[];
/** Get current parent of this Node */
get parent(): Node | undefined;
/** Is this Node enabled. Disabled nodes will not be rendered */
get enabled(): boolean;
/** Set enabled state of this Node, this will also set all child nodes */
set enabled(enabled: boolean);
/** Does this Node cast shadows, default true */
get castShadow(): boolean;
/** Set will this Node cast shadows, this will also set all child nodes */
set castShadow(value: boolean);
/** Does this Node receive shadows, default true */
get receiveShadow(): boolean;
/** Set will this Node receive shadows, this will also set all child nodes */
set receiveShadow(value: boolean);
/** Get the physics body for this Node, if there is one */
get physicsBody(): CANNON.Body | undefined;
/** Set the physics body for this Node */
set physicsBody(body: CANNON.Body | undefined);
/**
* Updates the position & rotation of this node to match it's linked physics Body
* This is called automatically by the engine, but can be called manually if needed
*/
updateFromPhysicsBody(): void;
/**
* Add an event handler to listen for node changes
* @param event NodeEvent type, one of 'position', 'rotation', 'scale'
* @param handler Function to call when event is triggered
*/
addEventHandler(event: string, handler: (event: NodeEvent) => void): void;
}
/**
* An instance of thing in the world to be rendered, with position, rotation, scale etc
*/
declare class Instance extends Node {
/** Main renderable thing this instance represents */
readonly renderable: Renderable | undefined;
/** Flip all textures on this instance on the X axis */
flipTextureX: boolean;
/** Flip all textures on this instance on the Y axis */
flipTextureY: boolean;
/** Material override. This will override the renderable's material.
* This is only useful on simple models that probably consist of one surface */
material?: Material;
/** Inject additional uniforms to the shader for this instance.
* Prefix with `u_mat.` e.g. `u_mat.diffuse` to change material properties for a single instance.
* Warning an advanced feature! */
uniformOverrides?: UniformSet;
/** Very advanced feature, set this to plugin a custom shader program
* Use ProgramCache.compileShader to create a named program */
customProgramName?: string;
/**
* Create a new instance of a renderable thing
* @param {Renderable} renderable - Renderable to use for this instance
*/
constructor(renderable: Renderable);
setPosition(x: number | XYZ, y?: number, z?: number): void;
/**
* Render this instance in the world, called internally by the context when rendering
* @param {WebGL2RenderingContext} gl - WebGL context to render into
* @param {UniformSet} uniforms - Map of uniforms to pass to shader
*/
render(gl: WebGL2RenderingContext, uniforms: UniformSet, programOverride?: ProgramInfo): void;
}
/** Billboarding modes, most things will ue NONE */
declare enum BillboardType {
SPHERICAL = 0,
CYLINDRICAL = 1
}
/**
* A simple 2D billboard, like a tree or grass. These are square by default, but can be scaled XY if needed.
* Both cylindrical and spherical billboards are supported. You must assign material with a texture
* to be rendered as a sprite on the billboard
* @see http://www.opengl-tutorial.org/intermediate-tutorials/billboards-particles/billboards/
*/
declare class Billboard implements Renderable {
protected bufferInfo: twgl.BufferInfo;
private programInfo;
material: Material;
type: BillboardType;
/** Creates a square billboard */
constructor(gl: WebGL2RenderingContext, type: BillboardType, material: Material, size: number);
/**
* Render is used draw this billboard, this is called from the Instance that wraps
* this renderable
*/
render(gl: WebGL2RenderingContext, uniforms: UniformSet, materialOverride?: Material): void;
}
/**
* Particle system, uses transform feedback on the GPU to update particles
* and VAO instancing to render them
*/
declare class ParticleSystem implements Renderable {
private progInfoUpdate;
private progInfoRender;
private inputBuffInfo;
private outputBuffInfo;
private outputVAO;
/** When enabled, particles will be spawned and emitted */
enabled: boolean;
/** Texture to use for particles */
texture: WebGLTexture;
/** Emission rate, number of particles per frame */
emitRate: number;
/** Min lifetime of particles in seconds */
minLifetime: number;
/** Max lifetime of particles in seconds */
maxLifetime: number;
/** Gravity vector. Default: [0, -9.81, 0] */
gravity: XYZ;
/** Min power (speed) of particles, this is multiplied by the direction vector */
minPower: number;
/** Max power (speed) of particles, this is multiplied by the direction vector */
maxPower: number;
/** Particles will randomly emit in a direction between this vector and direction2 */
direction1: XYZ;
/** Particles will randomly emit in a direction between this vector and direction1 */
direction2: XYZ;
/** Particles are spawned in a bounding box, defined by this vector as one corner */
emitterBoxMin: XYZ;
/** Particles are spawned in a bounding box, defined by this vector as one corner */
emitterBoxMax: XYZ;
/** Speed up or slow down time */
timeScale: number;
/** Change colour and alpha as particle reaches it's lifetime. Default: [0,0,0,1] */
ageColour: RGBA;
/** Min random size of particles */
minSize: number;
/** Max random size of particles */
maxSize: number;
/** Min initial random rotation of particles in radians */
minInitialRotation: number;
/** Max initial random rotation of particles in radians */
maxInitialRotation: number;
/** Min random rotation speed of particles in radians per second */
minRotationSpeed: number;
/** Max random rotation speed of particles in radians per second */
maxRotationSpeed: number;
/** Duration of particle system in frames, -1 = forever. Default: -1 */
duration: number;
/** Acceleration or deceleration multiplier, default 1.0. Applied every frame, so keep values *very* close to 1.0 */
acceleration: number;
/** Blend source mode, default: 'SRC_ALPHA', leave alone unless you know what you are doing */
blendSource: number;
/** Blend destination mode, default: 'ONE', leave alone unless you know what you are doing */
blendDest: number;
/** Colour multiplier pre-applied to particle texture before ageing */
preColour: RGBA;
/** Age power curve */
agePower: number;
/** Particles transformed fixed to local coordinate space, generally leave as false */
localSpace: boolean;
/**
* Create a new particle system
* @param gl WebGL2 rendering context
* @param maxParticles Maximum number of particles in the system
* @param baseSize Size of the particle quad
*/
constructor(gl: WebGL2RenderingContext, maxParticles: number, baseSize: number);
/**
* Render the particle system and implement the renderable interface
* @param gl WebGL2 rendering context
* @param uniforms Uniforms to pass to the shaders
*/
render(gl: WebGL2RenderingContext, uniforms: UniformSet): void;
/**
* Update the particles positions and velocities
*/
private updateParticles;
/**
* Render the particles to the world
*/
private renderParticles;
}
declare class HUD {
private hud;
private canvas;
private debugDiv;
private loadingDiv;
debug: boolean;
constructor(canvas: HTMLCanvasElement);
/**
* Update the HUD position and size to match the canvas
*/
private updateWithCanvas;
/**
* Add a HTML element to the HUD
* @param item HTML element to add
*/
addHUDItem(item: HTMLElement): void;
/**
* Render the HUD, called once per frame
*/
render(debug: boolean | undefined, camera: Camera): void;
/**
* Hide the loading message, this is called by the engine
*/
hideLoading(): void;
}
/**
* A builder for creating multi-part models from triangle meshes
* Use in conjunction Model.parseFromBuilder
*
* Example usage:
* ```typescript
* const builder = new ModelBuilder()
* const part = builder.newPart('foo' Material.RED)
* builder.addTriangle([1, -1, 1], [1, 1, 1], [-1, 1, 1])
* Model.parseFromBuilder(builder, 'myModel')
* ```
*/
declare class ModelBuilder {
readonly parts: Map<string, BuilderPart>;
constructor();
/**
* Create and add a 'part', each part should have a unique name, and material to apply to it
* Vertex mesh data is then added to the part, with addQuad and addTriangle
* @param name Name of this part, just a string can be anything
* @param material Material to attach and apply to all surfaces in this part
*/
newPart(name: string, material: Material): BuilderPart;
}
type extraAttributes = {
[key: string]: {
numComponents: number;
data: number[];
};
};
/**
* Manage parts or sections to be built into a model
*/
declare class BuilderPart {
private vertexData;
private vertexCount;
private indexData;
private indexCount;
private normalData;
private texcoordData;
private _boundingBox;
material: Material;
readonly name: string;
/**
* This is an *extremely* advanced feature, and allows you to add custom attributes to the part
* You will need to understand how to use twgl.js to use this feature at the createBufferInfoFromArrays function
*/
extraAttributes?: extraAttributes;
get boundingBox(): number[];
private _triCount;
get triangleCount(): number;
private _customArrayData;
constructor(name: string, mat: Material);
private addVertex;
private addIndex;
private addNormal;
/**
* Add a triangle to the renderable part
* Each triangle must be defined by 3 vertices and will get a normal calculated
* Each triangle will get a unique normal, so no smooth shading
* @param v1 Vertex 1 of the triangle
* @param v2 Vertex 2 of the triangle
* @param v3 Vertex 3 of the triangle
* @param tc1 Texture coordinate for vertex 1
* @param tc2 Texture coordinate for vertex 2
* @param tc3 Texture coordinate for vertex 3
*/
addTriangle(v1: XYZ, v2: XYZ, v3: XYZ, tc1?: number[], tc2?: number[], tc3?: number[]): void;
/**
* Add a two triangle quad to the renderable part
* Each quad must be defined by 4 vertices and will get a normal calculated
* Each quad will get a unique normal, so no smooth shading
* @param v1 Vertex 1 of the quad
* @param v2 Vertex 2 of the quad
* @param v3 Vertex 3 of the quad
* @param v4 Vertex 4 of the quad
* @param tc1 UV texture coordinate for vertex 1
* @param tc2 UV texture coordinate for vertex 2
* @param tc3 UV texture coordinate for vertex 3
* @param tc4 UV texture coordinate for vertex 4
*/
addQuad(v1: XYZ, v2: XYZ, v3: XYZ, v4: XYZ, tc1?: number[], tc2?: number[], tc3?: number[], tc4?: number[]): void;
/**
* This is a very advanced feature, and allows you to provide your own twgl.Arrays
* This is useful for creating custom renderables from existing data
* @param array The twgl.Arrays to use for the renderable
*/
set customArrayData(array: twgl.Arrays);
/**
* Build the part from the data added and turn into a twgl.BufferInfo
* @param gl A WebGL2 rendering context
* @returns BufferInfo used by twgl
*/
build(gl: WebGL2RenderingContext): twgl.BufferInfo | null;
}
/**
* The main rendering context. This is the effectively main entry point for the library.
* Typically you will create a single instance of this class using init() and use it to render your scene.
*/
declare class Context {
private gl;
private started;
private instances;
private instancesTrans;
private instancesParticles;
private cameras;
private activeCameraName;
private _envmap?;
private dynamicEnvMap?;
private renderPass;
/** Global directional light */
globalLight: LightDirectional;
/** All the dynamic point lights in the scene */
lights: LightPoint[];
/** Main camera for this context */
private _camera;
/** Show extra debug details on the canvas */
debug: boolean;
/** Optional post effects filter to apply to the output image */
private postEffects?;
/**
* The pre-render update function, called every frame.
* Hook in your custom logic and processing here
*/
update: (delta: number, now?: number) => void;
/** A HUD you can use to render HTML elements over the canvas */
readonly hud?: HUD;
/** Gamma correction value, default 1.0 */
gamma: number;
/**
* Integration with cannon-es for physics, set the CANNON.World you are using here.
* When set, world stepping will be called for you in the core rendering loop
*/
physicsWorld?: CANNON.World;
/** Set the fixed time step for physics stepping, only used when physicsWorld is set */
physicsTimeStep: number;
/** Backface culling */
disableCulling: boolean;
/**
* Blend mode for non-opaque instances
* 'NORMAL' is the default, 'ADDITIVE' is useful for particles and glowing effects
*/
blendMode: 'NORMAL' | 'ADDITIVE';
version: string;
/** Get the active camera */
get camera(): Camera;
/** Get the name of the active camera */
get cameraName(): string;
/** Get the current EnvironmentMap for the scene */
get envmap(): EnvironmentMap | undefined;
/** Constructor is private, use init() to create a new context */
private constructor();
/**
* Create & initialize a new Context which will render into provided canvas. This is where you start when using the library.
* @param canvasSelector CSS selector for canvas element, default is 'canvas'
* @param antiAlias Enable anti-aliasing in the renderer, default is true
*/
static init(canvasSelector?: string, antiAlias?: boolean, noHud?: boolean): Promise<Context>;
/**
* Main render loop, called every frame by the context when started
* @param now Current time in milliseconds
*/
private render;
/**
* Render the scene from the given camera, used internally for rendering both the main view,
* but also shadow maps and dynamic env maps
* @param camera
*/
renderWithCamera(camera: Camera, programOverride?: twgl.ProgramInfo): void;
/**
* Start the rendering loop, without calling this nothing will render
*/
start(): void;
/**
* Stop the rendering loop
*/
stop(): void;
/**
* Set the log level for the library
* @param level - Log level to set, default is 'info'
*/
setLogLevel(level: log.LogLevelNames): void;
/**
* Resize the canvas & viewport to match the size of the HTML element that contains it
* @param viewportOnly - Only resize the GL viewport, not the canvas, default false
*/
resize(viewportOnly?: boolean): void;
/**
* Internal function to add an instance to the scene
*/
private addInstance;
/**
* Model loader, loads an OBJ model from a file via URL or path and adds it to the cache
* This is preferred over calling Model.parse() directly
* @param path Base path to the model file, e.g. './renderable/'
* @param fileName Name of the model file, e.g 'teapot.obj'
* @param filterTextures Apply texture filtering as materials are loaded
* @param flipTextureY Flip the Y coordinate of the texture
*/
loadModel(path: string, fileName: string, filterTextures?: boolean, flipY?: boolean, flipUV?: boolean): Promise<void>;
/**
* Add or replace a named camera to the scene
* @param name Name of the camera
* @param camera Camera instance
*/
addCamera(name: string, camera: Camera): void;
/**
* Get a camera by name
* @param name Name of the camera
*/
getCamera(name: string): Camera | undefined;
/**
* Set the active camera, rendering will switch to this camera's view
* @param name Name of the camera to set as active
*/
setActiveCamera(name: string): void;
/**
* Create a new model instance, which should have been previously loaded into the cache
* @param modelName - Name of the model previously loaded into the cache, don't include the file extension
*/
createModelInstance(modelName: string, transparent?: boolean): Instance;
/**
* Create an instance of a primitive sphere
* @param material - Material to apply to the sphere
* @param radius - Radius of the sphere
* @param subdivisionsH - Number of subdivisions along the horizontal
* @param subdivisionsV - Number of subdivisions along the vertical
*/
createSphereInstance(material: Material, radius?: number, subdivisionsH?: number, subdivisionsV?: number): Instance;
/**
* Create an instance of a primitive plane
* @param material - Material to apply to the plane
* @param width - Width of the plane
* @param height - Height of the plane
* @param subdivisionsW - Number of subdivisions along the width
* @param subdivisionsH - Number of subdivisions along the height
* @param tiling - Number of times to tile the texture over the plane
*/
createPlaneInstance(material: Material, width?: number, height?: number, subdivisionsW?: number, subdivisionsH?: number, tiling?: number): Instance;
/**
* Create an instance of a primitive cube
*/
createCubeInstance(material: Material, size?: number, tilingFactor?: number): Instance;
/**
* Create an instance of a primitive cylinder
*/
createCylinderInstance(material: Material, r?: number, h?: number, subdivisionsR?: number, subdivisionsH?: number, caps?: boolean): Instance;
/**
* Create an instance of a billboard/sprite in the scene
* @param textureUrl - Path to the texture image file to use for the billboard
* @param width - Width of the billboard (default: 5)
* @param height - Height of the billboard (default: 5)
* @param type - Type of billboard to create (default: CYLINDRICAL)
*/
createBillboardInstance(material: Material, size?: number, type?: BillboardType): Instance;
/**
* Create a new point light in the scene
* @param position - Position of the light
* @param colour - Colour of the light, defaults to white
* @param intensity - Intensity of the light
* @returns The new light object
*/
createPointLight(position: XYZ, colour?: RGB, intensity?: number): LightPoint;
/**
* Create a new particle system in the scene
* @param maxParticles Maximum number of particles to allow in the system
* @param baseSize Base size of the particles, default 2
* @returns Both the instance and the particle system
*/
createParticleSystem(maxParticles?: number, baseSize?: number): {
instance: Instance;
particleSystem: ParticleSystem;
};
/**
* Set the EnvironmentMap for the scene, will overwrite any existing envmap.
* This will enable static reflections and create a 'skybox' around the scene
* @param textureURLs - Array of 6 texture URLs to use for the map, in the order: +X, -X, +Y, -Y, +Z, -Z
*/
setEnvmap(renderAsBackground?: boolean, ...textureURLs: string[]): void;
/**
* Remove any current EnvironmentMap from the scene
*/
removeEnvmap(): void;
/**
* Set and create a dynamic environment map which will enable dynamic/realtime reflections
* @param position - Position to render reflections from
* @param size - Size of the map to render, note higher sizes will come with a big performance hit
*/
setDynamicEnvmap(position: XYZ, size?: number, renderDistance?: number): void;
/**
* Remove instance from the scene, it will no longer be rendered
* @param instance - Instance to remove
*/
removeInstance(instance: Instance): void;
/**
* Remove all instances from the scene
*/
removeAllInstances(): void;
/**
* Use a custom shader for post effects, user must provide their own shader
* @param shaderCode - GLSL shader code for the post effect
*/
setEffectCustom(shaderCode: string): void;
/**
* Use bulit-in scanlines post effect shader
* @param density - Density of the scanlines, default 1.5
* @param opacity - Opacity of the scanlines, default 0.5
* @param noise - Noise level, default 0.2
* @param flicker - Flicker ammount, default 0.015
*/
setEffectScanlines(density?: number, opacity?: number, noise?: number, flicker?: number): void;
/**
* Use bulit-in glitch post effect shader
* @param amount - Amount of glitch, default 0.01
*/
setEffectGlitch(amount?: number): void;
/**
* Use bulit-in noise post effect shader
* @param amount - Amount of noise, default 0.1
* @param speed - Speed of noise pattern, default 5.0
*/
setEffectNoise(amount?: number, speed?: number): void;
/**
* Use bulit-in duotone post effect shader for monotone images
* @param colour1 - First colour, default [0.15, 0.09, 0.309]
* @param colour2 - Second colour, default [0.96, 0.39, 0.407]
* @param contrast - Contrast, default 1.5
*/
setEffectDuotone(colour1?: RGB, colour2?: RGB, contrast?: number): void;
/**
* Use bulit-in contrast post effect shader, which reduces the image to two solid colours
* @param threshold
* @param darkColour
* @param lightColour
*/
setEffectContrast(threshold?: number, darkColour?: RGB, lightColour?: RGB): void;
/**
* Remove any post effects shader
*/
removeEffect(): void;
/**
* Create and build a custom model from a ModelBuilder and cache it for use
* @param builder Builder with geometry and materials added
* @param name Name of the model
*/
buildCustomModel(builder: ModelBuilder, name: string): void;
}
/**
* Holds a 3D model, as a list of parts, each with a material
* Plus map of named materials
*/
declare class Model implements Renderable {
private programInfo;
private readonly parts;
private readonly materials;
private triCount;
private _boundingBox;
/** Name of the model, usually the filename without the extension */
readonly name: string;
/**
* Constructor is private, use static `parse()` method instead
*/
private constructor();
/**
* Render is used draw this model, this is called from the Instance that wraps
* this renderable.
*/
render(gl: WebGL2RenderingContext, uniforms: UniformSet, materialOverride?: Material, programOverride?: twgl.ProgramInfo): void;
/** Simple getter for the number of triangles in the model */
get triangleCount(): number;
/**
* Parse an OBJ file & MTL material libraries, returns a new Model
* @param {string} path - The path to the OBJ file
* @param {string} objFilename - The name of the OBJ file
* @param {boolean} filterTextures - Apply texture filtering to textures, default: true
* @param {boolean} flipTextureY - Flip the Y axis of textures as they are loaded, default: false
* @param {boolean} flipUV - Flip the UV coords of the model in the vertex/mesh data, default: true
*/
static parse(path: string | undefined, objFilename: string, filterTextures?: boolean, flipTextureY?: boolean, flipUV?: boolean): Promise<Model>;
/**
* Parse a custom model from a ModelBuilder, this is used to build models in code
* @param {ModelBuilder} builder - The ModelBuilder to parse
* @param {string} name - The name of the model
*/
static parseFromBuilder(builder: ModelBuilder, name: string): Model;
/**
* Get list of all material names in this model used by all parts
* @returns {string[]} - List of material names
*/
get materialNames(): string[];
/**
* Get number of parts in this model
*/
get partsCount(): number;
/**
* Get list of parts in this model, names are the material names
* @returns {string[]} - List of part material names
*/
get partList(): string[];
/**
* Can modify & override an existing named material
* @param {string} name - Name of the material to modify
* @param {Material} material - New material to use
*/
setNamedMaterial(name: string, material: Material): void;
/**
* Get a named material
* @param {string} name - Name of the material to get
*/
getNamedMaterial(name: string): Material;
get boundingBox(): number[];
}
/**
* Holds part of a model, as the WebGL buffers needed to render it
* Plus the material name associated with this part
*/
declare class ModelPart {
readonly bufferInfo: twgl.BufferInfo;
readonly materialName: string;
/**
* @param {twgl.BufferInfo} bufferInfo - WebGL buffer info for this model part
* @param {string} materialName - Name of the material associated with this part
*/
constructor(bufferInfo: twgl.BufferInfo, materialName: string);
}
/** @ignore */
declare const PROG_DEFAULT = "phong";
/** @ignore */
declare const PROG_BILLBOARD = "billboard";
/**
* A singleton cache for parsed and loaded models, indexed by name
*/
declare class ModelCache {
private cache;
private static _instance;
private constructor();
/**
* Return the singleton instance of the model cache
*/
static get instance(): ModelCache;
/**
* Return a model from the cache by name
* @param name Name of model without extension
* @param warn If true, log a warning if model not found
*/
get(name: string, warn?: boolean): Model | undefined;
/**
* Add a model to the cache, using the model name as key
*/
add(model: Model): void;
}
/**
* A caching texture manager
* It is instantiated with a WebGL context and then used to load and cache textures
*/
declare class TextureCache {
private cache;
private gl;
private static _instance;
private static initialized;
private defaultWhite;
private defaultRand;
private constructor();
static init(gl: WebGL2RenderingContext, randSize?: number): void;
/**
* Return the singleton instance of the texture cache
*/
static get instance(): TextureCache;
/**
* Return a texture from the cache by name
* @param key Key of texture, this is usually the URL or filename path
*/
get(key: string): WebGLTexture | undefined;
/**
* Add a texture to the cache
* @param key Key of texture, this is usually the URL or filename path
* @param texture WebGL texture
*/
add(key: string, texture: WebGLTexture): void;
/**
* Create or return a texture from the cache by name
* @param src URL or filename path of texture image, or ArrayBufferView holding texture
* @param filter Enable texture filtering and mipmaps (default true)
* @param flipY Flip the texture vertically (default true)
* @param textureKey Unique key, only used for ArrayBuffer textures
* @param extraOptions Extra options to pass to twgl.createTexture, see https://twgljs.org/docs/module-twgl.html#.TextureOptions
*/
getCreate(src: string | ArrayBufferView, filter?: boolean, flipY?: boolean, textureKey?: string, extraOptions?: TextureOptions$1): WebGLTexture | undefined;
/**
* Return the default white 1x1 texture
*/
static get defaultWhite(): WebGLTexture;
/**
* Return the default random RGB texture
*/
static get defaultRand(): WebGLTexture;
/**
* Return the number of textures in the cache
*/
static get size(): number;
/**
* Clear the texture cache
*/
static clear(): void;
}
/**
* Singleton cache for parsed and loaded GL programs, indexed by name
*/
declare class ProgramCache {
private cache;
private _default;
private static _instance;
private static initialized;
static PROG_PHONG: string;
static PROG_BILLBOARD: string;
static PROG_SHADOWMAP: string;
/**
* Create a new program cache, can't be used until init() is called
*/
private constructor();
/**
* Initialise the program cache with a default