UNPKG

@needle-tools/engine

Version:

Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in.

1,480 lines • 708 kB
var ki = Object.defineProperty; var Qi = (e, t, i) => t in e ? ki(e, t, { enumerable: !0, configurable: !0, writable: !0, value: i }) : e[t] = i; var It = (e, t, i) => Qi(e, typeof t != "symbol" ? t + "" : t, i); import { Uniform$1 as c, Vector4 as Be, Color as N, Vector2 as p, CanvasTexture as Vi, RepeatWrapping as se, ShaderMaterial as w, NoBlending as G, WebGLRenderTarget as T, NearestFilter as P, EventDispatcher as Tt, SRGBColorSpace as y, UnsignedByteType as Y, PerspectiveCamera as Ie, BasicDepthPacking as W, REVISION as Re, LinearFilter as R, RGBADepthPacking as ae, FloatType as J, LessDepth as Rt, MeshDepthMaterial as Wi, LinearSRGBColorSpace as je, NoColorSpace as tt, DepthTexture as ye, DepthStencilFormat as Zt, UnsignedInt248Type as jt, UnsignedIntType as Le, RGBAFormat as z, Scene as dt, Matrix4 as O, Vector3 as L, HalfFloatType as $, Data3DTexture as Xe, Loader as St, LoadingManager as Ne, FileLoader as Jt, ClampToEdgeWrapping as st, DataTexture as it, RedFormat as rt, MeshNormalMaterial as Yi, BackSide as ke, DoubleSide as Qe, FrontSide as Ki, Camera as Xi, Mesh as qt, Texture as Je, EqualDepth as vt, NotEqualDepth as _t, LinearMipmapLinearFilter as Zi, GreaterDepth as ji, GreaterEqualDepth as Ji, LessEqualDepth as qi, AlwaysDepth as _i, NeverDepth as $i, Material as $t, BufferGeometry as ei, BufferAttribute as qe, RGFormat as er, DepthFormat as bt, OrthographicCamera as tr, Sphere as ir } from "./three-Bz6X1mrw.js"; import { Pass as rr } from "./three-examples-GggCDHv0.js"; /** * postprocessing v6.37.6 build Fri Jul 04 2025 * https://github.com/pmndrs/postprocessing * Copyright 2015-2025 Raoul van RĂ¼schen * @license Zlib */ var ar = "6.37.6", sr = class { /** * Frees internal resources. */ dispose() { } }, nt = 1 / 1e3, nr = 1e3, ti = class { /** * Constructs a new timer. */ constructor() { this.startTime = performance.now(), this.previousTime = 0, this.currentTime = 0, this._delta = 0, this._elapsed = 0, this._fixedDelta = 1e3 / 60, this.timescale = 1, this.useFixedDelta = !1, this._autoReset = !1; } /** * Enables or disables auto reset based on page visibility. * * If enabled, the timer will be reset when the page becomes visible. This effectively pauses the timer when the page * is hidden. Has no effect if the API is not supported. * * @type {Boolean} * @see https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API */ get autoReset() { return this._autoReset; } set autoReset(e) { typeof document < "u" && document.hidden !== void 0 && (e ? document.addEventListener("visibilitychange", this) : document.removeEventListener("visibilitychange", this), this._autoReset = e); } get delta() { return this._delta * nt; } get fixedDelta() { return this._fixedDelta * nt; } set fixedDelta(e) { this._fixedDelta = e * nr; } get elapsed() { return this._elapsed * nt; } /** * Updates this timer. * * @param {Boolean} [timestamp] - The current time in milliseconds. */ update(e) { this.useFixedDelta ? this._delta = this.fixedDelta : (this.previousTime = this.currentTime, this.currentTime = (e !== void 0 ? e : performance.now()) - this.startTime, this._delta = this.currentTime - this.previousTime), this._delta *= this.timescale, this._elapsed += this._delta; } /** * Resets this timer. */ reset() { this._delta = 0, this._elapsed = 0, this.currentTime = performance.now() - this.startTime; } getDelta() { return this.delta; } getElapsed() { return this.elapsed; } handleEvent(e) { document.hidden || (this.currentTime = performance.now() - this.startTime); } dispose() { this.autoReset = !1; } }, or = /* @__PURE__ */ (() => { const e = new Float32Array([-1, -1, 0, 3, -1, 0, -1, 3, 0]), t = new Float32Array([0, 0, 2, 0, 0, 2]), i = new ei(); return i.setAttribute("position", new qe(e, 3)), i.setAttribute("uv", new qe(t, 2)), i; })(), H = class pt { /** * A shared fullscreen triangle. * * The screen size is 2x2 units (NDC). A triangle needs to be 4x4 units to fill the screen. * @see https://michaldrobot.com/2014/04/01/gcn-execution-patterns-in-full-screen-passes/ * @type {BufferGeometry} * @internal */ static get fullscreenGeometry() { return or; } /** * Constructs a new pass. * * @param {String} [name] - The name of this pass. Does not have to be unique. * @param {Scene} [scene] - The scene to render. The default scene contains a single mesh that fills the screen. * @param {Camera} [camera] - A camera. Fullscreen effect passes don't require a camera. */ constructor(t = "Pass", i = new dt(), r = new Xi()) { this.name = t, this.renderer = null, this.scene = i, this.camera = r, this.screen = null, this.rtt = !0, this.needsSwap = !0, this.needsDepthTexture = !1, this.enabled = !0; } /** * Sets the render to screen flag. * * If this flag is changed, the fullscreen material will be updated as well. * * @type {Boolean} */ get renderToScreen() { return !this.rtt; } set renderToScreen(t) { if (this.rtt === t) { const i = this.fullscreenMaterial; i !== null && (i.needsUpdate = !0), this.rtt = !t; } } /** * Sets the main scene. * * @type {Scene} */ set mainScene(t) { } /** * Sets the main camera. * * @type {Camera} */ set mainCamera(t) { } /** * Sets the renderer * * @deprecated * @param {WebGLRenderer} renderer - The renderer. */ setRenderer(t) { this.renderer = t; } /** * Indicates whether this pass is enabled. * * @deprecated Use enabled instead. * @return {Boolean} Whether this pass is enabled. */ isEnabled() { return this.enabled; } /** * Enables or disables this pass. * * @deprecated Use enabled instead. * @param {Boolean} value - Whether the pass should be enabled. */ setEnabled(t) { this.enabled = t; } /** * The fullscreen material. * * @type {Material} */ get fullscreenMaterial() { return this.screen !== null ? this.screen.material : null; } set fullscreenMaterial(t) { let i = this.screen; i !== null ? i.material = t : (i = new qt(pt.fullscreenGeometry, t), i.frustumCulled = !1, this.scene === null && (this.scene = new dt()), this.scene.add(i), this.screen = i); } /** * Returns the current fullscreen material. * * @deprecated Use fullscreenMaterial instead. * @return {Material} The current fullscreen material, or null if there is none. */ getFullscreenMaterial() { return this.fullscreenMaterial; } /** * Sets the fullscreen material. * * @deprecated Use fullscreenMaterial instead. * @protected * @param {Material} value - A fullscreen material. */ setFullscreenMaterial(t) { this.fullscreenMaterial = t; } /** * Returns the current depth texture. * * @return {Texture} The current depth texture, or null if there is none. */ getDepthTexture() { return null; } /** * Sets the depth texture. * * This method will be called automatically by the {@link EffectComposer}. * You may override this method if your pass relies on the depth information of a preceding {@link RenderPass}. * * @param {Texture} depthTexture - A depth texture. * @param {DepthPackingStrategy} [depthPacking=BasicDepthPacking] - The depth packing. */ setDepthTexture(t, i = W) { } /** * Renders this pass. * * This is an abstract method that must be overridden. * * @abstract * @throws {Error} An error is thrown if the method is not overridden. * @param {WebGLRenderer} renderer - The renderer. * @param {WebGLRenderTarget} inputBuffer - A frame buffer that contains the result of the previous pass. * @param {WebGLRenderTarget} outputBuffer - A frame buffer that serves as the output render target unless this pass renders to screen. * @param {Number} [deltaTime] - The time between the last frame and the current one in seconds. * @param {Boolean} [stencilTest] - Indicates whether a stencil mask is active. */ render(t, i, r, a, n) { throw new Error("Render method not implemented!"); } /** * Sets the size. * * You may override this method if you want to be informed about the size of the backbuffer/canvas. * This method is called before {@link initialize} and every time the size of the {@link EffectComposer} changes. * * @param {Number} width - The width. * @param {Number} height - The height. */ setSize(t, i) { } /** * Performs initialization tasks. * * This method is called when this pass is added to an {@link EffectComposer}. * * @param {WebGLRenderer} renderer - The renderer. * @param {Boolean} alpha - Whether the renderer uses the alpha channel or not. * @param {Number} frameBufferType - The type of the main frame buffers. */ initialize(t, i, r) { } /** * Performs a shallow search for disposable properties and deletes them. * * The {@link EffectComposer} calls this method when it is being destroyed. You can use it independently to free * memory when you're certain that you don't need this pass anymore. */ dispose() { for (const t of Object.keys(this)) { const i = this[t]; (i instanceof T || i instanceof $t || i instanceof Je || i instanceof pt) && this[t].dispose(); } this.fullscreenMaterial !== null && this.fullscreenMaterial.dispose(); } }, ii = class extends H { /** * Constructs a new clear mask pass. */ constructor() { super("ClearMaskPass", null, null), this.needsSwap = !1; } /** * Disables the global stencil test. * * @param {WebGLRenderer} renderer - The renderer. * @param {WebGLRenderTarget} inputBuffer - A frame buffer that contains the result of the previous pass. * @param {WebGLRenderTarget} outputBuffer - A frame buffer that serves as the output render target unless this pass renders to screen. * @param {Number} [deltaTime] - The time between the last frame and the current one in seconds. * @param {Boolean} [stencilTest] - Indicates whether a stencil mask is active. */ render(e, t, i, r, a) { const n = e.state.buffers.stencil; n.setLocked(!1), n.setTest(!1); } }, lr = `#include <common> #include <dithering_pars_fragment> #ifdef FRAMEBUFFER_PRECISION_HIGH uniform mediump sampler2D inputBuffer; #else uniform lowp sampler2D inputBuffer; #endif uniform float opacity;varying vec2 vUv;void main(){vec4 texel=texture2D(inputBuffer,vUv);gl_FragColor=opacity*texel; #include <colorspace_fragment> #include <dithering_fragment> }`, ce = "varying vec2 vUv;void main(){vUv=position.xy*0.5+0.5;gl_Position=vec4(position.xy,1.0,1.0);}", He = class extends w { /** * Constructs a new copy material. */ constructor() { super({ name: "CopyMaterial", uniforms: { inputBuffer: new c(null), opacity: new c(1) }, blending: G, toneMapped: !1, depthWrite: !1, depthTest: !1, fragmentShader: lr, vertexShader: ce }); } /** * The input buffer. * * @type {Texture} */ set inputBuffer(e) { this.uniforms.inputBuffer.value = e; } /** * Sets the input buffer. * * @deprecated Use inputBuffer instead. * @param {Number} value - The buffer. */ setInputBuffer(e) { this.uniforms.inputBuffer.value = e; } /** * Returns the opacity. * * @deprecated Use opacity instead. * @return {Number} The opacity. */ getOpacity(e) { return this.uniforms.opacity.value; } /** * Sets the opacity. * * @deprecated Use opacity instead. * @param {Number} value - The opacity. */ setOpacity(e) { this.uniforms.opacity.value = e; } }, _e = class extends H { /** * Constructs a new save pass. * * @param {WebGLRenderTarget} [renderTarget] - A render target. * @param {Boolean} [autoResize=true] - Whether the render target size should be updated automatically. */ constructor(e, t = !0) { super("CopyPass"), this.fullscreenMaterial = new He(), this.needsSwap = !1, this.renderTarget = e, e === void 0 && (this.renderTarget = new T(1, 1, { minFilter: R, magFilter: R, stencilBuffer: !1, depthBuffer: !1 }), this.renderTarget.texture.name = "CopyPass.Target"), this.autoResize = t; } /** * Enables or disables auto resizing of the render target. * * @deprecated Use autoResize instead. * @type {Boolean} */ get resize() { return this.autoResize; } set resize(e) { this.autoResize = e; } /** * The output texture. * * @type {Texture} */ get texture() { return this.renderTarget.texture; } /** * Returns the output texture. * * @deprecated Use texture instead. * @return {Texture} The texture. */ getTexture() { return this.renderTarget.texture; } /** * Enables or disables auto resizing of the render target. * * @deprecated Use autoResize instead. * @param {Boolean} value - Whether the render target size should be updated automatically. */ setAutoResizeEnabled(e) { this.autoResize = e; } /** * Saves the input buffer. * * @param {WebGLRenderer} renderer - The renderer. * @param {WebGLRenderTarget} inputBuffer - A frame buffer that contains the result of the previous pass. * @param {WebGLRenderTarget} outputBuffer - A frame buffer that serves as the output render target unless this pass renders to screen. * @param {Number} [deltaTime] - The time between the last frame and the current one in seconds. * @param {Boolean} [stencilTest] - Indicates whether a stencil mask is active. */ render(e, t, i, r, a) { this.fullscreenMaterial.inputBuffer = t.texture, e.setRenderTarget(this.renderToScreen ? null : this.renderTarget), e.render(this.scene, this.camera); } /** * Updates the size of this pass. * * @param {Number} width - The width. * @param {Number} height - The height. */ setSize(e, t) { this.autoResize && this.renderTarget.setSize(e, t); } /** * Performs initialization tasks. * * @param {WebGLRenderer} renderer - A renderer. * @param {Boolean} alpha - Whether the renderer uses the alpha channel. * @param {Number} frameBufferType - The type of the main frame buffers. */ initialize(e, t, i) { i !== void 0 && (this.renderTarget.texture.type = i, i !== Y ? this.fullscreenMaterial.defines.FRAMEBUFFER_PRECISION_HIGH = "1" : e !== null && e.outputColorSpace === y && (this.renderTarget.texture.colorSpace = y)); } }, Ut = /* @__PURE__ */ new N(), ge = class extends H { /** * Constructs a new clear pass. * * @param {Boolean} [color=true] - Determines whether the color buffer should be cleared. * @param {Boolean} [depth=true] - Determines whether the depth buffer should be cleared. * @param {Boolean} [stencil=false] - Determines whether the stencil buffer should be cleared. */ constructor(e = !0, t = !0, i = !1) { super("ClearPass", null, null), this.needsSwap = !1, this.color = e, this.depth = t, this.stencil = i, this.overrideClearColor = null, this.overrideClearAlpha = -1; } /** * Sets the clear flags. * * @param {Boolean} color - Whether the color buffer should be cleared. * @param {Boolean} depth - Whether the depth buffer should be cleared. * @param {Boolean} stencil - Whether the stencil buffer should be cleared. */ setClearFlags(e, t, i) { this.color = e, this.depth = t, this.stencil = i; } /** * Returns the override clear color. Default is null. * * @deprecated Use overrideClearColor instead. * @return {Color} The clear color. */ getOverrideClearColor() { return this.overrideClearColor; } /** * Sets the override clear color. * * @deprecated Use overrideClearColor instead. * @param {Color} value - The clear color. */ setOverrideClearColor(e) { this.overrideClearColor = e; } /** * Returns the override clear alpha. Default is -1. * * @deprecated Use overrideClearAlpha instead. * @return {Number} The clear alpha. */ getOverrideClearAlpha() { return this.overrideClearAlpha; } /** * Sets the override clear alpha. * * @deprecated Use overrideClearAlpha instead. * @param {Number} value - The clear alpha. */ setOverrideClearAlpha(e) { this.overrideClearAlpha = e; } /** * Clears the input buffer or the screen. * * @param {WebGLRenderer} renderer - The renderer. * @param {WebGLRenderTarget} inputBuffer - A frame buffer that contains the result of the previous pass. * @param {WebGLRenderTarget} outputBuffer - A frame buffer that serves as the output render target unless this pass renders to screen. * @param {Number} [deltaTime] - The time between the last frame and the current one in seconds. * @param {Boolean} [stencilTest] - Indicates whether a stencil mask is active. */ render(e, t, i, r, a) { const n = this.overrideClearColor, s = this.overrideClearAlpha, o = e.getClearAlpha(), l = n !== null, u = s >= 0; l ? (e.getClearColor(Ut), e.setClearColor(n, u ? s : o)) : u && e.setClearAlpha(s), e.setRenderTarget(this.renderToScreen ? null : t), e.clear(this.color, this.depth, this.stencil), l ? e.setClearColor(Ut, o) : u && e.setClearAlpha(o); } }, ri = class extends H { /** * Constructs a new mask pass. * * @param {Scene} scene - The scene to render. * @param {Camera} camera - The camera to use. */ constructor(e, t) { super("MaskPass", e, t), this.needsSwap = !1, this.clearPass = new ge(!1, !1, !0), this.inverse = !1; } set mainScene(e) { this.scene = e; } set mainCamera(e) { this.camera = e; } /** * Indicates whether the mask should be inverted. * * @type {Boolean} */ get inverted() { return this.inverse; } set inverted(e) { this.inverse = e; } /** * Indicates whether this pass should clear the stencil buffer. * * @type {Boolean} * @deprecated Use clearPass.enabled instead. */ get clear() { return this.clearPass.enabled; } set clear(e) { this.clearPass.enabled = e; } /** * Returns the internal clear pass. * * @deprecated Use clearPass.enabled instead. * @return {ClearPass} The clear pass. */ getClearPass() { return this.clearPass; } /** * Indicates whether the mask is inverted. * * @deprecated Use inverted instead. * @return {Boolean} Whether the mask is inverted. */ isInverted() { return this.inverted; } /** * Enables or disable mask inversion. * * @deprecated Use inverted instead. * @param {Boolean} value - Whether the mask should be inverted. */ setInverted(e) { this.inverted = e; } /** * Renders the effect. * * @param {WebGLRenderer} renderer - The renderer. * @param {WebGLRenderTarget} inputBuffer - A frame buffer that contains the result of the previous pass. * @param {WebGLRenderTarget} outputBuffer - A frame buffer that serves as the output render target unless this pass renders to screen. * @param {Number} [deltaTime] - The time between the last frame and the current one in seconds. * @param {Boolean} [stencilTest] - Indicates whether a stencil mask is active. */ render(e, t, i, r, a) { const n = e.getContext(), s = e.state.buffers, o = this.scene, l = this.camera, u = this.clearPass, f = this.inverted ? 0 : 1, h = 1 - f; s.color.setMask(!1), s.depth.setMask(!1), s.color.setLocked(!0), s.depth.setLocked(!0), s.stencil.setTest(!0), s.stencil.setOp(n.REPLACE, n.REPLACE, n.REPLACE), s.stencil.setFunc(n.ALWAYS, f, 4294967295), s.stencil.setClear(h), s.stencil.setLocked(!0), this.clearPass.enabled && (this.renderToScreen ? u.render(e, null) : (u.render(e, t), u.render(e, i))), this.renderToScreen ? (e.setRenderTarget(null), e.render(o, l)) : (e.setRenderTarget(t), e.render(o, l), e.setRenderTarget(i), e.render(o, l)), s.color.setLocked(!1), s.depth.setLocked(!1), s.stencil.setLocked(!1), s.stencil.setFunc(n.EQUAL, 1, 4294967295), s.stencil.setOp(n.KEEP, n.KEEP, n.KEEP), s.stencil.setLocked(!0); } }, ur = class { /** * Constructs a new effect composer. * * @param {WebGLRenderer} renderer - The renderer that should be used. * @param {Object} [options] - The options. * @param {Boolean} [options.depthBuffer=true] - Whether the main render targets should have a depth buffer. * @param {Boolean} [options.stencilBuffer=false] - Whether the main render targets should have a stencil buffer. * @param {Boolean} [options.alpha] - Deprecated. Buffers are always RGBA since three r137. * @param {Number} [options.multisampling=0] - The number of samples used for multisample antialiasing. Requires WebGL 2. * @param {Number} [options.frameBufferType] - The type of the internal frame buffers. It's recommended to use HalfFloatType if possible. */ constructor(e = null, { depthBuffer: t = !0, stencilBuffer: i = !1, multisampling: r = 0, frameBufferType: a } = {}) { this.renderer = null, this.inputBuffer = this.createBuffer(t, i, a, r), this.outputBuffer = this.inputBuffer.clone(), this.copyPass = new _e(), this.depthTexture = null, this.passes = [], this.timer = new ti(), this.autoRenderToScreen = !0, this.setRenderer(e); } /** * The current amount of samples used for multisample anti-aliasing. * * @type {Number} */ get multisampling() { return this.inputBuffer.samples || 0; } /** * Sets the amount of MSAA samples. * * Requires WebGL 2. Set to zero to disable multisampling. * * @type {Number} */ set multisampling(e) { const t = this.inputBuffer, i = this.multisampling; i > 0 && e > 0 ? (this.inputBuffer.samples = e, this.outputBuffer.samples = e, this.inputBuffer.dispose(), this.outputBuffer.dispose()) : i !== e && (this.inputBuffer.dispose(), this.outputBuffer.dispose(), this.inputBuffer = this.createBuffer( t.depthBuffer, t.stencilBuffer, t.texture.type, e ), this.inputBuffer.depthTexture = this.depthTexture, this.outputBuffer = this.inputBuffer.clone()); } /** * Returns the internal timer. * * @return {Timer} The timer. */ getTimer() { return this.timer; } /** * Returns the renderer. * * @return {WebGLRenderer} The renderer. */ getRenderer() { return this.renderer; } /** * Sets the renderer. * * @param {WebGLRenderer} renderer - The renderer. */ setRenderer(e) { if (this.renderer = e, e !== null) { const t = e.getSize(new p()), i = e.getContext().getContextAttributes().alpha, r = this.inputBuffer.texture.type; r === Y && e.outputColorSpace === y && (this.inputBuffer.texture.colorSpace = y, this.outputBuffer.texture.colorSpace = y, this.inputBuffer.dispose(), this.outputBuffer.dispose()), e.autoClear = !1, this.setSize(t.width, t.height); for (const a of this.passes) a.initialize(e, i, r); } } /** * Replaces the current renderer with the given one. * * The auto clear mechanism of the provided renderer will be disabled. If the new render size differs from the * previous one, all passes will be updated. * * By default, the DOM element of the current renderer will automatically be removed from its parent node and the DOM * element of the new renderer will take its place. * * @deprecated Use setRenderer instead. * @param {WebGLRenderer} renderer - The new renderer. * @param {Boolean} updateDOM - Indicates whether the old canvas should be replaced by the new one in the DOM. * @return {WebGLRenderer} The old renderer. */ replaceRenderer(e, t = !0) { const i = this.renderer, r = i.domElement.parentNode; return this.setRenderer(e), t && r !== null && (r.removeChild(i.domElement), r.appendChild(e.domElement)), i; } /** * Creates a depth texture attachment that will be provided to all passes. * * Note: When a shader reads from a depth texture and writes to a render target that uses the same depth texture * attachment, the depth information will be lost. This happens even if `depthWrite` is disabled. * * @private * @return {DepthTexture} The depth texture. */ createDepthTexture() { const e = this.depthTexture = new ye(); return this.inputBuffer.depthTexture = e, this.inputBuffer.dispose(), this.inputBuffer.stencilBuffer ? (e.format = Zt, e.type = jt) : e.type = Le, e; } /** * Deletes the current depth texture. * * @private */ deleteDepthTexture() { if (this.depthTexture !== null) { this.depthTexture.dispose(), this.depthTexture = null, this.inputBuffer.depthTexture = null, this.inputBuffer.dispose(); for (const e of this.passes) e.setDepthTexture(null); } } /** * Creates a new render target. * * @deprecated Create buffers manually via WebGLRenderTarget instead. * @param {Boolean} depthBuffer - Whether the render target should have a depth buffer. * @param {Boolean} stencilBuffer - Whether the render target should have a stencil buffer. * @param {Number} type - The frame buffer type. * @param {Number} multisampling - The number of samples to use for antialiasing. * @return {WebGLRenderTarget} A new render target that equals the renderer's canvas. */ createBuffer(e, t, i, r) { const a = this.renderer, n = a === null ? new p() : a.getDrawingBufferSize(new p()), s = { minFilter: R, magFilter: R, stencilBuffer: t, depthBuffer: e, type: i }, o = new T(n.width, n.height, s); return r > 0 && (o.ignoreDepthForMultisampleCopy = !1, o.samples = r), i === Y && a !== null && a.outputColorSpace === y && (o.texture.colorSpace = y), o.texture.name = "EffectComposer.Buffer", o.texture.generateMipmaps = !1, o; } /** * Can be used to change the main scene for all registered passes and effects. * * @param {Scene} scene - The scene. */ setMainScene(e) { for (const t of this.passes) t.mainScene = e; } /** * Can be used to change the main camera for all registered passes and effects. * * @param {Camera} camera - The camera. */ setMainCamera(e) { for (const t of this.passes) t.mainCamera = e; } /** * Adds a pass, optionally at a specific index. * * @param {Pass} pass - A new pass. * @param {Number} [index] - An index at which the pass should be inserted. */ addPass(e, t) { const i = this.passes, r = this.renderer, a = r.getDrawingBufferSize(new p()), n = r.getContext().getContextAttributes().alpha, s = this.inputBuffer.texture.type; if (e.setRenderer(r), e.setSize(a.width, a.height), e.initialize(r, n, s), this.autoRenderToScreen && (i.length > 0 && (i[i.length - 1].renderToScreen = !1), e.renderToScreen && (this.autoRenderToScreen = !1)), t !== void 0 ? i.splice(t, 0, e) : i.push(e), this.autoRenderToScreen && (i[i.length - 1].renderToScreen = !0), e.needsDepthTexture || this.depthTexture !== null) if (this.depthTexture === null) { const o = this.createDepthTexture(); for (e of i) e.setDepthTexture(o); } else e.setDepthTexture(this.depthTexture); } /** * Removes a pass. * * @param {Pass} pass - The pass. */ removePass(e) { const t = this.passes, i = t.indexOf(e); if (i !== -1 && t.splice(i, 1).length > 0) { if (this.depthTexture !== null) { const n = (o, l) => o || l.needsDepthTexture; t.reduce(n, !1) || (e.getDepthTexture() === this.depthTexture && e.setDepthTexture(null), this.deleteDepthTexture()); } this.autoRenderToScreen && i === t.length && (e.renderToScreen = !1, t.length > 0 && (t[t.length - 1].renderToScreen = !0)); } } /** * Removes all passes. */ removeAllPasses() { const e = this.passes; this.deleteDepthTexture(), e.length > 0 && (this.autoRenderToScreen && (e[e.length - 1].renderToScreen = !1), this.passes = []); } /** * Renders all enabled passes in the order in which they were added. * * @param {Number} [deltaTime] - The time since the last frame in seconds. */ render(e) { const t = this.renderer, i = this.copyPass; let r = this.inputBuffer, a = this.outputBuffer, n = !1, s, o, l; e === void 0 && (this.timer.update(), e = this.timer.getDelta()); for (const u of this.passes) u.enabled && (u.render(t, r, a, e, n), u.needsSwap && (n && (i.renderToScreen = u.renderToScreen, s = t.getContext(), o = t.state.buffers.stencil, o.setFunc(s.NOTEQUAL, 1, 4294967295), i.render(t, r, a, e, n), o.setFunc(s.EQUAL, 1, 4294967295)), l = r, r = a, a = l), u instanceof ri ? n = !0 : u instanceof ii && (n = !1)); } /** * Sets the size of the buffers, passes and the renderer. * * @param {Number} width - The width. * @param {Number} height - The height. * @param {Boolean} [updateStyle] - Determines whether the style of the canvas should be updated. */ setSize(e, t, i) { const r = this.renderer, a = r.getSize(new p()); (e === void 0 || t === void 0) && (e = a.width, t = a.height), (a.width !== e || a.height !== t) && r.setSize(e, t, i); const n = r.getDrawingBufferSize(new p()); this.inputBuffer.setSize(n.width, n.height), this.outputBuffer.setSize(n.width, n.height); for (const s of this.passes) s.setSize(n.width, n.height); } /** * Resets this composer by deleting all passes and creating new buffers. */ reset() { this.dispose(), this.autoRenderToScreen = !0; } /** * Disposes this composer and all passes. */ dispose() { for (const e of this.passes) e.dispose(); this.passes = [], this.inputBuffer !== null && this.inputBuffer.dispose(), this.outputBuffer !== null && this.outputBuffer.dispose(), this.deleteDepthTexture(), this.copyPass.dispose(), this.timer.dispose(), H.fullscreenGeometry.dispose(); } }, V = { NONE: 0, DEPTH: 1, CONVOLUTION: 2 }, B = { FRAGMENT_HEAD: "FRAGMENT_HEAD", FRAGMENT_MAIN_UV: "FRAGMENT_MAIN_UV", FRAGMENT_MAIN_IMAGE: "FRAGMENT_MAIN_IMAGE", VERTEX_HEAD: "VERTEX_HEAD", VERTEX_MAIN_SUPPORT: "VERTEX_MAIN_SUPPORT" }, ai = class { /** * Constructs new shader data. */ constructor() { this.shaderParts = /* @__PURE__ */ new Map([ [B.FRAGMENT_HEAD, null], [B.FRAGMENT_MAIN_UV, null], [B.FRAGMENT_MAIN_IMAGE, null], [B.VERTEX_HEAD, null], [B.VERTEX_MAIN_SUPPORT, null] ]), this.defines = /* @__PURE__ */ new Map(), this.uniforms = /* @__PURE__ */ new Map(), this.blendModes = /* @__PURE__ */ new Map(), this.extensions = /* @__PURE__ */ new Set(), this.attributes = V.NONE, this.varyings = /* @__PURE__ */ new Set(), this.uvTransformation = !1, this.readDepth = !1, this.colorSpace = je; } }; function Ft(e) { let t; if (e === 0) t = new Float64Array(0); else if (e === 1) t = new Float64Array([1]); else if (e > 1) { let i = new Float64Array(e), r = new Float64Array(e); for (let a = 1; a <= e; ++a) { for (let n = 0; n < a; ++n) r[n] = n === 0 || n === a - 1 ? 1 : i[n - 1] + i[n]; t = r, r = i, i = t; } } return t; } var si = class { /** * Constructs a new Gauss kernel. * * @param {Number} kernelSize - The kernel size. Should be an odd number in the range [3, 1020]. * @param {Number} [edgeBias=2] - Determines how many edge coefficients should be cut off for increased accuracy. */ constructor(e, t = 2) { this.weights = null, this.offsets = null, this.linearWeights = null, this.linearOffsets = null, this.generate(e, t); } /** * The number of steps for discrete sampling. * * @type {Number} */ get steps() { return this.offsets === null ? 0 : this.offsets.length; } /** * The number of steps for linear sampling. * * @type {Number} */ get linearSteps() { return this.linearOffsets === null ? 0 : this.linearOffsets.length; } /** * Generates the kernel. * * @private * @param {Number} kernelSize - The kernel size. * @param {Number} edgeBias - The amount of edge coefficients to ignore. */ generate(e, t) { if (e < 3 || e > 1020) throw new Error("The kernel size must be in the range [3, 1020]"); const i = e + t * 2, r = t > 0 ? Ft(i).slice(t, -t) : Ft(i), a = Math.floor((r.length - 1) / 2), n = r.reduce((h, d) => h + d, 0), s = r.slice(a), o = [...Array(a + 1).keys()], l = new Float64Array(Math.floor(o.length / 2)), u = new Float64Array(l.length); l[0] = s[0] / n; for (let h = 1, d = 1, v = o.length - 1; h < v; h += 2, ++d) { const A = o[h], m = o[h + 1], E = s[h], C = s[h + 1], S = E + C, D = (A * E + m * C) / S; l[d] = S / n, u[d] = D; } for (let h = 0, d = s.length, v = 1 / n; h < d; ++h) s[h] *= v; const f = (l.reduce((h, d) => h + d, 0) - l[0] * 0.5) * 2; if (f !== 0) for (let h = 0, d = l.length, v = 1 / f; h < d; ++h) l[h] *= v; this.offsets = o, this.weights = s, this.linearOffsets = u, this.linearWeights = l; } }, cr = class { /** * The current delta time in seconds. * * @type {Number} */ getDelta() { return NaN; } /** * The elapsed time in seconds. * * @type {Number} */ getElapsed() { return NaN; } }, fr = class { /** * Performs initialization tasks. * * @param {WebGLRenderer} renderer - A renderer. * @param {Boolean} alpha - Whether the renderer uses the alpha channel. * @param {Number} frameBufferType - The type of the main frame buffers. */ initialize(e, t, i) { } }, ot = !1, gt = class { /** * Constructs a new override material manager. * * @param {Material} [material=null] - An override material. */ constructor(e = null) { this.originalMaterials = /* @__PURE__ */ new Map(), this.material = null, this.materials = null, this.materialsBackSide = null, this.materialsDoubleSide = null, this.materialsFlatShaded = null, this.materialsFlatShadedBackSide = null, this.materialsFlatShadedDoubleSide = null, this.setMaterial(e), this.meshCount = 0, this.replaceMaterial = (t) => { if (t.isMesh) { let i; if (t.material.flatShading) switch (t.material.side) { case Qe: i = this.materialsFlatShadedDoubleSide; break; case ke: i = this.materialsFlatShadedBackSide; break; default: i = this.materialsFlatShaded; break; } else switch (t.material.side) { case Qe: i = this.materialsDoubleSide; break; case ke: i = this.materialsBackSide; break; default: i = this.materials; break; } this.originalMaterials.set(t, t.material), t.isSkinnedMesh ? t.material = i[2] : t.isInstancedMesh ? t.material = i[1] : t.material = i[0], ++this.meshCount; } }; } /** * Clones the given material. * * @private * @param {Material} material - The material. * @return {Material} The cloned material. */ cloneMaterial(e) { if (!(e instanceof w)) return e.clone(); const t = e.uniforms, i = /* @__PURE__ */ new Map(); for (const a in t) { const n = t[a].value; n.isRenderTargetTexture && (t[a].value = null, i.set(a, n)); } const r = e.clone(); for (const a of i) t[a[0]].value = a[1], r.uniforms[a[0]].value = a[1]; return r; } /** * Sets the override material. * * @param {Material} material - The material. */ setMaterial(e) { if (this.disposeMaterials(), this.material = e, e !== null) { const t = this.materials = [ this.cloneMaterial(e), this.cloneMaterial(e), this.cloneMaterial(e) ]; for (const i of t) i.uniforms = Object.assign({}, e.uniforms), i.side = Ki; t[2].skinning = !0, this.materialsBackSide = t.map((i) => { const r = this.cloneMaterial(i); return r.uniforms = Object.assign({}, e.uniforms), r.side = ke, r; }), this.materialsDoubleSide = t.map((i) => { const r = this.cloneMaterial(i); return r.uniforms = Object.assign({}, e.uniforms), r.side = Qe, r; }), this.materialsFlatShaded = t.map((i) => { const r = this.cloneMaterial(i); return r.uniforms = Object.assign({}, e.uniforms), r.flatShading = !0, r; }), this.materialsFlatShadedBackSide = t.map((i) => { const r = this.cloneMaterial(i); return r.uniforms = Object.assign({}, e.uniforms), r.flatShading = !0, r.side = ke, r; }), this.materialsFlatShadedDoubleSide = t.map((i) => { const r = this.cloneMaterial(i); return r.uniforms = Object.assign({}, e.uniforms), r.flatShading = !0, r.side = Qe, r; }); } } /** * Renders the scene with the override material. * * @private * @param {WebGLRenderer} renderer - The renderer. * @param {Scene} scene - A scene. * @param {Camera} camera - A camera. */ render(e, t, i) { const r = e.shadowMap.enabled; if (e.shadowMap.enabled = !1, ot) { const a = this.originalMaterials; this.meshCount = 0, t.traverse(this.replaceMaterial), e.render(t, i); for (const n of a) n[0].material = n[1]; this.meshCount !== a.size && a.clear(); } else { const a = t.overrideMaterial; t.overrideMaterial = this.material, e.render(t, i), t.overrideMaterial = a; } e.shadowMap.enabled = r; } /** * Deletes cloned override materials. * * @private */ disposeMaterials() { if (this.material !== null) { const e = this.materials.concat(this.materialsBackSide).concat(this.materialsDoubleSide).concat(this.materialsFlatShaded).concat(this.materialsFlatShadedBackSide).concat(this.materialsFlatShadedDoubleSide); for (const t of e) t.dispose(); } } /** * Performs cleanup tasks. */ dispose() { this.originalMaterials.clear(), this.disposeMaterials(); } /** * Indicates whether the override material workaround is enabled. * * @type {Boolean} */ static get workaroundEnabled() { return ot; } /** * Enables or disables the override material workaround globally. * * This only affects post processing passes and effects. * * @type {Boolean} */ static set workaroundEnabled(e) { ot = e; } }, hr = class { /** * Sets the size of this object. * * @param {Number} width - The width. * @param {Number} height - The height. */ setSize(e, t) { } }, oe = -1, x = class extends Tt { /** * Constructs a new resolution. * * TODO Remove resizable param. * @param {Resizable} resizable - A resizable object. * @param {Number} [width=Resolution.AUTO_SIZE] - The preferred width. * @param {Number} [height=Resolution.AUTO_SIZE] - The preferred height. * @param {Number} [scale=1.0] - A resolution scale. */ constructor(e, t = oe, i = oe, r = 1) { super(), this.resizable = e, this.baseSize = new p(1, 1), this.preferredSize = new p(t, i), this.target = this.preferredSize, this.s = r, this.effectiveSize = new p(), this.addEventListener("change", () => this.updateEffectiveSize()), this.updateEffectiveSize(); } /** * Calculates the effective size. * * @private */ updateEffectiveSize() { const e = this.baseSize, t = this.preferredSize, i = this.effectiveSize, r = this.scale; t.width !== oe ? i.width = t.width : t.height !== oe ? i.width = Math.round(t.height * (e.width / Math.max(e.height, 1))) : i.width = Math.round(e.width * r), t.height !== oe ? i.height = t.height : t.width !== oe ? i.height = Math.round(t.width / Math.max(e.width / Math.max(e.height, 1), 1)) : i.height = Math.round(e.height * r); } /** * The effective width. * * If the preferred width and height are set to {@link Resizer.AUTO_SIZE}, the base width will be returned. * * @type {Number} */ get width() { return this.effectiveSize.width; } set width(e) { this.preferredWidth = e; } /** * The effective height. * * If the preferred width and height are set to {@link Resizer.AUTO_SIZE}, the base height will be returned. * * @type {Number} */ get height() { return this.effectiveSize.height; } set height(e) { this.preferredHeight = e; } /** * Returns the effective width. * * If the preferred width and height are set to {@link Resizer.AUTO_SIZE}, the base width will be returned. * * @deprecated Use width instead. * @return {Number} The effective width. */ getWidth() { return this.width; } /** * Returns the effective height. * * If the preferred width and height are set to {@link Resizer.AUTO_SIZE}, the base height will be returned. * * @deprecated Use height instead. * @return {Number} The effective height. */ getHeight() { return this.height; } /** * The resolution scale. * * @type {Number} */ get scale() { return this.s; } set scale(e) { this.s !== e && (this.s = e, this.preferredSize.setScalar(oe), this.dispatchEvent({ type: "change" }), this.resizable.setSize(this.baseSize.width, this.baseSize.height)); } /** * Returns the current resolution scale. * * @deprecated Use scale instead. * @return {Number} The scale. */ getScale() { return this.scale; } /** * Sets the resolution scale. * * Also sets the preferred resolution to {@link Resizer.AUTO_SIZE}. * * @deprecated Use scale instead. * @param {Number} value - The scale. */ setScale(e) { this.scale = e; } /** * The base width. * * @type {Number} */ get baseWidth() { return this.baseSize.width; } set baseWidth(e) { this.baseSize.width !== e && (this.baseSize.width = e, this.dispatchEvent({ type: "change" }), this.resizable.setSize(this.baseSize.width, this.baseSize.height)); } /** * Returns the base width. * * @deprecated Use baseWidth instead. * @return {Number} The base width. */ getBaseWidth() { return this.baseWidth; } /** * Sets the base width. * * @deprecated Use baseWidth instead. * @param {Number} value - The width. */ setBaseWidth(e) { this.baseWidth = e; } /** * The base height. * * @type {Number} */ get baseHeight() { return this.baseSize.height; } set baseHeight(e) { this.baseSize.height !== e && (this.baseSize.height = e, this.dispatchEvent({ type: "change" }), this.resizable.setSize(this.baseSize.width, this.baseSize.height)); } /** * Returns the base height. * * @deprecated Use baseHeight instead. * @return {Number} The base height. */ getBaseHeight() { return this.baseHeight; } /** * Sets the base height. * * @deprecated Use baseHeight instead. * @param {Number} value - The height. */ setBaseHeight(e) { this.baseHeight = e; } /** * Sets the base size. * * @param {Number} width - The width. * @param {Number} height - The height. */ setBaseSize(e, t) { (this.baseSize.width !== e || this.baseSize.height !== t) && (this.baseSize.set(e, t), this.dispatchEvent({ type: "change" }), this.resizable.setSize(this.baseSize.width, this.baseSize.height)); } /** * The preferred width. * * @type {Number} */ get preferredWidth() { return this.preferredSize.width; } set preferredWidth(e) { this.preferredSize.width !== e && (this.preferredSize.width = e, this.dispatchEvent({ type: "change" }), this.resizable.setSize(this.baseSize.width, this.baseSize.height)); } /** * Returns the preferred width. * * @deprecated Use preferredWidth instead. * @return {Number} The preferred width. */ getPreferredWidth() { return this.preferredWidth; } /** * Sets the preferred width. * * Use {@link Resizer.AUTO_SIZE} to automatically calculate the width based on the height and aspect ratio. * * @deprecated Use preferredWidth instead. * @param {Number} value - The width. */ setPreferredWidth(e) { this.preferredWidth = e; } /** * The preferred height. * * @type {Number} */ get preferredHeight() { return this.preferredSize.height; } set preferredHeight(e) { this.preferredSize.height !== e && (this.preferredSize.height = e, this.dispatchEvent({ type: "change" }), this.resizable.setSize(this.baseSize.width, this.baseSize.height)); } /** * Returns the preferred height. * * @deprecated Use preferredHeight instead. * @return {Number} The preferred height. */ getPreferredHeight() { return this.preferredHeight; } /** * Sets the preferred height. * * Use {@link Resizer.AUTO_SIZE} to automatically calculate the height based on the width and aspect ratio. * * @deprecated Use preferredHeight instead. * @param {Number} value - The height. */ setPreferredHeight(e) { this.preferredHeight = e; } /** * Sets the preferred size. * * @param {Number} width - The width. * @param {Number} height - The height. */ setPreferredSize(e, t) { (this.preferredSize.width !== e || this.preferredSize.height !== t) && (this.preferredSize.set(e, t), this.dispatchEvent({ type: "change" }), this.resizable.setSize(this.baseSize.width, this.baseSize.height)); } /** * Copies the given resolution. * * @param {Resolution} resolution - The resolution. */ copy(e) { this.s = e.scale, this.baseSize.set(e.baseWidth, e.baseHeight), this.preferredSize.set(e.preferredWidth, e.preferredHeight), this.dispatchEvent({ type: "change" }), this.resizable.setSize(this.baseSize.width, this.baseSize.height); } /** * An auto sizing constant. * * Can be used to automatically calculate the width or height based on the original aspect ratio. * * @type {Number} */ static get AUTO_SIZE() { return oe; } }, dr = class { /** * Constructs a new ID manager. * * @param initialId - The first ID. */ constructor(e = 0) { this.nextId = e; } /** * Returns the next unique ID. * * @return The ID. */ getNextId() { return this.nextId++; } /** * Resets the ID counter. * * @param initialId - The first ID. * @return This manager. */ reset(e = 0) { return this.nextId = e, this; } }, lt = /* @__PURE__ */ new dr(2), Et = class extends Set { /** * Constructs a new selection. * * @param {Iterable<Object3D>} [iterable] - A collection of objects that should be added to this selection. * @param {Number} [layer] - A dedicated render layer for selected objects. Range is `[2, 31]`. Starts at 2 if omitted. */ constructor(e, t = lt.getNextId()) { super(), this.exclusive = !1, this._layer = t, (this._layer < 1 || this._layer > 31) && (console.warn("Layer out of range, resetting to 2"), lt.reset(2), this._layer = lt.getNextId()), e !== void 0 && this.set(e); } /** * The render layer for selected objects. * * @type {Number} */ get layer() { return this._layer; } set layer(e) { const t = this._layer; for (const i of this) i.layers.disable(t), i.layers.enable(e); this._layer = e; } /** * Returns the current render layer for selected objects. * * The default layer is 2. If this collides with your own custom layers, please change it before rendering! * * @deprecated Use layer instead. * @return {Number} The layer. */ getLayer() { return this.layer; } /** * Sets the render layer for selected objects. * * The current selection will be updated accordingly. * * @deprecated Use layer instead. * @param {Number} value - The layer. Range is [0, 31]. */ setLayer(e) { this.layer = e; } /** * Indicates whether objects that are added to this selection will be removed from all other layers. * * @deprecated Use exclusive instead. * @return {Number} Whether this selection is exclusive. Default is false. */ isExclusive() { return this.exclusive; } /** * Controls whether objects that are added to this selection should be removed from all other layers. * * @deprecated Use exclusive instead. * @param {Number} value - Whether this selection should be exclusive. */ setExclusive(e) { this.exclusive = e; } /** * Clears this selection. * * @return {Selection} This selection. */ clear() { const e = this.layer; for (const t of this) t.layers.disable(e); return super.clear(); } /** * Clears this selection and adds the given objects. * * @param {Iterable<Object3D>} objects - The objects that should be selected. * @return {Selection} This selection. */ set(e) { this.clear(); for (const t of e) this.add(t); return this; } /** * An alias for {@link has}. * * @param {Object3D} object - An object. * @return {Number} Returns 0 if the given object is currently selected, or -1 otherwise. * @deprecated Added for backward-compatibility. */ indexOf(e) { return this.has(e) ? 0 : -1; } /** * Adds an object to this selection. * * If {@link exclusive} is set to `true`, the object will also be removed from all other layers. * * @param {Object3D} object - The object that should be selected. * @return {Selection} This selection. */ add(e) { return this.exclusive ? e.layers.set(this.layer) : e.layers.enable(this.layer), super.add(e); } /** * Removes an object from this selection. * * @param {Object3D} object - The object that should be deselected. * @return {Boo