UNPKG

@google/model-viewer-effects

Version:

Easily add and combine post-processing effects with <model-viewer>!

1,320 lines (1,316 loc) 488 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('three')) : typeof define === 'function' && define.amd ? define(['exports', 'three'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ModelViewerEffects = {}, global.three)); })(this, (function (exports, three) { 'use strict'; /** * @license * Copyright 2019 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ const t$1 = globalThis, e$2 = t$1.ShadowRoot && (void 0 === t$1.ShadyCSS || t$1.ShadyCSS.nativeShadow) && "adoptedStyleSheets" in Document.prototype && "replace" in CSSStyleSheet.prototype, s$1 = Symbol(), o$3 = new WeakMap; let n$3 = class n { get styleSheet() { let t = this.o; const s = this.t; if (e$2 && void 0 === t) { const e = void 0 !== s && 1 === s.length; e && (t = o$3.get(s)), void 0 === t && ((this.o = t = new CSSStyleSheet).replaceSync(this.cssText), e && o$3.set(s, t)); } return t; } toString() { return this.cssText; } constructor(t, e, o){ if (this._$cssResult$ = true, o !== s$1) throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead."); this.cssText = t, this.t = e; } }; const r$4 = (t)=>new n$3("string" == typeof t ? t : t + "", void 0, s$1), S$1 = (s, o)=>{ if (e$2) s.adoptedStyleSheets = o.map((t)=>t instanceof CSSStyleSheet ? t : t.styleSheet); else for (const e of o){ const o = document.createElement("style"), n = t$1.litNonce; void 0 !== n && o.setAttribute("nonce", n), o.textContent = e.cssText, s.appendChild(o); } }, c$2 = e$2 ? (t)=>t : (t)=>t instanceof CSSStyleSheet ? ((t)=>{ let e = ""; for (const s of t.cssRules)e += s.cssText; return r$4(e); })(t) : t; var _Symbol, _a$1, _a1; /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ const { is: i$2, defineProperty: e$1, getOwnPropertyDescriptor: r$3, getOwnPropertyNames: h$1, getOwnPropertySymbols: o$2, getPrototypeOf: n$2 } = Object, a$1 = globalThis, c$1 = a$1.trustedTypes, l$1 = c$1 ? c$1.emptyScript : "", p$1 = a$1.reactiveElementPolyfillSupport, d$1 = (t, s)=>t, u$1 = { toAttribute (t, s) { switch(s){ case Boolean: t = t ? l$1 : null; break; case Object: case Array: t = null == t ? t : JSON.stringify(t); } return t; }, fromAttribute (t, s) { let i = t; switch(s){ case Boolean: i = null !== t; break; case Number: i = null === t ? null : Number(t); break; case Object: case Array: try { i = JSON.parse(t); } catch (t) { i = null; } } return i; } }, f$1 = (t, s)=>!i$2(t, s), y = { attribute: true, type: String, converter: u$1, reflect: false, hasChanged: f$1 }; (_Symbol = Symbol).metadata ?? (_Symbol.metadata = Symbol("metadata")), (_a$1 = a$1).litPropertyMetadata ?? (_a$1.litPropertyMetadata = new WeakMap); class b extends HTMLElement { static addInitializer(t) { this._$Ei(), (this.l ?? (this.l = [])).push(t); } static get observedAttributes() { return this.finalize(), this._$Eh && [ ...this._$Eh.keys() ]; } static createProperty(t, s = y) { if (s.state && (s.attribute = false), this._$Ei(), this.elementProperties.set(t, s), !s.noAccessor) { const i = Symbol(), r = this.getPropertyDescriptor(t, i, s); void 0 !== r && e$1(this.prototype, t, r); } } static getPropertyDescriptor(t, s, i) { const { get: e, set: h } = r$3(this.prototype, t) ?? { get () { return this[s]; }, set (t) { this[s] = t; } }; return { get () { return e?.call(this); }, set (s) { const r = e?.call(this); h.call(this, s), this.requestUpdate(t, r, i); }, configurable: true, enumerable: true }; } static getPropertyOptions(t) { return this.elementProperties.get(t) ?? y; } static _$Ei() { if (this.hasOwnProperty(d$1("elementProperties"))) return; const t = n$2(this); t.finalize(), void 0 !== t.l && (this.l = [ ...t.l ]), this.elementProperties = new Map(t.elementProperties); } static finalize() { if (this.hasOwnProperty(d$1("finalized"))) return; if (this.finalized = true, this._$Ei(), this.hasOwnProperty(d$1("properties"))) { const t = this.properties, s = [ ...h$1(t), ...o$2(t) ]; for (const i of s)this.createProperty(i, t[i]); } const t = this[Symbol.metadata]; if (null !== t) { const s = litPropertyMetadata.get(t); if (void 0 !== s) for (const [t, i] of s)this.elementProperties.set(t, i); } this._$Eh = new Map; for (const [t, s] of this.elementProperties){ const i = this._$Eu(t, s); void 0 !== i && this._$Eh.set(i, t); } this.elementStyles = this.finalizeStyles(this.styles); } static finalizeStyles(s) { const i = []; if (Array.isArray(s)) { const e = new Set(s.flat(1 / 0).reverse()); for (const s of e)i.unshift(c$2(s)); } else void 0 !== s && i.push(c$2(s)); return i; } static _$Eu(t, s) { const i = s.attribute; return false === i ? void 0 : "string" == typeof i ? i : "string" == typeof t ? t.toLowerCase() : void 0; } _$Ev() { this._$ES = new Promise((t)=>this.enableUpdating = t), this._$AL = new Map, this._$E_(), this.requestUpdate(), this.constructor.l?.forEach((t)=>t(this)); } addController(t) { (this._$EO ?? (this._$EO = new Set)).add(t), void 0 !== this.renderRoot && this.isConnected && t.hostConnected?.(); } removeController(t) { this._$EO?.delete(t); } _$E_() { const t = new Map, s = this.constructor.elementProperties; for (const i of s.keys())this.hasOwnProperty(i) && (t.set(i, this[i]), delete this[i]); t.size > 0 && (this._$Ep = t); } createRenderRoot() { const t = this.shadowRoot ?? this.attachShadow(this.constructor.shadowRootOptions); return S$1(t, this.constructor.elementStyles), t; } connectedCallback() { this.renderRoot ?? (this.renderRoot = this.createRenderRoot()), this.enableUpdating(true), this._$EO?.forEach((t)=>t.hostConnected?.()); } enableUpdating(t) {} disconnectedCallback() { this._$EO?.forEach((t)=>t.hostDisconnected?.()); } attributeChangedCallback(t, s, i) { this._$AK(t, i); } _$EC(t, s) { const i = this.constructor.elementProperties.get(t), e = this.constructor._$Eu(t, i); if (void 0 !== e && true === i.reflect) { const r = (void 0 !== i.converter?.toAttribute ? i.converter : u$1).toAttribute(s, i.type); this._$Em = t, null == r ? this.removeAttribute(e) : this.setAttribute(e, r), this._$Em = null; } } _$AK(t, s) { const i = this.constructor, e = i._$Eh.get(t); if (void 0 !== e && this._$Em !== e) { const t = i.getPropertyOptions(e), r = "function" == typeof t.converter ? { fromAttribute: t.converter } : void 0 !== t.converter?.fromAttribute ? t.converter : u$1; this._$Em = e, this[e] = r.fromAttribute(s, t.type), this._$Em = null; } } requestUpdate(t, s, i) { if (void 0 !== t) { if (i ?? (i = this.constructor.getPropertyOptions(t)), !(i.hasChanged ?? f$1)(this[t], s)) return; this.P(t, s, i); } false === this.isUpdatePending && (this._$ES = this._$ET()); } P(t, s, i) { this._$AL.has(t) || this._$AL.set(t, s), true === i.reflect && this._$Em !== t && (this._$Ej ?? (this._$Ej = new Set)).add(t); } async _$ET() { this.isUpdatePending = true; try { await this._$ES; } catch (t) { Promise.reject(t); } const t = this.scheduleUpdate(); return null != t && await t, !this.isUpdatePending; } scheduleUpdate() { return this.performUpdate(); } performUpdate() { if (!this.isUpdatePending) return; if (!this.hasUpdated) { if (this.renderRoot ?? (this.renderRoot = this.createRenderRoot()), this._$Ep) { for (const [t, s] of this._$Ep)this[t] = s; this._$Ep = void 0; } const t = this.constructor.elementProperties; if (t.size > 0) for (const [s, i] of t) true !== i.wrapped || this._$AL.has(s) || void 0 === this[s] || this.P(s, this[s], i); } let t = false; const s = this._$AL; try { t = this.shouldUpdate(s), t ? (this.willUpdate(s), this._$EO?.forEach((t)=>t.hostUpdate?.()), this.update(s)) : this._$EU(); } catch (s) { throw t = false, this._$EU(), s; } t && this._$AE(s); } willUpdate(t) {} _$AE(t) { this._$EO?.forEach((t)=>t.hostUpdated?.()), this.hasUpdated || (this.hasUpdated = true, this.firstUpdated(t)), this.updated(t); } _$EU() { this._$AL = new Map, this.isUpdatePending = false; } get updateComplete() { return this.getUpdateComplete(); } getUpdateComplete() { return this._$ES; } shouldUpdate(t) { return true; } update(t) { this._$Ej && (this._$Ej = this._$Ej.forEach((t)=>this._$EC(t, this[t]))), this._$EU(); } updated(t) {} firstUpdated(t) {} constructor(){ super(), this._$Ep = void 0, this.isUpdatePending = false, this.hasUpdated = false, this._$Em = null, this._$Ev(); } } b.elementStyles = [], b.shadowRootOptions = { mode: "open" }, b[d$1("elementProperties")] = new Map, b[d$1("finalized")] = new Map, p$1?.({ ReactiveElement: b }), ((_a1 = a$1).reactiveElementVersions ?? (_a1.reactiveElementVersions = [])).push("2.0.4"); /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ const o$1 = { attribute: true, type: String, converter: u$1, reflect: false, hasChanged: f$1 }, r$2 = (t = o$1, e, r)=>{ const { kind: n, metadata: i } = r; let s = globalThis.litPropertyMetadata.get(i); if (void 0 === s && globalThis.litPropertyMetadata.set(i, s = new Map), s.set(r.name, t), "accessor" === n) { const { name: o } = r; return { set (r) { const n = e.get.call(this); e.set.call(this, r), this.requestUpdate(o, n, t); }, init (e) { return void 0 !== e && this.P(o, void 0, t), e; } }; } if ("setter" === n) { const { name: o } = r; return function(r) { const n = this[o]; e.call(this, r), this.requestUpdate(o, n, t); }; } throw Error("Unsupported decorator location: " + n); }; function n$1(t) { return (e, o)=>"object" == typeof o ? r$2(t, e, o) : ((t, e, o)=>{ const r = e.hasOwnProperty(o); return e.constructor.createProperty(o, r ? { ...t, wrapped: true } : t), r ? Object.getOwnPropertyDescriptor(e, o) : void 0; })(t, e, o); } /** * postprocessing v6.37.2 build Fri Mar 28 2025 * https://github.com/pmndrs/postprocessing * Copyright 2015-2025 Raoul van Rüschen * @license Zlib */ // package.json // src/core/Timer.js var MILLISECONDS_TO_SECONDS = 1 / 1e3; var SECONDS_TO_MILLISECONDS = 1e3; var Timer = class { /** * 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(value) { if (typeof document !== "undefined" && document.hidden !== void 0) { if (value) { document.addEventListener("visibilitychange", this); } else { document.removeEventListener("visibilitychange", this); } this._autoReset = value; } } get delta() { return this._delta * MILLISECONDS_TO_SECONDS; } get fixedDelta() { return this._fixedDelta * MILLISECONDS_TO_SECONDS; } set fixedDelta(value) { this._fixedDelta = value * SECONDS_TO_MILLISECONDS; } get elapsed() { return this._elapsed * MILLISECONDS_TO_SECONDS; } /** * Updates this timer. * * @param {Boolean} [timestamp] - The current time in milliseconds. */ update(timestamp) { if (this.useFixedDelta) { this._delta = this.fixedDelta; } else { this.previousTime = this.currentTime; this.currentTime = (timestamp !== void 0 ? timestamp : 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) { if (!document.hidden) { this.currentTime = performance.now() - this.startTime; } } dispose() { this.autoReset = false; } /** * 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 = false; this._autoReset = false; } }; var fullscreenGeometry = /* @__PURE__ */ (()=>{ const vertices = new Float32Array([ -1, -1, 0, 3, -1, 0, -1, 3, 0 ]); const uvs = new Float32Array([ 0, 0, 2, 0, 0, 2 ]); const geometry = new three.BufferGeometry(); geometry.setAttribute("position", new three.BufferAttribute(vertices, 3)); geometry.setAttribute("uv", new three.BufferAttribute(uvs, 2)); return geometry; })(); var Pass = class _Pass { /** * 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 fullscreenGeometry; } /** * 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(value) { if (this.rtt === value) { const material = this.fullscreenMaterial; if (material !== null) { material.needsUpdate = true; } this.rtt = !value; } } /** * Sets the main scene. * * @type {Scene} */ set mainScene(value) {} /** * Sets the main camera. * * @type {Camera} */ set mainCamera(value) {} /** * Sets the renderer * * @deprecated * @param {WebGLRenderer} renderer - The renderer. */ setRenderer(renderer) { this.renderer = renderer; } /** * 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(value) { this.enabled = value; } /** * The fullscreen material. * * @type {Material} */ get fullscreenMaterial() { return this.screen !== null ? this.screen.material : null; } set fullscreenMaterial(value) { let screen = this.screen; if (screen !== null) { screen.material = value; } else { screen = new three.Mesh(_Pass.fullscreenGeometry, value); screen.frustumCulled = false; if (this.scene === null) { this.scene = new three.Scene(); } this.scene.add(screen); this.screen = screen; } } /** * 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(value) { this.fullscreenMaterial = value; } /** * 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(depthTexture, depthPacking = three.BasicDepthPacking) {} /** * 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(renderer, inputBuffer, outputBuffer, deltaTime, stencilTest) { 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(width, height) {} /** * 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(renderer, alpha, frameBufferType) {} /** * 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 key of Object.keys(this)){ const property = this[key]; const isDisposable = property instanceof three.WebGLRenderTarget || property instanceof three.Material || property instanceof three.Texture || property instanceof _Pass; if (isDisposable) { this[key].dispose(); } } if (this.fullscreenMaterial !== null) { this.fullscreenMaterial.dispose(); } } /** * 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(name = "Pass", scene = new three.Scene(), camera = new three.Camera()){ this.name = name; this.renderer = null; this.scene = scene; this.camera = camera; this.screen = null; this.rtt = true; this.needsSwap = true; this.needsDepthTexture = false; this.enabled = true; } }; // src/passes/ClearMaskPass.js var ClearMaskPass = class extends Pass { /** * 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(renderer, inputBuffer, outputBuffer, deltaTime, stencilTest) { const stencil = renderer.state.buffers.stencil; stencil.setLocked(false); stencil.setTest(false); } /** * Constructs a new clear mask pass. */ constructor(){ super("ClearMaskPass", null, null); this.needsSwap = false; } }; // src/materials/glsl/copy.frag var copy_default = `#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> }`; // src/materials/glsl/common.vert var common_default = `varying vec2 vUv;void main(){vUv=position.xy*0.5+0.5;gl_Position=vec4(position.xy,1.0,1.0);}`; // src/materials/CopyMaterial.js var CopyMaterial = class extends three.ShaderMaterial { /** * The input buffer. * * @type {Texture} */ set inputBuffer(value) { this.uniforms.inputBuffer.value = value; } /** * Sets the input buffer. * * @deprecated Use inputBuffer instead. * @param {Number} value - The buffer. */ setInputBuffer(value) { this.uniforms.inputBuffer.value = value; } /** * Returns the opacity. * * @deprecated Use opacity instead. * @return {Number} The opacity. */ getOpacity(value) { return this.uniforms.opacity.value; } /** * Sets the opacity. * * @deprecated Use opacity instead. * @param {Number} value - The opacity. */ setOpacity(value) { this.uniforms.opacity.value = value; } /** * Constructs a new copy material. */ constructor(){ super({ name: "CopyMaterial", uniforms: { inputBuffer: new three.Uniform(null), opacity: new three.Uniform(1) }, blending: three.NoBlending, toneMapped: false, depthWrite: false, depthTest: false, fragmentShader: copy_default, vertexShader: common_default }); } }; // src/passes/CopyPass.js var CopyPass = class extends Pass { /** * Enables or disables auto resizing of the render target. * * @deprecated Use autoResize instead. * @type {Boolean} */ get resize() { return this.autoResize; } set resize(value) { this.autoResize = value; } /** * 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(value) { this.autoResize = value; } /** * 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(renderer, inputBuffer, outputBuffer, deltaTime, stencilTest) { this.fullscreenMaterial.inputBuffer = inputBuffer.texture; renderer.setRenderTarget(this.renderToScreen ? null : this.renderTarget); renderer.render(this.scene, this.camera); } /** * Updates the size of this pass. * * @param {Number} width - The width. * @param {Number} height - The height. */ setSize(width, height) { if (this.autoResize) { this.renderTarget.setSize(width, height); } } /** * 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(renderer, alpha, frameBufferType) { if (frameBufferType !== void 0) { this.renderTarget.texture.type = frameBufferType; if (frameBufferType !== three.UnsignedByteType) { this.fullscreenMaterial.defines.FRAMEBUFFER_PRECISION_HIGH = "1"; } else if (renderer !== null && renderer.outputColorSpace === three.SRGBColorSpace) { this.renderTarget.texture.colorSpace = three.SRGBColorSpace; } } } /** * 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(renderTarget, autoResize = true){ super("CopyPass"); this.fullscreenMaterial = new CopyMaterial(); this.needsSwap = false; this.renderTarget = renderTarget; if (renderTarget === void 0) { this.renderTarget = new three.WebGLRenderTarget(1, 1, { minFilter: three.LinearFilter, magFilter: three.LinearFilter, stencilBuffer: false, depthBuffer: false }); this.renderTarget.texture.name = "CopyPass.Target"; } this.autoResize = autoResize; } }; var color = /* @__PURE__ */ new three.Color(); var ClearPass = class extends Pass { /** * 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(color2, depth, stencil) { this.color = color2; this.depth = depth; this.stencil = stencil; } /** * 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(value) { this.overrideClearColor = value; } /** * 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(value) { this.overrideClearAlpha = value; } /** * 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(renderer, inputBuffer, outputBuffer, deltaTime, stencilTest) { const overrideClearColor = this.overrideClearColor; const overrideClearAlpha = this.overrideClearAlpha; const clearAlpha = renderer.getClearAlpha(); const hasOverrideClearColor = overrideClearColor !== null; const hasOverrideClearAlpha = overrideClearAlpha >= 0; if (hasOverrideClearColor) { renderer.getClearColor(color); renderer.setClearColor(overrideClearColor, hasOverrideClearAlpha ? overrideClearAlpha : clearAlpha); } else if (hasOverrideClearAlpha) { renderer.setClearAlpha(overrideClearAlpha); } renderer.setRenderTarget(this.renderToScreen ? null : inputBuffer); renderer.clear(this.color, this.depth, this.stencil); if (hasOverrideClearColor) { renderer.setClearColor(color, clearAlpha); } else if (hasOverrideClearAlpha) { renderer.setClearAlpha(clearAlpha); } } /** * 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(color2 = true, depth = true, stencil = false){ super("ClearPass", null, null); this.needsSwap = false; this.color = color2; this.depth = depth; this.stencil = stencil; this.overrideClearColor = null; this.overrideClearAlpha = -1; } }; // src/passes/MaskPass.js var MaskPass = class extends Pass { set mainScene(value) { this.scene = value; } set mainCamera(value) { this.camera = value; } /** * Indicates whether the mask should be inverted. * * @type {Boolean} */ get inverted() { return this.inverse; } set inverted(value) { this.inverse = value; } /** * Indicates whether this pass should clear the stencil buffer. * * @type {Boolean} * @deprecated Use clearPass.enabled instead. */ get clear() { return this.clearPass.enabled; } set clear(value) { this.clearPass.enabled = value; } /** * 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(value) { this.inverted = value; } /** * 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(renderer, inputBuffer, outputBuffer, deltaTime, stencilTest) { const context = renderer.getContext(); const buffers = renderer.state.buffers; const scene = this.scene; const camera = this.camera; const clearPass = this.clearPass; const writeValue = this.inverted ? 0 : 1; const clearValue = 1 - writeValue; buffers.color.setMask(false); buffers.depth.setMask(false); buffers.color.setLocked(true); buffers.depth.setLocked(true); buffers.stencil.setTest(true); buffers.stencil.setOp(context.REPLACE, context.REPLACE, context.REPLACE); buffers.stencil.setFunc(context.ALWAYS, writeValue, 4294967295); buffers.stencil.setClear(clearValue); buffers.stencil.setLocked(true); if (this.clearPass.enabled) { if (this.renderToScreen) { clearPass.render(renderer, null); } else { clearPass.render(renderer, inputBuffer); clearPass.render(renderer, outputBuffer); } } if (this.renderToScreen) { renderer.setRenderTarget(null); renderer.render(scene, camera); } else { renderer.setRenderTarget(inputBuffer); renderer.render(scene, camera); renderer.setRenderTarget(outputBuffer); renderer.render(scene, camera); } buffers.color.setLocked(false); buffers.depth.setLocked(false); buffers.stencil.setLocked(false); buffers.stencil.setFunc(context.EQUAL, 1, 4294967295); buffers.stencil.setOp(context.KEEP, context.KEEP, context.KEEP); buffers.stencil.setLocked(true); } /** * Constructs a new mask pass. * * @param {Scene} scene - The scene to render. * @param {Camera} camera - The camera to use. */ constructor(scene, camera){ super("MaskPass", scene, camera); this.needsSwap = false; this.clearPass = new ClearPass(false, false, true); this.inverse = false; } }; // src/core/EffectComposer.js var EffectComposer$1 = class EffectComposer { /** * 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(value) { const buffer = this.inputBuffer; const multisampling = this.multisampling; if (multisampling > 0 && value > 0) { this.inputBuffer.samples = value; this.outputBuffer.samples = value; this.inputBuffer.dispose(); this.outputBuffer.dispose(); } else if (multisampling !== value) { this.inputBuffer.dispose(); this.outputBuffer.dispose(); this.inputBuffer = this.createBuffer(buffer.depthBuffer, buffer.stencilBuffer, buffer.texture.type, value); 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(renderer) { this.renderer = renderer; if (renderer !== null) { const size = renderer.getSize(new three.Vector2()); const alpha = renderer.getContext().getContextAttributes().alpha; const frameBufferType = this.inputBuffer.texture.type; if (frameBufferType === three.UnsignedByteType && renderer.outputColorSpace === three.SRGBColorSpace) { this.inputBuffer.texture.colorSpace = three.SRGBColorSpace; this.outputBuffer.texture.colorSpace = three.SRGBColorSpace; this.inputBuffer.dispose(); this.outputBuffer.dispose(); } renderer.autoClear = false; this.setSize(size.width, size.height); for (const pass of this.passes){ pass.initialize(renderer, alpha, frameBufferType); } } } /** * 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(renderer, updateDOM = true) { const oldRenderer = this.renderer; const parent = oldRenderer.domElement.parentNode; this.setRenderer(renderer); if (updateDOM && parent !== null) { parent.removeChild(oldRenderer.domElement); parent.appendChild(renderer.domElement); } return oldRenderer; } /** * 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 depthTexture = this.depthTexture = new three.DepthTexture(); this.inputBuffer.depthTexture = depthTexture; this.inputBuffer.dispose(); if (this.inputBuffer.stencilBuffer) { depthTexture.format = three.DepthStencilFormat; depthTexture.type = three.UnsignedInt248Type; } else { depthTexture.type = three.UnsignedIntType; } return depthTexture; } /** * 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 pass of this.passes){ pass.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(depthBuffer, stencilBuffer, type, multisampling) { const renderer = this.renderer; const size = renderer === null ? new three.Vector2() : renderer.getDrawingBufferSize(new three.Vector2()); const options = { minFilter: three.LinearFilter, magFilter: three.LinearFilter, stencilBuffer, depthBuffer, type }; const renderTarget = new three.WebGLRenderTarget(size.width, size.height, options); if (multisampling > 0) { renderTarget.ignoreDepthForMultisampleCopy = false; renderTarget.samples = multisampling; } if (type === three.UnsignedByteType && renderer !== null && renderer.outputColorSpace === three.SRGBColorSpace) { renderTarget.texture.colorSpace = three.SRGBColorSpace; } renderTarget.texture.name = "EffectComposer.Buffer"; renderTarget.texture.generateMipmaps = false; return renderTarget; } /** * Can be used to change the main scene for all registered passes and effects. * * @param {Scene} scene - The scene. */ setMainScene(scene) { for (const pass of this.passes){ pass.mainScene = scene; } } /** * Can be used to change the main camera for all registered passes and effects. * * @param {Camera} camera - The camera. */ setMainCamera(camera) { for (const pass of this.passes){ pass.mainCamera = camera; } } /** * 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(pass, index) { const passes = this.passes; const renderer = this.renderer; const drawingBufferSize = renderer.getDrawingBufferSize(new three.Vector2()); const alpha = renderer.getContext().getContextAttributes().alpha; const frameBufferType = this.inputBuffer.texture.type; pass.setRenderer(renderer); pass.setSize(drawingBufferSize.width, drawingBufferSize.height); pass.initialize(renderer, alpha, frameBufferType); if (this.autoRenderToScreen) { if (passes.length > 0) { passes[passes.length - 1].renderToScreen = false; } if (pass.renderToScreen) { this.autoRenderToScreen = false; } } if (index !== void 0) { passes.splice(index, 0, pass); } else { passes.push(pass); } if (this.autoRenderToScreen) { passes[passes.length - 1].renderToScreen = true; } if (pass.needsDepthTexture || this.depthTexture !== null) { if (this.depthTexture === null) { const depthTexture = this.createDepthTexture(); for (pass of passes){ pass.setDepthTexture(depthTexture); } } else { pass.setDepthTexture(this.depthTexture); } } } /** * Removes a pass. * * @param {Pass} pass - The pass. */ removePass(pass) { const passes = this.passes; const index = passes.indexOf(pass); const exists = index !== -1; const removed = exists && passes.splice(index, 1).length > 0; if (removed) { if (this.depthTexture !== null) { const reducer = (a, b)=>a || b.needsDepthTexture; const depthTextureRequired = passes.reduce(reducer, false); if (!depthTextureRequired) { if (pass.getDepthTexture() === this.depthTexture) { pass.setDepthTexture(null); } this.deleteDepthTexture(); } } if (this.autoRenderToScreen) { if (index === passes.length) { pass.renderToScreen = false; if (passes.length > 0) { passes[passes.length - 1].renderToScreen = true; } } } } } /** * Removes all passes. */ removeAllPasses() { const passes = this.passes; this.deleteDepthTexture(); if (passes.length > 0) { if (this.autoRenderToScreen) { passes[passes.length - 1].renderToScreen = false; } 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(deltaTime) { const renderer = this.renderer; const copyPass = this.copyPass; let inputBuffer = this.inputBuffer; let outputBuffer = this.outputBuffer; let stencilTest = false; let context, stencil, buffer; if (deltaTime === void 0) { this.timer.update(); deltaTime = this.timer.getDelta(); } for (const pass of this.passes){ if (pass.enabled) { pass.render(renderer, inputBuffer, outputBuffer, deltaTime, stencilTest); if (pass.needsSwap) { if (stencilTest) { copyPass.renderToScreen = pass.renderToScreen; context = renderer.getContext(); stencil = renderer.state.buffers.stencil; stencil.setFunc(context.NOTEQUAL, 1, 4294967295); copyPass.render(renderer, inputBuffer, outputBuffer, deltaTime, stencilTest); stencil.setFunc(context.EQUAL, 1, 4294967295); } buffer = inputBuffer; inputBuffer = outputBuffer; outputBuffer = buffer; } if (pass instanceof MaskPass) { stencilTest = true; } else if (pass instanceof ClearMaskPass) { stencilTest = false; } } } } /** * 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(width, height, updateStyle) { con