@babylonjs/viewer
Version:
The Babylon Viewer aims to simplify a specific but common Babylon.js use case: loading, viewing, and interacting with a 3D model.
1,212 lines (1,210 loc) • 79 kB
TypeScript
import { HotSpotQuery, Nullable, IDisposable, IColor4Like, IReadonlyObservable, AssetContainer, PickingInfo, Camera, AbstractMesh, AbstractEngine, FrameGraph, LoadAssetContainerOptions, AbstractEngineOptions, EngineOptions, WebGPUEngineOptions } from '@babylonjs/core/index.js';
import { Observable } from '@babylonjs/core/Misc/observable.js';
import { MaterialVariantsController } from '@babylonjs/loaders/glTF/2.0/Extensions/KHR_materials_variants.js';
import { ArcRotateCamera } from '@babylonjs/core/Cameras/arcRotateCamera.js';
import { Vector3 } from '@babylonjs/core/Maths/math.vector.js';
import { SnapshotRenderingHelper } from '@babylonjs/core/Misc/snapshotRenderingHelper.js';
import { Scene } from '@babylonjs/core/scene.js';
import * as lit from 'lit';
import { LitElement, CSSResultGroup, PropertyValues, TemplateResult } from 'lit';
import { Color4 } from '@babylonjs/core/Maths/math.color.js';
import * as lit_html from 'lit-html';
/**
* Flags for selectively resetting parts of the viewer state.
*/
type ResetFlag = "source" | "environment" | "camera" | "animation" | "post-processing" | "material-variant" | "shadow";
declare const shadowQualityOptions: readonly ["none", "normal", "high"];
/**
* Shadow quality levels.
*/
type ShadowQuality = (typeof shadowQualityOptions)[number];
declare const toneMappingOptions: readonly ["none", "standard", "aces", "neutral"];
/**
* Tone mapping modes.
*/
type ToneMapping = (typeof toneMappingOptions)[number];
declare const ssaoOptions: readonly ["enabled", "disabled", "auto"];
/**
* Screen-space ambient occlusion options.
*/
type SSAOOptions = (typeof ssaoOptions)[number];
/**
* Camera orbit as [alpha, beta, radius].
*/
type CameraOrbit = [alpha: number, beta: number, radius: number];
/**
* Camera target as [x, y, z].
*/
type CameraTarget = [x: number, y: number, z: number];
/**
* Camera auto-orbit configuration.
*/
type CameraAutoOrbit = {
/**
* Whether the camera should automatically orbit around the model when idle.
*/
enabled: boolean;
/**
* The speed at which the camera orbits around the model when idle.
*/
speed: number;
/**
* The delay in milliseconds before the camera starts orbiting around the model when idle.
*/
delay: number;
};
/**
* Environment configuration parameters.
*/
type EnvironmentParams = {
/**
* The intensity of the environment lighting.
*/
intensity: number;
/**
* The blur applied to the environment lighting.
*/
blur: number;
/**
* The rotation of the environment lighting in radians.
*/
rotation: number;
};
/**
* Shadow configuration parameters.
*/
type ShadowParams = {
/**
* The quality of shadow being used.
*/
quality: ShadowQuality;
};
/**
* Post-processing configuration.
*/
type PostProcessing = {
/**
* The tone mapping to use for rendering the scene.
*/
toneMapping: ToneMapping;
/**
* The contrast applied to the scene.
*/
contrast: number;
/**
* The exposure applied to the scene.
*/
exposure: number;
/**
* Whether to enable screen space ambient occlusion (SSAO).
*/
ssao: SSAOOptions;
};
/**
* Options for controlling which parts of the environment to update.
*/
type EnvironmentOptions = Partial<Readonly<{
/**
* Whether to use the environment for lighting (e.g. IBL).
*/
lighting: boolean;
/**
* Whether to use the environment for the skybox.
*/
skybox: boolean;
}>>;
/**
* Options for loading an environment.
*/
type LoadEnvironmentOptions = EnvironmentOptions & Partial<Readonly<{
/**
* Specifies the extension of the environment texture to load.
* This must be specified when the extension cannot be determined from the url.
*/
extension: string;
}>>;
/**
* @internal `LoadEnvironmentOptions` after the base class has resolved the optional `lighting` and
* `skybox` flags to definite booleans (defaults to `true` for both when omitted, otherwise honors the
* caller's choice). Engine-specific extras such as `extension` are forwarded as-is. Passed to the
* subclass `_loadEnvironmentImpl` so it doesn't repeat the default-resolution logic.
*/
type ResolvedLoadEnvironmentOptions = Omit<LoadEnvironmentOptions, "lighting" | "skybox"> & {
readonly lighting: boolean;
readonly skybox: boolean;
};
/**
* A hot spot query specifying either a surface point or a fixed world position.
*/
type ViewerHotSpotQuery = ({
/**
* The type of the hot spot.
*/
type: "surface";
/**
* The index of the mesh within the loaded model.
*/
meshIndex: number;
} & HotSpotQuery) | {
/**
* The type of the hot spot.
*/
type: "world";
/**
* The fixed world space position of the hot spot.
*/
position: [x: number, y: number, z: number];
/**
* The fixed world space normal of the hot spot.
*/
normal: [x: number, y: number, z: number];
};
/**
* A hot spot definition with an optional camera pose.
*/
type HotSpot = ViewerHotSpotQuery & {
/**
* An optional camera pose to associate with the hotspot.
*/
cameraOrbit?: CameraOrbit;
};
/**
* Provides the result of a hot spot query.
*/
declare class ViewerHotSpotResult {
/**
* 2D canvas position in pixels.
*/
readonly screenPosition: [x: number, y: number];
/**
* 3D world coordinates.
*/
readonly worldPosition: [x: number, y: number, z: number];
/**
* Visibility range is [-1..1]. A value of 0 means camera eye is on the plane.
*/
visibility: number;
}
/**
* Bounding information for a model.
*/
type ViewerBoundingInfo = {
/**
* The minimum and maximum extents of the model.
*/
extents: Readonly<{
/**
* The minimum extent of the model.
*/
readonly min: readonly [x: number, y: number, z: number];
/**
* The maximum extent of the model.
*/
readonly max: readonly [x: number, y: number, z: number];
}>;
/**
* The size of the model.
*/
readonly size: readonly [x: number, y: number, z: number];
/**
* The center of the model.
*/
readonly center: readonly [x: number, y: number, z: number];
};
/**
* Backend-agnostic options for loading a model.
* @remarks
* The full Viewer accepts the wider LoadAssetContainerOptions from core.
* This type captures the subset that both backends support.
*/
type ViewerLoadModelOptions = Partial<Readonly<{
/**
* The file extension to use for determining the loader plugin (e.g. ".glb", ".gltf").
*/
pluginExtension: string;
/**
* If true, load glTF files using the OpenPBR material instead of the default PBR material.
* Overrides the corresponding constructor option for this load.
* @experimental
*/
useOpenPBR: boolean;
}>>;
/**
* Backend-agnostic options shared by all viewer implementations.
*/
type ViewerBaseOptions = Partial<{
/**
* The default clear color of the scene.
*/
clearColor: [r: number, g: number, b: number, a?: number];
/**
* When enabled, rendering will be suspended when no scene state driven by the Viewer has changed.
* This can reduce resource CPU/GPU pressure when the scene is static.
* Enabled by default.
*/
autoSuspendRendering: boolean;
/**
* The default source model to load into the viewer.
*/
source: string;
/**
* The file extension to use for determining the loader plugin for the default source model (e.g. ".glb", ".obj").
* @remarks
* If not set, the extension is inferred from the source URL when possible. This is needed for sources whose
* extension cannot be inferred from the URL (e.g. data URLs or extension-less URLs).
*/
pluginExtension: string;
/**
* The default environment to load into the viewer for lighting (IBL).
*/
environmentLighting: string;
/**
* The default environment to load into the viewer for the skybox.
*/
environmentSkybox: string;
/**
* The default environment configuration.
*/
environmentConfig: Partial<EnvironmentParams>;
/**
* The default camera orbit.
* @remarks The default camera orbit is restored when a new model is loaded.
*/
cameraOrbit: Partial<CameraOrbit>;
/**
* The default camera target.
* @remarks The default camera target is restored when a new model is loaded.
*/
cameraTarget: Partial<CameraTarget>;
/**
* Automatically rotates a 3D model or scene without requiring user interaction.
* @remarks The default camera auto orbit is restored when a new model is loaded.
*/
cameraAutoOrbit: Partial<CameraAutoOrbit>;
/**
* Whether to play the default animation immediately after loading.
* @remarks The default animation auto play is restored when a new model is loaded.
*/
animationAutoPlay: boolean;
/**
* The default speed of the animation.
* @remarks The default animation speed is restored when a new model is loaded.
*/
animationSpeed: number;
/**
* The default selected animation.
* @remarks The default selected animation is restored when a new model is loaded.
*/
selectedAnimation: number;
/**
* The default post processing configuration.
*/
postProcessing: Partial<PostProcessing>;
/**
* Shadow configuration.
*/
shadowConfig: Partial<ShadowParams>;
/**
* The default selected material variant.
* @remarks The default material variant is restored when a new model is loaded.
*/
selectedMaterialVariant: string;
/**
* The default hotspots.
*/
hotSpots: Record<string, HotSpot>;
/**
* Boolean indicating if the scene must use right-handed coordinates system.
*/
useRightHandedSystem: boolean;
/**
* If true, load glTF files using the OpenPBR material instead of the default PBR material.
* @experimental
*/
useOpenPBR: boolean;
/**
* Called when a fatal error occurs that prevents the viewer from functioning.
*/
onFaulted: (error: Error) => void;
}>;
/**
* The subset of the Viewer API that ViewerElementBase depends on.
* Both the full Babylon.js Viewer and ViewerLite implement this contract.
*/
interface IViewer extends IDisposable {
/**
* Fired when the environment has changed.
*/
readonly onEnvironmentChanged: IReadonlyObservable<void>;
/**
* Fired when the environment configuration has changed.
*/
readonly onEnvironmentConfigurationChanged: IReadonlyObservable<void>;
/**
* Fired when an error occurs while loading the environment.
*/
readonly onEnvironmentError: IReadonlyObservable<unknown>;
/**
* Fired when the shadows configuration changes.
*/
readonly onShadowsConfigurationChanged: IReadonlyObservable<void>;
/**
* Fired when the post processing state changes.
*/
readonly onPostProcessingChanged: IReadonlyObservable<void>;
/**
* Fired when a model is loaded into the viewer (or unloaded from the viewer).
*/
readonly onModelChanged: IReadonlyObservable<Nullable<string | File | ArrayBufferView>>;
/**
* Fired when an error occurs while loading a model.
*/
readonly onModelError: IReadonlyObservable<unknown>;
/**
* Fired when progress changes on loading activity.
*/
readonly onLoadingProgressChanged: IReadonlyObservable<void>;
/**
* Fired when the camera auto orbit state changes.
*/
readonly onCameraAutoOrbitChanged: IReadonlyObservable<void>;
/**
* Fired when the selected animation changes.
*/
readonly onSelectedAnimationChanged: IReadonlyObservable<void>;
/**
* Fired when the animation speed changes.
*/
readonly onAnimationSpeedChanged: IReadonlyObservable<void>;
/**
* Fired when the selected animation is playing or paused.
*/
readonly onIsAnimationPlayingChanged: IReadonlyObservable<void>;
/**
* Fired when the current point on the selected animation timeline changes.
*/
readonly onAnimationProgressChanged: IReadonlyObservable<void>;
/**
* Fired when the selected material variant changes.
*/
readonly onSelectedMaterialVariantChanged: IReadonlyObservable<void>;
/**
* Fired when the hot spots object changes to a complete new object instance.
*/
readonly onHotSpotsChanged: IReadonlyObservable<void>;
/**
* Fired when the cameras as hot spots property changes.
*/
readonly onCamerasAsHotSpotsChanged: IReadonlyObservable<void>;
/**
* Fired after each frame is rendered.
*/
readonly onAfterRenderObservable: IReadonlyObservable<void>;
/**
* Fired when the clear color changes.
*/
readonly onClearColorChanged: IReadonlyObservable<void>;
/**
* Gets or sets the clear color (background color) of the viewer.
*/
clearColor: IColor4Like;
/**
* Gets the camera auto-orbit configuration.
*/
get cameraAutoOrbit(): Readonly<CameraAutoOrbit>;
/**
* Sets the camera auto-orbit configuration. Only specified fields are updated.
*/
set cameraAutoOrbit(value: Partial<Readonly<CameraAutoOrbit>>);
/**
* Resets the camera to its default state.
* @param reframe If true, reframes the camera to fit the model. If undefined, automatically determined.
*/
resetCamera(reframe?: boolean): void;
/**
* Updates the camera pose.
* @param pose The new pose of the camera. Any unspecified values are left unchanged.
*/
updateCamera(pose: {
alpha?: number;
beta?: number;
radius?: number;
targetX?: number;
targetY?: number;
targetZ?: number;
}): void;
/**
* Gets the environment configuration.
*/
get environmentConfig(): Readonly<EnvironmentParams>;
/**
* Sets the environment configuration. Only specified fields are updated.
*/
set environmentConfig(value: Partial<Readonly<EnvironmentParams>>);
/**
* Loads an environment from the specified URL.
* @param url The URL of the environment to load.
* @param options The options for loading the environment.
* @param abortSignal An optional signal that can be used to abort the load.
*/
loadEnvironment(url: string, options?: LoadEnvironmentOptions, abortSignal?: AbortSignal): Promise<void>;
/**
* Resets the environment to its default state.
* @param options The options to use when resetting the environment.
* @param abortSignal An optional signal that can be used to abort the reset.
*/
resetEnvironment(options?: EnvironmentOptions, abortSignal?: AbortSignal): Promise<void>;
/**
* Gets the post-processing configuration.
*/
get postProcessing(): Readonly<PostProcessing>;
/**
* Sets the post-processing configuration. Only specified fields are updated.
*/
set postProcessing(value: Partial<Readonly<PostProcessing>>);
/**
* Gets the current shadow configuration.
*/
readonly shadowConfig: Readonly<ShadowParams>;
/**
* Updates the shadow configuration.
* @param value The new shadow configuration.
* @param abortSignal Optional signal that can be used to abort the update.
*/
updateShadows(value: Partial<Readonly<ShadowParams>>, abortSignal?: AbortSignal): Promise<void>;
/**
* Loads a 3D model from the specified source.
* @param source The source of the model to load.
* @param options The options for loading the model.
* @param abortSignal An optional signal that can be used to abort the load.
*/
loadModel(source: string | File | ArrayBufferView, options?: ViewerLoadModelOptions, abortSignal?: AbortSignal): Promise<void>;
/**
* Unloads the current 3D model if one is loaded.
* @param abortSignal An optional signal that can be used to abort the reset.
*/
resetModel(abortSignal?: AbortSignal): Promise<void>;
/**
* The list of animation names for the currently loaded model.
*/
readonly animations: readonly string[];
/**
* Gets or sets the index of the selected animation.
*/
selectedAnimation: number;
/**
* Gets or sets the speed scale at which animations are played.
*/
animationSpeed: number;
/**
* True if an animation is currently playing.
*/
readonly isAnimationPlaying: boolean;
/**
* Gets or sets the current point on the selected animation timeline, normalized between 0 and 1.
*/
animationProgress: number;
/**
* Toggles between playing and pausing the selected animation.
*/
toggleAnimation(): void;
/**
* Plays the selected animation.
*/
playAnimation(): void;
/**
* Pauses the selected animation.
*/
pauseAnimation(): Promise<void>;
/**
* The list of material variant names for the currently loaded model.
*/
readonly materialVariants: readonly string[];
/**
* Gets or sets the selected material variant.
*/
selectedMaterialVariant: Nullable<string>;
/**
* Gets or sets the hot spots configuration.
*/
hotSpots: Record<string, HotSpot>;
/**
* Gets or sets whether cameras embedded in the model should be exposed as hot spots.
*/
camerasAsHotSpots: boolean;
/**
* Queries a named hot spot and returns its screen and world positions.
* @param name The name of the hot spot to query.
* @param result The result object to populate.
* @returns True if the hot spot was found.
*/
queryHotSpot(name: string, result: ViewerHotSpotResult): boolean;
/**
* Updates the camera to focus on a named hotspot.
* @param name The name of the hotspot to focus on.
* @returns True if the hotspot was found and the camera was updated.
*/
focusHotSpot(name: string): boolean;
/**
* True if a model is currently loaded.
*/
readonly isModelLoaded: boolean;
/**
* The current loading progress. False when not loading, true when loading with indeterminate progress, or a number between 0 and 1.
*/
readonly loadingProgress: boolean | number;
/**
* Resets the viewer to its initial state based on the options passed in to the constructor.
* @param flags The flags that specify which parts of the viewer to reset. If no flags are provided, all parts will be reset.
*/
reset(...flags: ResetFlag[]): void;
/**
* Disposes the viewer and releases all resources.
*/
dispose(): void;
}
/**
* Common base for the full Babylon.js {@link Viewer} and the lite Viewer.
*
* Encapsulates the pieces that are identical between both engine backends:
* - The 18 public observables exposed by the viewer surface area
* - In-flight load operation tracking (used to compute aggregate `loadingProgress`)
* - The `_throwIfDisposedOrAborted` helper used at the start of every async operation
* - The disposed flag and observable teardown in `dispose()`
*
* Subclasses are responsible for everything engine-specific (scene/engine creation,
* model + environment loading orchestration, camera, post-processing, shadows, etc.)
* and for declaring `implements IViewer` themselves so the public API contract is
* verified at the leaf class level.
*/
declare abstract class ViewerBase {
/**
* Fired when the environment has changed.
*/
readonly onEnvironmentChanged: Observable<void>;
/**
* Fired when the environment configuration has changed.
*/
readonly onEnvironmentConfigurationChanged: Observable<void>;
/**
* Fired when an error occurs while loading the environment.
*/
readonly onEnvironmentError: Observable<unknown>;
/**
* Fired when the shadows configuration changes.
*/
readonly onShadowsConfigurationChanged: Observable<void>;
/**
* Fired when the post processing state changes.
*/
readonly onPostProcessingChanged: Observable<void>;
/**
* Fired when a model is loaded into the viewer (or unloaded from the viewer).
* @remarks
* The event argument is the source that was loaded, or null if no model is loaded.
*/
readonly onModelChanged: Observable<Nullable<string | File | ArrayBufferView<ArrayBufferLike>>>;
/**
* Fired when an error occurs while loading a model.
*/
readonly onModelError: Observable<unknown>;
/**
* Fired when progress changes on loading activity.
*/
readonly onLoadingProgressChanged: Observable<void>;
/**
* Fired when the camera auto orbit state changes.
*/
readonly onCameraAutoOrbitChanged: Observable<void>;
/**
* Fired when the selected animation changes.
*/
readonly onSelectedAnimationChanged: Observable<void>;
/**
* Fired when the animation speed changes.
*/
readonly onAnimationSpeedChanged: Observable<void>;
/**
* Fired when the selected animation is playing or paused.
*/
readonly onIsAnimationPlayingChanged: Observable<void>;
/**
* Fired when the current point on the selected animation timeline changes.
*/
readonly onAnimationProgressChanged: Observable<void>;
/**
* Fired when the selected material variant changes.
*/
readonly onSelectedMaterialVariantChanged: Observable<void>;
/**
* Fired when the hot spots object changes to a complete new object instance.
*/
readonly onHotSpotsChanged: Observable<void>;
/**
* Fired when the cameras as hot spots property changes.
*/
readonly onCamerasAsHotSpotsChanged: Observable<void>;
/**
* Fired after each frame is rendered.
*/
readonly onAfterRenderObservable: Observable<void>;
/**
* Fired when the clear color changes.
*/
readonly onClearColorChanged: Observable<void>;
/**
* @internal Tracks in-flight load operations (model + environment + shadows) so that
* `loadingProgress` can return either an aggregate progress number, `true` (indeterminate),
* or `false` (no operations in flight).
*/
protected readonly _loadOperations: Set<Readonly<{
progress: Nullable<number>;
}>>;
/** @internal True after `dispose()` has been called. */
protected _isDisposed: boolean;
/**
* @internal Backend-agnostic viewer options stored at construction time. Subclasses declare this
* with their own (narrower) options type that extends {@link ViewerBaseOptions} and assign it from
* their own constructor (typically via a parameter property).
*/
protected abstract readonly _options?: Readonly<ViewerBaseOptions>;
/**
* The current loading progress. False when no load is in flight, true when at least one
* load is in flight with indeterminate progress, or a number between 0 and 1 representing
* the average of all in-flight loads' progress.
*/
get loadingProgress(): boolean | number;
/**
* Begin tracking a new load operation. Subclasses call this at the start of an async load
* and dispose the returned handle when it completes (or fails). The handle exposes a
* `progress` setter that, when assigned, fires `onLoadingProgressChanged`.
* @returns A handle that can be disposed when the operation completes; the `progress` setter
* updates the aggregate `loadingProgress` as the operation runs.
*/
protected _beginLoadOperation(): IDisposable & {
progress: Nullable<number>;
};
/**
* @internal Throws if the viewer has been disposed or any of the supplied abort signals
* are aborted. Used at the start of every async operation to bail out early.
* @param abortSignals Optional abort signals to check.
*/
protected _throwIfDisposedOrAborted(...abortSignals: (Nullable<AbortSignal> | undefined)[]): void;
/** Lock guarding lighting-side environment loads. */
private readonly _loadEnvironmentLightingLock;
/** Abort controller for the currently in-flight lighting-side load (null when none). */
private _loadEnvironmentLightingAbortController;
/** Lock guarding skybox-side environment loads. */
private readonly _loadEnvironmentSkyboxLock;
/** Abort controller for the currently in-flight skybox-side load (null when none). */
private _loadEnvironmentSkyboxAbortController;
/**
* @internal The abort signal of the currently in-flight lighting-side load, or `undefined` if
* none. Subclasses can use this in `_throwIfDisposedOrAborted` to bail out of dependent async
* work (shadows, post-processing, etc.) when the user starts a new lighting load.
*/
protected get _loadEnvironmentLightingAbortSignal(): AbortSignal | undefined;
/**
* @internal The abort signal of the currently in-flight skybox-side load, or `undefined` if
* none. Subclasses can use this in `_throwIfDisposedOrAborted` to bail out of dependent async
* work (shadows, post-processing, etc.) when the user starts a new skybox load.
*/
protected get _loadEnvironmentSkyboxAbortSignal(): AbortSignal | undefined;
/**
* Loads an environment from the specified URL. The lighting and skybox sides have
* independent locks and abort controllers so concurrent requests for one side don't
* cancel an in-flight load for the other.
* @param url The URL of the environment to load.
* @param options Selects which sides to update (defaults to both) and forwards engine-specific extras.
* @param abortSignal Optional signal that can be used to abort the load externally.
* @returns A promise that resolves when the environment has finished loading.
*/
loadEnvironment(url: string, options?: LoadEnvironmentOptions, abortSignal?: AbortSignal): Promise<void>;
/**
* Removes the loaded environment. By default removes both lighting and skybox; pass `options`
* to remove only one side. Subclasses (notably the full Viewer) may override to add backend-specific
* fallback behavior such as substituting a default environment for lighting when the scene contains
* PBR materials.
* @param options Selects which sides to remove (defaults to both).
* @param abortSignal Optional signal that can be used to abort the operation externally.
* @returns A promise that resolves when the environment has finished resetting.
*/
resetEnvironment(options?: EnvironmentOptions, abortSignal?: AbortSignal): Promise<void>;
/**
* @internal Internal helper exposing the dual-lock orchestration with a nullable URL.
* Used by the public `loadEnvironment` (with a string URL) and by subclass `resetEnvironment`
* implementations (which pass `undefined` to clear or `"auto"` to load defaults).
*
* Subclasses should NOT override this — override the abstract `_loadEnvironmentImpl` instead.
*/
protected _updateEnvironment(url: Nullable<string | undefined>, options?: LoadEnvironmentOptions, abortSignal?: AbortSignal): Promise<void>;
/**
* @internal Engine-specific environment loading. Subclasses implement this with their actual
* texture loading / scene mutation logic. The base class handles only the surrounding lock +
* abort-prev orchestration and the composite abort signal; everything else (`onEnvironmentChanged` /
* `onEnvironmentError` notifications, snapshot-helper bracketing, etc.) is the impl's responsibility.
*
* Implementations should:
* - Throw on failure. They should fire `onEnvironmentError` themselves before throwing if they
* want external observers to be notified.
* - Fire `onEnvironmentChanged` on success.
* - Periodically re-check abort by calling `throwIfAborted(abortSignal, compositeAbortSignal)`
* at safe points within the load (e.g. after long-running awaits).
*
* @param url Trimmed URL string, `undefined` (caller asked to clear), or `null`.
* @param options Resolved options — `lighting` and `skybox` are guaranteed booleans indicating
* which sides the caller is updating; engine-specific extras (e.g. `extension`) are forwarded as-is.
* @param abortSignal The caller's external abort signal (or `undefined`).
* @param compositeAbortSignal Signal that fires when ALL relevant internal load operations have aborted.
*/
protected abstract _loadEnvironmentImpl(url: Nullable<string | undefined>, options: ResolvedLoadEnvironmentOptions, abortSignal: AbortSignal | undefined, compositeAbortSignal: AbortSignal): Promise<void>;
/** @internal Current environment intensity. Initialized from options in subclass constructors. */
protected _environmentIntensity: number;
/** @internal Current environment skybox blur. Initialized from options in subclass constructors. */
protected _environmentBlur: number;
/** @internal Current environment rotation in radians. Initialized from options in subclass constructors. */
protected _environmentRotation: number;
get environmentConfig(): Readonly<EnvironmentParams>;
set environmentConfig(value: Partial<Readonly<EnvironmentParams>>);
/**
* @internal Push the current `_environmentIntensity` value into the engine's environment state.
* Called by the public `environmentConfig` setter only when the value changes.
*/
protected abstract _applyEnvironmentIntensity(): void;
/**
* @internal Push the current `_environmentBlur` value into the engine's environment state.
* Called by the public `environmentConfig` setter only when the value changes.
*/
protected abstract _applyEnvironmentBlur(): void;
/**
* @internal Push the current `_environmentRotation` value into the engine's environment state.
* Called by the public `environmentConfig` setter only when the value changes.
*/
protected abstract _applyEnvironmentRotation(): void;
/** @internal Initialized from options in subclass constructors. */
protected _autoOrbitEnabled: boolean;
/** @internal Initialized from options in subclass constructors. */
protected _autoOrbitSpeed: number;
/** @internal Initialized from options in subclass constructors. */
protected _autoOrbitDelay: number;
get cameraAutoOrbit(): Readonly<CameraAutoOrbit>;
set cameraAutoOrbit(value: Partial<Readonly<CameraAutoOrbit>>);
/**
* @internal Push the current `_autoOrbitEnabled` value into engine state.
* Called by the public `cameraAutoOrbit` setter only when the value changes.
*/
protected abstract _applyCameraAutoOrbitEnabled(): void;
/**
* @internal Push the current `_autoOrbitSpeed` value into engine state.
* Called by the public `cameraAutoOrbit` setter only when the value changes.
*/
protected abstract _applyCameraAutoOrbitSpeed(): void;
/**
* @internal Push the current `_autoOrbitDelay` value into engine state.
* Called by the public `cameraAutoOrbit` setter only when the value changes.
*/
protected abstract _applyCameraAutoOrbitDelay(): void;
/**
* @internal The current scene clear color, stored as a stable mutable record so consumers
* holding a reference returned by the `clearColor` getter see updates from the setter and from
* `reset("environment")`. The setter mutates this object in-place rather than replacing it.
*/
protected readonly _clearColor: IColor4Like;
/**
* The viewer clear color (e.g. background).
*/
get clearColor(): Readonly<IColor4Like>;
set clearColor(value: Readonly<IColor4Like>);
/**
* @internal Push the current `_clearColor` value into the engine's scene state. Called by the
* public `clearColor` setter; subclasses may also call this directly during construction to sync
* engine state to the initial field values.
*/
protected abstract _applyClearColor(): void;
/** @internal Pure state — no engine state. Subclasses initialize via the public `hotSpots` setter in their constructor body. */
private _hotSpots;
/**
* The set of defined hotspots.
*/
get hotSpots(): Record<string, HotSpot>;
set hotSpots(value: Record<string, HotSpot>);
/** Lock guarding model loads (and resets). */
private readonly _loadModelLock;
/** Abort controller for the currently in-flight model load (null when none). */
private _loadModelAbortController;
/**
* @internal The abort signal of the currently in-flight model load, or `undefined` if none.
* Subclasses can use this in `_throwIfDisposedOrAborted` to bail out of dependent async work
* (shadows, environment fallback, etc.) when the user starts a new model load.
*/
protected get _loadModelAbortSignal(): AbortSignal | undefined;
/**
* Loads a 3D model from the specified source.
* @param source The source of the model to load.
* @param options Engine-specific options for loading the model.
* @param abortSignal Optional signal that can be used to abort the load externally.
* @returns A promise that resolves when the model has finished loading.
*/
loadModel(source: string | File | ArrayBufferView, options?: ViewerLoadModelOptions, abortSignal?: AbortSignal): Promise<void>;
/**
* Unloads the current 3D model if one is loaded.
* @param abortSignal Optional signal that can be used to abort the reset.
* @returns A promise that resolves when the current model has been unloaded.
*/
resetModel(abortSignal?: AbortSignal): Promise<void>;
/**
* @internal Internal helper exposing the model load orchestration with `source: undefined` meaning
* "unload the current model". Subclasses should NOT override this — override `_loadModelImpl` instead.
*/
protected _updateModel(source: string | File | ArrayBufferView | undefined, options?: ViewerLoadModelOptions, abortSignal?: AbortSignal): Promise<void>;
/**
* @internal Engine-specific model loading. Subclasses implement this with their actual model
* loading logic. The base class handles only the surrounding lock + abort-prev orchestration;
* everything else (load-operation progress tracking, `onModelChanged` / `onModelError`
* notifications, snapshot-helper bracketing) is the impl's responsibility.
*
* Implementations should:
* - Throw on failure. They should fire `onModelError` themselves before throwing if they want
* external observers to be notified.
* - Fire `onModelChanged` on success.
* - Manage their own `_beginLoadOperation` / dispose pair if they want to contribute to
* `loadingProgress`.
* - Periodically re-check abort by calling `throwIfAborted(abortSignal, internalAbortSignal)`
* at safe points within the load (e.g. after long-running awaits).
* - Treat `source === undefined` as "unload the current model" — this is how `resetModel` flows
* through. They should still fire `onModelChanged(null)` so consumers see the unload.
*
* @param source Source URL/File/ArrayBufferView, or `undefined` to unload the current model.
* @param options Caller's options (or undefined). May contain engine-specific extras.
* @param abortSignal The caller's external abort signal (or `undefined`).
* @param internalAbortSignal Signal that fires when a NEWER model load supersedes this one.
*/
protected abstract _loadModelImpl(source: string | File | ArrayBufferView | undefined, options: ViewerLoadModelOptions | undefined, abortSignal: AbortSignal | undefined, internalAbortSignal: AbortSignal): Promise<void>;
/**
* @internal Optional post-lock hook invoked AFTER the model load lock is released, allowing
* subclasses to do follow-up work that needs other locks (e.g. environment fallback). The base
* skips this hook if the load was superseded by a newer one before we got here.
*
* Implementations that await additional work should re-check `internalAbortSignal.aborted`
* after each await to avoid acting on stale state (a newer load may have started during the
* await window).
*
* Default: no-op.
*/
protected _afterLoadModel(source: string | File | ArrayBufferView | undefined, options: ViewerLoadModelOptions | undefined, abortSignal: AbortSignal | undefined, internalAbortSignal: AbortSignal): Promise<void>;
/** Lock guarding shadow updates. */
private readonly _updateShadowsLock;
/** Abort controller for the currently in-flight shadow update (null when none). */
private _shadowsAbortController;
/**
* @internal The abort signal of the currently in-flight shadow update, or `undefined` if none.
* Subclasses can use this in `_throwIfDisposedOrAborted` to bail out of dependent async work
* when the user starts a new shadow update.
*/
protected get _shadowsAbortSignal(): AbortSignal | undefined;
/**
* @internal The currently committed shadow quality. Subclasses initialize this from their
* options in their constructor and read it in their `_loadModelImpl` etc. The base class
* commits a new value here only after `_updateShadowsImpl` succeeds, so failed/aborted
* shadow updates don't leave this field out of sync with engine state.
*/
protected _shadowQuality: ShadowQuality;
/** @internal */
abstract get selectedMaterialVariant(): Nullable<string>;
/** @internal */
abstract set selectedMaterialVariant(value: Nullable<string>);
/**
* Gets the current shadow configuration.
*/
get shadowConfig(): Readonly<ShadowParams>;
/**
* Updates the shadow configuration. Skips work if the requested value matches the currently
* committed one. Subclasses can override this to validate the requested quality (e.g. throw on
* unsupported combinations) before delegating to `super.updateShadows(value, abortSignal)`.
* @param value The new shadow configuration.
* @param abortSignal Optional signal that can be used to abort the update externally.
* @returns A promise that resolves when the shadow update completes.
*/
updateShadows(value: Partial<Readonly<ShadowParams>>, abortSignal?: AbortSignal): Promise<void>;
/**
* Runs the engine-specific shadow update at the given quality under the shared lock, with
* abort-prev semantics. Subclasses should call this (rather than `_updateShadowsImpl` directly)
* when they need to re-run the shadow setup (e.g. after a model change or environment change).
* The public `updateShadows` also routes through this helper.
* @param quality The shadow quality to apply. Defaults to the currently committed quality
* (`this._shadowQuality`), which is the right choice for re-running shadow setup without
* changing the committed quality. The public `updateShadows` passes a resolved new quality.
* @param abortSignal Optional external abort signal.
* @returns A promise that resolves when the shadow update completes.
*/
protected _updateShadows(quality?: ShadowQuality, abortSignal?: AbortSignal): Promise<void>;
/**
* @internal Engine-specific shadow setup. Subclasses implement this with their actual shadow
* generation logic. The base class handles all surrounding orchestration: lock acquisition,
* abort-prev semantics, quality resolution, and the success-only commit of `_shadowQuality`.
*
* Implementations should:
* - Throw on failure; the base class propagates the error to the caller without committing the new quality.
* - Use `quality` (not `this._shadowQuality`, which still holds the pre-update value) to drive the setup.
* - Periodically re-check abort by calling `throwIfAborted(abortSignal, internalAbortSignal)` at safe points.
*/
protected abstract _updateShadowsImpl(quality: ShadowQuality, abortSignal: AbortSignal | undefined, internalAbortSignal: AbortSignal): Promise<void>;
/**
* Disposes the viewer and releases shared resources (observables, disposed flag).
* Subclasses MUST override this method to dispose their own engine-specific state
* (engine, scene, abort controllers, models, etc.) and call `super.dispose()` last
* so observable consumers see the engine-specific notifications before observables clear.
*
* Subclasses should also early-return if `_isDisposed` is already true.
*/
dispose(): void;
/**
* Resets the viewer to its initial state based on the options passed in to the constructor.
* @param flags The flags that specify which parts of the viewer to reset. If no flags are provided, all parts will be reset.
* - "source": Reset the loaded model.
* - "environment": Reset environment related state.
* - "shadow": Reset shadow related state.
* - "animation": Reset animation related state.
* - "camera": Reset camera related state.
* - "post-processing": Reset post-processing related state.
* - "material-variant": Reset material variant related state.
*/
reset(...flags: ResetFlag[]): void;
/**
* @internal
* Orchestrates the reset operation in canonical flag order. The {@link interpolate} parameter is
* forwarded to per-flag hooks (currently only `_resetCamera`) so internal callers can reset
* without camera animation.
*/
protected _reset(interpolate: boolean, ...flags: ResetFlag[]): void;
/**
* @internal Resets the loaded model to the source specified at construction (or no model if no source was specified).
*/
protected _resetModel(): void;
/** @internal */
protected abstract _resetEnvironment(): void;
/**
* @internal Resets the shadow configuration to the value specified at construction.
*/
protected _resetShadows(): void;
/** @internal */
protected abstract _resetAnimation(): void;
/**
* @internal
* @param interpolate If true, animate camera transitions when supported. Subclasses without bounds-based
* reframing may ignore this parameter.
*/
protected abstract _resetCamera(interpolate: boolean): void;
/** @internal */
protected abstract _resetPostProcessing(): void;
/**
* @internal Resets the selected material variant to the value specified at construction (or null if not specified).
*/
protected _resetMaterialVariant(): void;
}
type ActivateModelOptions = Partial<{
source: string | File | ArrayBufferView;
}>;
type LoadModelOptions = ViewerLoadModelOptions & LoadAssetContainerOptions;
/**
* Generates a HotSpot from a camera by computing its spherical coordinates (alpha, beta, radius) relative to a target point.
*
* The target point is determined using the camera's forward ray:
* - If the ray intersects with a mesh in the model, the intersection point is used as the target.
* - If no intersection is found, a fallback target is calculated by projecting the distance
* between the camera and the model's center along the camera's forward direction.
*
* @param model The reference model used to determine the target point.
* @param camera The camera from which the HotSpot is generated.
* @returns A HotSpot object.
*/
declare function CreateHotSpotFromCamera(model: Model, camera: Camera): Promise<HotSpot>;
type ViewerDetails = {
/**
* Provides access to the Scene managed by the Viewer.
*/
scene: Scene;
/**
* Provides access to the Camera managed by the Viewer.
*/
camera: ArcRotateCamera;
/**
* Provides access to the currently loaded model.
*/
model: Nullable<Model>;
/**
* Suspends the render loop.
* @returns A token that should be disposed when the request for suspending rendering is no longer needed.
*/
suspendRendering(): IDisposable;
/**
* Marks the scene as mutated, which will trigger a render on the next frame (unless rendering is suspended).
*/
markSceneMutated(): void;
/**
* Picks the object at the given screen coordinates.
* @remarks This function ensures skeletal and morph target animations are up to date before picking, and typically should not be called at high frequency (e.g. every frame, on pointer move, etc.).
* @param screenX The x coordinate in screen space.
* @param screenY The y coordinate in screen space.
* @returns A PickingInfo if an object was picked, otherwise null.
*/
pick(screenX: number, screenY: number): Promise<Nullable<PickingInfo>>;
/**
* True if the viewer's render loop is currently suspended (not actively rendering).
*/
readonly isIdle: boolean;
};
/**
* The options for the Viewer.
*/
type ViewerOptions = ViewerBaseOptions & Partial<{
/**
* Called once when the viewer is initialized and provides viewer details that can be used for advanced customization.
*/
onInitialized: (details: Readonly<ViewerDetails>) => void;
}>;
/**
* The default options for the Viewer.
*/
declare const DefaultViewerOptions: {
readonly clearColor: [0, 0, 0, 0];
readonly autoSuspendRendering: true;
readonly environmentConfig: {
readonly intensity: 1;
readonly blur: 0.3;
readonly rotation: 0;
};
readonly environmentLighting: "auto";
readonly environmentSkybox: "none";
readonly cameraAutoOrbit: {
readonly enabled: false;
readonly delay: 2000;
readonly speed: 0.05;
};
readonly animationAutoPlay: false;
readonly animationSpeed: 1;
readonly shadowConfig: {
readonly quality: "none";
};
readonly postProcessing: {
readonly toneMapping: "neutral";
readonly contrast: 1;
readonly exposure: 1;
readonly ssao: "auto";
};
readonly useRightHandedSystem: false;
readonly useOpenPBR: false;
};
type ViewerCameraConfig = {
/**
* The goal radius of the camera.
* @remarks This is the size of the scene bounds (times a factor)
*/
radius: number;
/**
* The goal target of the camera.
* @remarks Center of the bounds of the scene or 0,0,0 by default
*/
target: Vector3;
/**
* The minimum zoom distance of the camera.
*/
lowerRadiusLimit: number;
/**
* The maximum zoom distance of the camera.
*/
upperRadiusLimit: number;
/**
* The minZ of the camera.
*/
minZ: number;
/**
* The maxZ of the camera.
*/
maxZ: number;
};
type Model = IDisposable & {
/**
* The asset container representing the model.
*/
readonly assetContainer: AssetContainer;
/**
* The material variants controller for the model.
*/
readonly materialVariantsController: Nullable<MaterialVariantsController>;
/**
* The current animation.
*/
selectedAnimation: number;
/**
* Returns the world position and visibility of a hot spot.
*/
getHotSpotToRef(query: Readonly<ViewerHotSpotQuery>, result: ViewerHotSpotResult): boolean;
/**
* Compute and return the world bounds of the model.
* The minimum and maximum extents, the size and the center.
* @param animationIndex The index of the animation group to use for computation. If omitted, the current selected animation is used.
* @returns The computed bounding info for the model or null if no meshes are present in the asset container.
*/
getWorldBounds(animationIndex?: number): Nullable<ViewerBoundingInfo>;
/**
* Resets the computed world bounds of the model.
* Should be called after the model undergoes transformations.
*/
resetWorldBounds(): void;
/**
* Makes the model the current active model in the viewer.
* @param options Options for activating the model.
*/
makeActive(options?: ActivateModelOptions): void;
/**
* The selected material variant.
*/
selectedMaterialVariant: Nullable<string>;
};
/**
* Provides an experience for viewing a single 3D model.
* @remarks
* The Viewer is not tied to a specific UI framework and can be used with Babylon.js in a browser or with Babylon Native.
*/
declare class Viewer extends ViewerBase implements IDisposable, IViewer {
private readonly _engine;
protected readonly _options?: Readonly<ViewerOptions> | undefined;
/**
* When enabled, the Viewer will emit additional diagnostic logs to the console.
*/
showDebugLogs: boolean;
/**
* Gets or sets the clear color (background color) of the viewer.
*/
/** @internal */
protected _applyClearColor(): void;
/**
* True if a model is currently loaded.
*/
get isModelLoaded(): boolean;
protected readonly _scene: Scene;
protected readonly _camera: ArcRotateCamera;
protected readonly _snapshotHelper: Nullable<SnapshotRenderingHelper>;
private _defaultMaterialPromise;
private readonly _defaultHardwareScalingLevel;
private _lastHardwareScalingLevel;
private _renderedLastFrame;
private _isIdle;
private _sceneOptimizer;
private readonly _tempVectors;
private readonly _meshDataCache;
private readonly _autoRotationBehavior;
private readonly _imageProcessingConfigurationObserver;
private readonly _beforeRenderObserver;
private _renderLoopController;
private _loadedModelsBacking;
private _activeModelBacking;
private _environmentSkyboxMode;
private _environmentLightingMode;
private _skybox;
private _skyboxTexture;
private _reflectionTexture;
private _light;
private _toneMappingEnabled;
private _toneMap