UNPKG

threepipe

Version:

A modern 3D viewer framework built on top of three.js, written in TypeScript, designed to make creating high-quality, modular, and extensible 3D experiences on the web simple and enjoyable.

615 lines 28.4 kB
import { BaseEvent, CanvasTexture, Color, Event, EventDispatcher, Object3D, Scene, Vector3, Vector3Tuple } from 'three'; import { Class, ValOrArr } from 'ts-browser-helpers'; import { TViewerScreenShader } from '../postprocessing'; import { AddObjectOptions, IAnimationLoopEvent, ICamera, IGeometry, IMaterial, IObject3D, ITexture, RootScene, TCameraControlsMode } from '../core'; import { ViewerRenderManager } from './ViewerRenderManager'; import { EasingFunctionType, GLStatsJS, IDialogWrapper, SerializationMetaType, SerializationResourcesType } from '../utils'; import { AssetManager, AssetManagerOptions, BlobExt, ExportFileOptions, IAsset, ImportAddOptions, ImportAssetOptions, ImportResult, RootSceneImportResult } from '../assetmanager'; import { IViewerPlugin, IViewerPluginSync } from './IViewerPlugin'; import { UiObjectConfig } from 'uiconfig.js'; import { IRenderTarget } from '../rendering'; import { DropzonePluginOptions } from '../plugins/interaction/DropzonePlugin'; import { Object3DManager } from '../assetmanager/Object3DManager'; import { ViewerTimeline } from '../utils/ViewerTimeline'; import { AViewerPlugin } from './AViewerPlugin'; export interface IViewerEvent extends BaseEvent, Partial<IAnimationLoopEvent> { type: '*' | 'update' | 'preRender' | 'postRender' | 'preFrame' | 'postFrame' | 'dispose' | 'addPlugin' | 'removePlugin' | 'renderEnabled' | 'renderDisabled' | 'renderError'; eType?: '*' | 'update' | 'preRender' | 'postRender' | 'preFrame' | 'postFrame' | 'dispose' | 'addPlugin' | 'removePlugin' | 'renderEnabled' | 'renderDisabled' | 'renderError'; [p: string]: any; } export type IViewerEventTypes = IViewerEvent['type']; export interface ISerializedConfig { assetType: 'config'; type: string; metadata?: { generator: string; version: number; [key: string]: any; }; [key: string]: any; } export interface ISerializedViewerConfig extends ISerializedConfig { type: 'ThreeViewer' | 'ViewerApp'; version: string; plugins: ISerializedConfig[]; resources?: Partial<SerializationResourcesType> | SerializationMetaType; renderManager?: any; scene?: any; [key: string]: any; } export interface ViewerEventMap { preFrame: { time: number; deltaTime: number; }; } export interface ViewerEventListener<T extends keyof ViewerEventMap> { callback: (event: ViewerEventMap[T] & { type: T; target: ThreeViewer; }) => void; order?: number; } export type IConsoleWrapper = Partial<Console> & Pick<Console, 'log' | 'warn' | 'error'>; /** * Options for the ThreeViewer creation. * @category Viewer */ export interface ThreeViewerOptions { /** * The canvas element to use for rendering. Only one of container and canvas must be specified. */ canvas?: HTMLCanvasElement; /** * The container for the canvas. A new canvas will be created in this container. Only one of container and canvas must be specified. */ container?: HTMLElement; /** * The fragment shader snippet to render on screen. */ screenShader?: TViewerScreenShader; /** * Use MSAA. * Renders objects in a multi-sampled buffer. * @default false */ msaa?: boolean; /** * Use Uint8 RGBM HDR Render Pipeline. * Provides better performance with post-processing. * RenderManager Uses Half-float if set to false. * @default true */ rgbm?: boolean; /** * Use rendered gbuffer as depth-prepass / z-prepass. (Requires DepthBufferPlugin/GBufferPlugin). * Set it to true if you only have opaque objects in the scene to get better performance. * * @default false * * todo fix: It should be disabled when there are any transparent/transmissive objects with render to depth buffer enabled, see forceZPrepass */ zPrepass?: boolean; /** * Render scale, 1 = full resolution, 0.5 = half resolution, 2 = double resolution. * Same as pixelRatio in three.js * Can be set to `window.devicePixelRatio` to render at device resolution in browsers. * An optimal value is `Math.min(2, window.devicePixelRatio)` to prevent issues on mobile. This is set when 'auto' is passed. * @default 1 */ renderScale?: number | 'auto'; /** * Max render scale when set to 'auto' * @default 2 */ maxRenderScale?: number; /** * Default Background color of the scene. * To set the background texture/map, use {@link ThreeViewerOptions.load.background} or {@link setBackgroundMap} * @default '#ffffff' (white) */ backgroundColor?: string | Color | number | null; /** * Model Root Scale * @default 1 */ modelRootScale?: number; /** * Enable stencil in renderer and stencilBuffer in composer render targets. * @default false */ stencil?: boolean; debug?: boolean; /** * Add initial plugins. */ plugins?: (IViewerPluginSync | Class<IViewerPluginSync>)[]; load?: { /** * Load one or more source files */ src?: ValOrArr<string | IAsset | null>; /** * Load environment map */ environment?: string | IAsset | ITexture | undefined | null; /** * Load background map */ background?: string | IAsset | ITexture | undefined | null; }; onLoad?: (results: any) => void; /** * TonemapPlugin is added to the viewer if this is true. * @default true */ tonemap?: boolean; camera?: { type?: 'perspective' | 'orthographic'; controlsMode?: TCameraControlsMode; position?: Vector3 | Vector3Tuple; target?: Vector3 | Vector3Tuple; } | ICamera; rootScene?: RootScene; /** * Max HDR intensity for rendering and post-processing. * Values above this might be clamped during post-processing. * @default 72 (when rgbm is false), 16 (when rgbm is true) */ maxHDRIntensity?: number; /** * Power preference for the WebGL context. * @default 'high-performance' */ powerPreference?: WebGLPowerPreference; /** * Options for the asset manager. */ assetManager?: AssetManagerOptions; /** * Add the dropzone plugin to the viewer, allowing to drag and drop files into the viewer over the canvas/container. * Set to true/false to enable/disable the plugin, or pass options to configure the plugin. Assuming true if options are passed. * @default - false */ dropzone?: boolean | DropzonePluginOptions; /** * If true, will stop event propagation on all pointer events on the viewer container (when camera interactions are enabled). * * Set this to true when the viewer is inside a carousel or similar component that might interfere with pointer events. * @default false */ stopPointerEventPropagation?: boolean; /** * By default, all imported assets are cached in memory, so that calling import/load would return the same instance of an asset if the same source and options is passed again. * Set this to `false` to disable this caching. * @default true */ cacheImportedAssets?: boolean; /** * @deprecated use {@link msaa} instead */ isAntialiased?: boolean; /** * @deprecated use {@link rgbm} instead */ useRgbm?: boolean; /** * @deprecated use {@link zPrepass} instead */ useGBufferDepth?: boolean; } /** * Three Viewer * * The ThreeViewer is the main class in the framework to manage a scene, render and add plugins to it. * @category Viewer */ export declare class ThreeViewer extends EventDispatcher<Record<IViewerEventTypes, IViewerEvent>> { static readonly VERSION = "0.4.3"; static readonly ConfigTypeSlug = "vjson"; uiConfig: UiObjectConfig; static Console: IConsoleWrapper; static Dialog: IDialogWrapper; readonly type = "ThreeViewer"; /** * If the viewer is enabled. Set this `false` to disable RAF loop. */ enabled: boolean; /** * Enable or disable all rendering. * When disabled, the animation loop is still running, but nothing is rendered. * This can be used to pause rendering when not needed, for example when the viewer is not visible. * Note: this does not pause plugins or the timeline, use {@link enabled} for that. */ renderEnabled: boolean; readonly assetManager: AssetManager; readonly object3dManager: Object3DManager; readonly renderManager: ViewerRenderManager; /** * The Scene attached to the viewer, this cannot be changed. * @type {RootScene} */ private readonly _scene; /** * Main timeline for the viewer. * * It's a WIP, API might change. */ readonly timeline: ViewerTimeline; get materialManager(): import('../assetmanager').MaterialManager<object>; readonly plugins: Record<string, IViewerPlugin>; /** * Scene with object hierarchy used for rendering */ get scene(): RootScene & Scene; /** * Specifies how many frames to render in a single request animation frame. Keep to 1 for realtime rendering. * Note: should be max (screen refresh rate / animation frame rate) like 60Hz / 30fps */ maxFramePerLoop: number; readonly debug: boolean; /** * Number of times to run composer render. If set to more than 1, preRender and postRender events will also be called multiple times. */ rendersPerFrame: number; /** * Get the HTML Element containing the canvas * @returns {HTMLElement} */ get container(): HTMLElement; /** * Get the HTML Canvas Element where the viewer is rendering * @returns {HTMLCanvasElement} */ get canvas(): HTMLCanvasElement; get console(): IConsoleWrapper; get dialog(): IDialogWrapper; /** * Helper to track and visualize rendering performance while in debug mode. */ renderStats?: GLStatsJS; /** * The ResizeObserver observing the canvas element. Add more elements to this observer to resize viewer on their size change. * @type {ResizeObserver | undefined} */ readonly resizeObserver: ResizeObserver | undefined; private readonly _canvas; private readonly _container; private _needsResize; private _isRenderingFrame; private _needsReset; private _lastCameraPosition; private _lastCameraQuat; private _lastCameraTarget; private _tempVec; private _tempQuat; private _lastMainCamera; /** * If any of the viewers are in debug mode, this will be true. * This is required for debugging/logging in some cases. */ static ViewerDebugging: boolean; /** * plugins that are not serialized/deserialized with the viewer from config. useful when loading files exported from the editor, etc * (runtime only, not serialized itself) */ serializePluginsIgnored: string[]; /** * Create a viewer instance for using the webgi viewer SDK. * @param options - {@link ThreeViewerOptions} */ constructor({ debug, ...options }: ThreeViewerOptions); /** * Add an object/model/material/viewer-config/plugin-preset/... to the viewer scene from url or an {@link IAsset} object. * Same as {@link AssetManager.addAssetSingle} * @param obj * @param options */ load<T extends ImportResult = ImportResult>(obj: string | IAsset | File | null, options?: ImportAddOptions): Promise<T | undefined>; /** * Imports an object/model/material/texture/viewer-config/plugin-preset/... to the viewer scene from url or an {@link IAsset} object. * Same as {@link AssetImporter.importSingle} * @param obj * @param options */ import<T extends ImportResult = ImportResult>(obj: string | IAsset | File | null, options?: ImportAssetOptions): Promise<T | undefined>; /** * Set the environment map of the scene from url or an {@link IAsset} object. * @param map * @param setBackground - Set the background image of the scene from the same map. * @param options - Options for importing the asset. See {@link ImportAssetOptions} */ setEnvironmentMap(map: string | IAsset | null | ITexture | File | undefined, { setBackground, ...options }?: ImportAssetOptions & { setBackground?: boolean; }): Promise<ITexture | null>; /** * Set the background image of the scene from url or an {@link IAsset} object. * @param map * @param setEnvironment - Set the environment map of the scene from the same map. * @param options - Options for importing the asset. See {@link ImportAssetOptions} */ setBackgroundMap(map: string | IAsset | null | ITexture | File | undefined, { setEnvironment, ...options }?: ImportAssetOptions & { setBackground?: boolean; }): Promise<ITexture | null>; /** * Exports an object/mesh/material/texture/render-target/plugin-preset/viewer to a blob. * If no object is given, a glb is exported with the current viewer state. * @param obj * @param options */ export(obj?: IObject3D | IMaterial | ITexture | IRenderTarget | IViewerPlugin | (typeof this), options?: ExportFileOptions): Promise<BlobExt | undefined>; /** * Export the scene to a file (default: glb with viewer config) and return a blob * @param options * @param useExporterPlugin - uses the {@link AssetExporterPlugin} if available. This is useful to use the options configured by the user in the plugin. */ exportScene(options?: ExportFileOptions, useExporterPlugin?: boolean): Promise<BlobExt | undefined>; /** * Returns a blob with the screenshot of the canvas. * If {@link CanvasSnapshotPlugin} is added, it will be used, otherwise canvas.toBlob will be used directly. * @param mimeType default image/jpeg * @param quality between 0 and 100 */ getScreenshotBlob({ mimeType, quality }?: { mimeType?: string | undefined; quality?: number | undefined; }): Promise<Blob | null | undefined>; getScreenshotDataUrl({ mimeType, quality }?: { mimeType?: string | undefined; quality?: number | undefined; }): Promise<string | null | undefined>; /** * Disposes the viewer and frees up all resource and events. Do not use the viewer after calling dispose. * NOTE - If you want to reuse the viewer, set viewer.enabled to false instead, then set it to true again when required. * To dispose all the objects, materials in the scene, but not the viewer itself, use `viewer.scene.disposeSceneModels()` */ dispose(clear?: boolean): void; /** * Mark that the canvas is resized. If the size is changed, the renderer and all render targets are resized. This happens before the render of the next frame. */ resize: () => void; /** * Set the viewer to dirty and trigger render of the next frame. * * This also triggers the 'update' event on the viewer. Note - update event might be triggered multiple times in a single frame, use preFrame or preRender events to get notified only once per frame. * @param source - The source of the dirty event. like plugin or 3d object * @param event - The event that triggered the dirty event. */ setDirty(source?: any, event?: Event): void; protected _animationLoop(event: IAnimationLoopEvent): void; /** * Get the Plugin by a constructor type or by the string type. * Use string type if the plugin is not a dependency, and you don't want to bundle the plugin. * @param type - The class of the plugin to get, or the string type of the plugin to get which is in the static PluginType property of the plugin * @returns {T extends IViewerPlugin | undefined} - The plugin of the specified type. */ getPlugin<T extends IViewerPlugin>(type: Class<T> | string): T | undefined; getPlugins<T extends IViewerPlugin>(type: Class<T> | string): T[]; /** * Get the Plugin by a constructor type or add a new plugin of the specified type if it doesn't exist. * @param type * @param args - arguments for the constructor of the plugin, used when a new plugin is created. */ getOrAddPlugin<T extends IViewerPlugin>(type: Class<T>, ...args: ConstructorParameters<Class<T>>): Promise<T>; /** * Get the Plugin by a constructor type or add a new plugin to the viewer of the specified type if it doesn't exist(sync). * @param type * @param args - arguments for the constructor of the plugin, used when a new plugin is created. */ getOrAddPluginSync<T extends IViewerPluginSync>(type: Class<T>, ...args: ConstructorParameters<Class<T>>): T; /** * Add a plugin to the viewer. * @param plugin - The instance of the plugin to add or the class of the plugin to add. * @param args - Arguments for the constructor of the plugin, in case a class is passed. * @returns {Promise<T>} - The plugin added. */ addPlugin<T extends IViewerPlugin>(plugin: T | Class<T>, ...args: ConstructorParameters<Class<T>>): Promise<T>; /** * Add a plugin to the viewer(sync). * @param plugin * @param args */ addPluginSync<T extends IViewerPluginSync>(plugin: T | Class<T>, ...args: ConstructorParameters<Class<T>>): T; /** * Add multiple plugins to the viewer. * @param plugins - List of plugin instances or classes */ addPlugins(plugins: (IViewerPlugin | Class<IViewerPlugin>)[]): Promise<void>; /** * Add multiple plugins to the viewer(sync). * @param plugins - List of plugin instances or classes */ addPluginsSync(plugins: (IViewerPluginSync | Class<IViewerPluginSync>)[]): void; /** * Remove a plugin instance or a plugin class. Works similar to {@link ThreeViewer.addPlugin} * @param p * @param dispose * @returns {Promise<void>} */ removePlugin(p: IViewerPlugin<ThreeViewer, boolean>, dispose?: boolean): Promise<void>; /** * Remove a plugin instance or a plugin class(sync). Works similar to {@link ThreeViewer.addPluginSync} * @param p * @param dispose */ removePluginSync(p: IViewerPluginSync, dispose?: boolean): void; /** * Set size of the canvas and update the renderer. * If no size or width/height is passed, canvas is set to 100% of the container. * * See also {@link ThreeViewer.setRenderSize} to set the size of the render target by automatically calculating the renderScale and fitting in container. * * Note: Apps using this should ideally set `max-width: 100%` for the canvas in css. * @param size */ setSize(size?: { width?: number; height?: number; }): void; /** * Set the render size of the viewer to fit in the container according to the specified mode, maintaining aspect ratio. * Changes the renderScale accordingly. * Note: the canvas needs to be centered in the container to work properly, this can be done with the following css on the container: * ```css * display: flex; * justify-content: center; * align-items: center; * ``` * or in js: * ```js * viewer.container.style.display = 'flex'; * viewer.container.style.justifyContent = 'center'; * viewer.container.style.alignItems = 'center'; * ``` * Modes: * 'contain': The canvas is scaled to fit within the container while maintaining its aspect ratio. The canvas will be fully visible, but there may be empty space around it. * 'cover': The canvas is scaled to fill the entire container while maintaining its aspect ratio. Part of the canvas may be clipped to fit the container. * 'fill': The canvas is stretched to completely fill the container, ignoring its aspect ratio. * 'scale-down': The canvas is scaled down to fit within the container while maintaining its aspect ratio, but it won't be scaled up if it's smaller than the container. * 'none': container size is ignored, but devicePixelRatio is used * * Check the example for more details - https://threepipe.org/examples/#viewer-render-size/ * @param size - The size to set the render to. The canvas will render to this size. * @param mode - 'contain', 'cover', 'fill', 'scale-down' or 'none'. Default is 'contain'. * @param devicePixelRatio - typically set to `window.devicePixelRatio`, or `Math.min(1.5, window.devicePixelRatio)` for performance. Use this only when size is derived from dom elements. * @param containerSize - (optional) The size of the container, if not passed, the bounding client rect of the container is used. */ setRenderSize(size: { width: number; height: number; }, mode?: 'contain' | 'cover' | 'fill' | 'scale-down' | 'none', devicePixelRatio?: number, containerSize?: { width: number; height: number; }): void; /** * Traverse all objects in scene model root. * @param callback */ traverseSceneObjects<T extends IObject3D = IObject3D>(callback: (o: T) => void): void; deleteImportedViewerConfigOnLoad: boolean; deleteImportedViewerConfigOnLoadWait: number; /** * Add an object to the scene model root. * If an imported scene model root is passed, it will be loaded with viewer configuration, unless importConfig is false * @param imported * @param options */ addSceneObject<T extends IObject3D | Object3D | RootSceneImportResult = RootSceneImportResult>(imported: T, options?: AddObjectOptions): Promise<T>; /** * Serialize all the plugins and their settings to save or create presets. Used in {@link toJSON}. * @param meta - The meta object. * @param filter - List of PluginType for to include. If empty, no plugins will be serialized. If undefined, all plugins will be serialized. * @returns {any[]} */ serializePlugins(meta: SerializationMetaType, filter?: string[]): ISerializedConfig[]; serializePlugin(plugin: IViewerPlugin, meta: SerializationMetaType): ISerializedConfig | undefined; /** * Deserialize all the plugins and their settings from a preset. Used in {@link fromJSON}. * @param plugins - The output of {@link serializePlugins}. * @param meta - The meta object. * @returns {this} */ deserializePlugins(plugins: any[], meta?: SerializationMetaType): this; /** * Serialize a single plugin settings. */ exportPluginConfig(plugin?: string | Class<IViewerPlugin> | IViewerPlugin): ISerializedConfig | Record<string, never>; /** * Deserialize and import a single plugin settings. * Can also use {@link ThreeViewer.importConfig} to import only plugin config. * @param json * @param plugin */ importPluginConfig(json: ISerializedConfig, plugin?: IViewerPlugin): Promise<IViewerPlugin<ThreeViewer, boolean> | undefined>; /** * Serialize multiple plugin settings. * @param filter - List of PluginType to include. If empty, no plugins will be serialized. If undefined, all plugins will be serialized. */ exportPluginsConfig(filter?: string[]): ISerializedViewerConfig; /** * Serialize all the viewer and plugin settings. * @param binary - Indicate that the output will be converted and saved as binary data. (default: false) * @param pluginFilter - List of PluginType to include. If empty, no plugins will be serialized. If undefined, all plugins will be serialized. */ exportConfig(binary?: boolean, pluginFilter?: string[]): ISerializedViewerConfig; /** * Deserialize and import all the viewer and plugin settings, exported with {@link exportConfig}. * * @param json - The serialized JSON object returned from {@link exportConfig} or {@link toJSON}. * @returns {Promise<this>} - The viewer instance with the imported config. */ importConfig(json: ISerializedConfig | ISerializedViewerConfig, meta?: SerializationMetaType): Promise<this | IViewerPlugin | undefined>; /** * Serialize all the viewer and plugin settings and versions. * @param binary - Indicate that the output will be converted and saved as binary data. (default: true) * @param pluginFilter - List of PluginType to include. If empty, no plugins will be serialized. If undefined/not-passed, all plugins will be serialized. * @returns {any} - Serializable JSON object. */ toJSON(binary?: boolean, pluginFilter?: string[], meta?: SerializationMetaType): ISerializedViewerConfig; /** * Deserialize all the viewer and plugin settings. * NOTE - use async {@link ThreeViewer.importConfig} to import a json/config exported with {@link ThreeViewer.exportConfig} or {@link ThreeViewer.toJSON}. * @param data - The serialized JSON object returned from {@link toJSON}. * @param meta - The meta object, see {@link SerializationMetaType} * @returns {this} */ fromJSON(data: ISerializedViewerConfig, meta?: SerializationMetaType): this | null; loadConfigResources: (json: Partial<SerializationMetaType>, extraResources?: Partial<SerializationResourcesType>) => Promise<SerializationMetaType>; doOnce<TRet>(event: IViewerEventTypes, func?: (...args: any[]) => TRet): Promise<TRet | undefined>; dispatchEvent(event: IViewerEvent): void; /** * Uses the {@link FileTransferPlugin} to export a Blob/File. If the plugin is not available, it will download the blob. * {@link FileTransferPlugin} can be configured by other plugins to export the blob to a specific location like local file system, cloud storage, etc. * @param blob - The blob or file to export/download * @param name - name of the file, if not provided, the name of the file is used if it's a file. */ exportBlob(blob: Blob | File, name?: string): Promise<void>; private _setActiveCameraView; private _resolvePluginOrClass; private _renderEnabledChanged; private readonly _defaultConfig; private _lastSize; private _onContextRestore; private _onContextLost; fitToView(selected?: Object3D | Object3D[] | IMaterial | IMaterial[] | ITexture | ITexture[] | IGeometry | IGeometry[], distanceMultiplier?: number, duration?: number, ease?: ((v: number) => number) | EasingFunctionType): Promise<void>; private _canvasTexture?; /** * Create and get a three.js CanvasTexture from the viewer's canvas. */ get canvasTexture(): CanvasTexture; private _stopPropagation; private _onListeners; on<T extends keyof ViewerEventMap>(type: T, listener: ViewerEventListener<T>): (() => void) | undefined; off<T extends keyof ViewerEventMap>(type: T, listener: ViewerEventListener<T>): void; dispatch<T extends keyof ViewerEventMap>(type: T, event: ViewerEventMap[T]): void; private _onPluginAdd; private _onPluginRemove; private _pluginListeners; addPluginListener(type: 'add' | 'remove', listener: (event: IViewerEvent) => void, ...plugins: (string | undefined)[]): void; removePluginListener(type: 'add' | 'remove', listener: (event: IViewerEvent) => void): void; /** * Can be used to "subscribe" to plugins. * @param plugin * @param mount * @param unmount */ forPlugin<T extends IViewerPlugin>(plugin: string | Class<T>, mount: (p: T) => void, unmount?: (p: T) => void, thisPlugin?: AViewerPlugin): void; /** * The renderer for the viewer that's attached to the canvas. This is wrapper around WebGLRenderer and EffectComposer and manages post-processing passes and rendering logic * @deprecated - use {@link renderManager} instead */ get renderer(): ViewerRenderManager; /** * @deprecated use {@link assetManager} instead. * Gets the Asset manager, contains useful functions for managing, loading and inserting assets. */ getManager(): AssetManager | undefined; /** * Get the Plugin by the string type. * @deprecated - Use {@link getPlugin} instead. * @param type * @returns {T | undefined} */ getPluginByType<T extends IViewerPlugin>(type: string): T | undefined; } //# sourceMappingURL=../src/viewer/ThreeViewer.d.ts.map