import Renderer from './Renderer'; import Scene from './Scene'; import Timeline from './Timeline'; import { ParametricSurfaceGeometryOpts } from './geometry/ParametricSurface'; import Texture2D, { Texture2DOpts } from './Texture2D'; import TextureCube, { CubeTarget, TextureCubeOpts } from './TextureCube'; import Texture, { TextureImageSource } from './Texture'; import Mesh from './Mesh'; import Material, { MaterialOpts } from './Material'; import Vector3 from './math/Vector3'; import { GLTFLoadResult } from './loader/GLTF'; import ClayNode from './Node'; import DirectionalLight from './light/Directional'; import PointLight from './light/Point'; import SpotLight from './light/Spot'; import AmbientLight from './light/Ambient'; import AmbientCubemapLight from './light/AmbientCubemap'; import AmbientSHLight from './light/AmbientSH'; import ShadowMapPass from './prePass/ShadowMap'; import { Notifier } from './core'; import Camera from './Camera'; import { EventManager, EventTriggers } from './app/EventManager'; import Shader from './Shader'; import { createStandardShader } from './shader/create'; import Geometry from './Geometry'; import { Color } from './core/type'; interface App3DEventOpts { /** * Container that event will be listened to */ enabled?: boolean; trigger?: EventTriggers[]; container?: HTMLElement; } interface App3DGraphicOpts { /** * If enable shadow */ shadow?: boolean; /** * If use linear color space */ linear?: boolean; /** * If enable ACES tone mapping. */ tonemapping?: boolean; } interface App3DOpts { pixelRatio?: number; width?: number; height?: number; /** * If render automatically each frame. */ autoRender?: boolean; /** * If do auto gc on the gpu resources. * Otherwise needs to call gc() manually */ autoGC?: boolean; /** * If update camera aspect automatically. */ autoUpdateCameraAspect?: boolean; /** * If not init immediately. Should call init method manually. * * App will start the loop after promise returned from init resolved. */ lazyInit?: boolean; /** * If enable mouse/touch event. It will slow down the system if geometries are complex. */ event?: App3DEventOpts | boolean; /** * Graphic configuration including shadow, color space. */ graphic?: App3DGraphicOpts; /** * Attributes for creating gl context */ glAttributes?: { alpha?: boolean; depth?: boolean; stencil?: boolean; antialias?: boolean; premultipliedAlpha?: boolean; preserveDrawingBuffer?: boolean; }; } type StandardShader = ReturnType; type CreateMaterialConfig = Partial & { shader?: T; textureFlipY?: boolean; textureLoaded?: (textureName: string, texture: Texture) => void; texturesReady?: (textures: Texture[]) => void; } & { [key: string]: any; }; /** * Using App3D is a much more convenient way to create and manage your 3D application. * * It provides the abilities to: * * + Manage application loop and rendering. * + Collect GPU resource automatically without memory leak concern. * + Mouse event management. * + Create scene objects, materials, textures with simpler code. * + Load models with one line of code. * + Promised interfaces. * * Here is a basic example to create a rotating cube. * ```js const app = new App3D('#viewport'); // Create a perspective camera. // First parameter is the camera position. Which is in front of the cube. // Second parameter is the camera lookAt target. Which is the origin of the world, and where the cube puts. const camera = app.createCamera([0, 2, 5], [0, 0, 0]); // Create a sample cube const cube = app.createCube(); // Create a directional light. The direction is from top right to left bottom, away from camera. const mainLight = app.createDirectionalLight([-1, -1, -1]); app.loop((app) => { // Simply rotating the cube every frame. this._cube.rotation.rotateY(app.frameTime / 1000); }); ``` * @param dom Container dom element or a selector string that can be used in `querySelector` * @param option Options in creating app3D */ declare class App3D extends Notifier { private _container; private _renderer; private _scene; private _timeline; private _shadowPass?; private _gpuResourceManager; private _eventManager?; private _geoCache; private _texCache; private _graphicOpts; private _inRender; private _disposed; private _autoRender; private _autoGC; private _autoUpdateCameraAspect; private _inited; private _frameTime; private _elapsedTime; private _defaultShader; constructor(container: HTMLElement | string, opts?: App3DOpts); get scene(): Scene; set scene(scene: Scene); get renderer(): Renderer; get container(): HTMLElement; get timeline(): Timeline; get frameTime(): number; get elapsedTime(): number; get width(): number; get height(): number; getShadowMapPass(): ShadowMapPass | undefined; getEventManager(): EventManager | undefined; /** * Init app3D. Only available when lazyInit is set true. * * @param prepare Prepare before an intialization. * Return a promise that should be resolved when app is ready */ init(prepare?: () => Promise): void; /** * Alias for app3D.on('loop') */ loop(cb: (frameTime: number) => void): void; private _onBeforeRenderScene; private _doInit; private _updateGraphicOptions; private _doRender; /** * Do render */ render(): void; /** * Collect resources. */ gc(): void; /** * Load a texture from image or string. * @example * app.loadTexture('diffuseMap.jpg') * .then(function (texture) { * material.set('diffuseMap', texture); * }); */ loadTexture(urlOrImg: string | TextureImageSource, opts: Partial & { exposure?: number; }, useCache?: boolean): Promise; /** * Create a texture from image or string synchronously. Texture can be use directly and don't have to wait for it's loaded. * @param {ImageLike} img * @param {Object} [opts] Texture options. * @param {boolean} [opts.flipY=true] If flipY. See {@link clay.Texture.flipY} * @param {boolean} [opts.convertToPOT=false] Force convert None Power of Two texture to Power of two so it can be tiled. * @param {number} [opts.anisotropic] Anisotropic filtering. See {@link clay.Texture.anisotropic} * @param {number} [opts.wrapS=clay.Texture.REPEAT] See {@link clay.Texture.wrapS} * @param {number} [opts.wrapT=clay.Texture.REPEAT] See {@link clay.Texture.wrapT} * @param {number} [opts.minFilter=clay.Texture.LINEAR_MIPMAP_LINEAR] See {@link clay.Texture.minFilter} * @param {number} [opts.magFilter=clay.Texture.LINEAR] See {@link clay.Texture.magFilter} * @param {number} [opts.exposure] Only be used when source is a HDR image. * @return {clay.Texture2D} * @example * const texture = app.loadTexture('diffuseMap.jpg', { * anisotropic: 8, * flipY: false * }); * material.set('diffuseMap', texture); */ loadTextureSync(urlOrImg: string | TextureImageSource, opts?: Partial & { exposure?: number; }): Texture2D; /** * Create a texture from image or string synchronously. Texture can be use directly and don't have to wait for it's loaded. * @param {ImageLike} img * @param {Object} [opts] Texture options. * @param {boolean} [opts.flipY=false] If flipY. See {@link clay.Texture.flipY} * @return {Promise} * @example * app.loadTextureCube({ * px: 'skybox/px.jpg', py: 'skybox/py.jpg', pz: 'skybox/pz.jpg', * nx: 'skybox/nx.jpg', ny: 'skybox/ny.jpg', nz: 'skybox/nz.jpg' * }).then(function (texture) { * skybox.setEnvironmentMap(texture); * }) */ loadTextureCube(imgList: Record, opts?: Partial): Promise; /** * Create a texture from image or string synchronously. Texture can be use directly and don't have to wait for it's loaded. * @param {ImageLike} img * @param {Object} [opts] Texture options. * @param {boolean} [opts.flipY=false] If flipY. See {@link clay.Texture.flipY} * @return {clay.TextureCube} * @example * const texture = app.loadTextureCubeSync({ * px: 'skybox/px.jpg', py: 'skybox/py.jpg', pz: 'skybox/pz.jpg', * nx: 'skybox/nx.jpg', ny: 'skybox/ny.jpg', nz: 'skybox/nz.jpg' * }); * skybox.setEnvironmentMap(texture); */ loadTextureCubeSync(imgList: Record, opts?: Partial): TextureCube; /** * Create a material. * @param {Object|StandardMaterialMRConfig} materialConfig. materialConfig contains `shader`, `transparent` and uniforms that used in corresponding uniforms. * Uniforms can be `color`, `alpha` `diffuseMap` etc. * @param {string|clay.Shader} Default to be standard shader with metalness and roughness workflow. * @param {boolean} [transparent=false] If material is transparent. * @param {boolean} [textureFlipY=true] If flip y of texture. * @param {Function} [textureLoaded] Callback when single texture loaded. * @param {Function} [texturesReady] Callback when all texture loaded. * @return {clay.Material} */ createMaterial(matConfig?: CreateMaterialConfig): Material; /** * Create a cube mesh and add it to the scene or the given parent node. * @param material * @param parentNode Parent node to append. Default to be scene. * @param subdivision Subdivision of cube. * Can be a number to represent both width, height and depth dimensions. Or an array to represent them respectively. * @example * // Create a white cube. * app.createCube() */ createCube(material?: CreateMaterialConfig | Material, parentNode?: ClayNode, subdiv?: number | number[]): Mesh>; /** * Create a cube mesh that camera is inside the cube. * @function * @param {Object|clay.Material} [material] * @param {clay.Node} [parentNode] Parent node to append. Default to be scene. * @param {Array.|number} [subdivision=1] Subdivision of cube. * Can be a number to represent both width, height and depth dimensions. Or an array to represent them respectively. * @return {clay.Mesh} * @example * // Create a white cube inside. * app.createCubeInside() */ createCubeInside(material?: CreateMaterialConfig | Material, parentNode?: ClayNode, subdiv?: number | number[]): Mesh>; /** * Create a sphere mesh and add it to the scene or the given parent node. * @param material * @param parentNode Parent node to append. Default to be scene. * @param subdivision Subdivision of sphere. * @example * // Create a semi-transparent sphere. * app.createSphere({ * color: [0, 0, 1], * transparent: true, * alpha: 0.5 * }) */ createSphere(material?: CreateMaterialConfig | Material, parentNode?: ClayNode, subdiv?: number): Mesh>; /** * Create a plane mesh and add it to the scene or the given parent node. * @function * @param {Object|clay.Material} [material] * @param {clay.Node} [parentNode] Parent node to append. Default to be scene. * @param {Array.|number} [subdivision=1] Subdivision of plane. * Can be a number to represent both width and height dimensions. Or an array to represent them respectively. * @return {clay.Mesh} * @example * // Create a red color plane. * app.createPlane({ * color: [1, 0, 0] * }) */ createPlane(material?: CreateMaterialConfig | Material, parentNode?: ClayNode, subdiv?: number | number[]): Mesh>; /** * Create mesh with parametric surface function * @param {Object|clay.Material} [material] * @param {clay.Node} [parentNode] Parent node to append. Default to be scene. * @param {Object} generator * @param {Function} generator.x * @param {Function} generator.y * @param {Function} generator.z * @param {Array} [generator.u=[0, 1, 0.05]] * @param {Array} [generator.v=[0, 1, 0.05]] * @return {clay.Mesh} */ createParametricSurface(material?: CreateMaterialConfig | Material, parentNode?: ClayNode, generator?: ParametricSurfaceGeometryOpts['generator']): Mesh>; /** * Create a general mesh with given geometry instance and material config. * @param geometry */ createMesh(geometry: Geometry, mat?: CreateMaterialConfig | Material, parentNode?: ClayNode): Mesh>; /** * Create an empty node * @param {clay.Node} parentNode * @return {clay.Node} */ createNode(parentNode?: ClayNode): ClayNode; /** * Create a perspective or orthographic camera and add it to the scene. * @param position * @param target * @param type Can be 'perspective' or 'orthographic'(in short 'ortho') * @param extent Extent is available only if type is orthographic. */ createCamera(position: Vector3 | Vector3['array'], target: Vector3 | Vector3['array'], type: 'ortho' | 'orthographic', extent?: Vector3 | Vector3['array']): Camera<'orthographic'>; createCamera(position: Vector3 | Vector3['array'], target?: Vector3 | Vector3['array'], type?: 'perspective'): Camera<'perspective'>; /** * Create a directional light and add it to the scene. * @param dir A Vector3 or array to represent the direction. * @param {Color} [color='#fff'] Color of directional light, default to be white. * @param {number} [intensity] Intensity of directional light, default to be 1. * * @example * app.createDirectionalLight([-1, -1, -1], '#fff', 2); */ createDirectionalLight(dir: Vector3 | Vector3['array'], color?: Color | string, intensity?: number): DirectionalLight; /** * Create a spot light and add it to the scene. * @param {Array.|clay.Vector3} position Position of the spot light. * @param {Array.|clay.Vector3} [target] Target position where spot light points to. * @param {number} [range=20] Falloff range of spot light. Default to be 20. * @param {Color} [color='#fff'] Color of spot light, default to be white. * @param {number} [intensity=1] Intensity of spot light, default to be 1. * @param {number} [umbraAngle=30] Umbra angle of spot light. Default to be 30 degree from the middle line. * @param {number} [penumbraAngle=45] Penumbra angle of spot light. Default to be 45 degree from the middle line. * * @example * app.createSpotLight([5, 5, 5], [0, 0, 0], 20, #900); */ createSpotLight(position: Vector3 | Vector3['array'], target?: Vector3 | Vector3['array'], range?: number, color?: Color | string, intensity?: number, umbraAngle?: number, penumbraAngle?: number): SpotLight; /** * Create a point light. * @param {Array.|clay.Vector3} position Position of point light.. * @param {number} [range=100] Falloff range of point light. * @param {Color} [color='#fff'] Color of point light. * @param {number} [intensity=1] Intensity of point light. */ createPointLight(position: Vector3 | Vector3['array'], range?: number, color?: Color | string, intensity?: number): PointLight; /** * Create a ambient light. * @param {Color} [color='#fff'] Color of ambient light. * @param {number} [intensity=1] Intensity of ambient light. */ createAmbientLight(color: Color | string, intensity?: number): AmbientLight; /** * Create an cubemap ambient light and an spherical harmonic ambient light * for specular and diffuse lighting in PBR rendering * @param {ImageLike|TextureCube} [envImage] Panorama environment image, HDR format is better. Or a pre loaded texture cube * @param {number} [specularIntenstity=0.7] Intensity of specular light. * @param {number} [diffuseIntenstity=0.7] Intensity of diffuse light. * @param {number} [exposure=1] Exposure of HDR image. Only if image in first paramter is HDR. * @param {number} [prefilteredCubemapSize=32] The size of prefilerted cubemap. Larger value will take more time to do expensive prefiltering. * @return {Promise} */ createAmbientCubemapLight(envImage: TextureCube | string | TextureImageSource, specIntensity?: number, diffIntensity?: number, exposure?: number, prefilteredCubemapSize?: number): Promise<{ specular: AmbientCubemapLight; diffuse: AmbientSHLight; environmentMap: TextureCube; }>; /** * Load a [glTF](https://github.com/KhronosGroup/glTF) format model. * You can convert FBX/DAE/OBJ format models to [glTF](https://github.com/KhronosGroup/glTF) with [fbx2gltf](https://github.com/pissang/claygl#fbx-to-gltf20-converter) python script, * or simply using the [Clay Viewer](https://github.com/pissang/clay-viewer) client application. * @param {string} url * @param {Object} opts * @param {string|clay.Shader} [opts.shader='clay.standard'] 'basic'|'lambert'|'standard'. * @param {boolean} [opts.waitTextureLoaded=false] If add to scene util textures are all loaded. * @param {boolean} [opts.autoPlayAnimation=true] If autoplay the animation of model. * @param {boolean} [opts.upAxis='y'] Change model to y up if upAxis is 'z' * @param {boolean} [opts.textureFlipY=false] * @param {boolean} [opts.textureConvertToPOT=false] If convert texture to power-of-two * @param {string} [opts.textureRootPath] Root path of texture. Default to be relative with glTF file. * @param {clay.Node} [parentNode] Parent node that model will be mounted. Default to be scene * @return {Promise} */ loadModel(url: string, opts?: { shader?: Shader; waitTextureLoaded?: boolean; autoPlayAnimation?: boolean; upAxis?: 'y' | 'z'; textureFlipY?: boolean; textureConvertToPOT?: boolean; textureRootPath?: string; }, parentNode?: ClayNode): Promise; /** * Similar to `app.scene.cloneNode`, except it will mount the cloned node to the scene automatically. * See more in {@link clay.Scene#cloneNode} * * @param node * @param parentNode Parent node that new cloned node will be mounted. * Default to have same parent with source node. */ cloneNode(node: T, parentNode?: ClayNode): T; /** * Resize the application. Will use the container clientWidth/clientHeight if width/height in parameters are not given. */ resize(width?: number, height?: number, pixelRatio?: number): void; /** * Dispose the application * @function */ dispose(): void; } export default App3D;