UNPKG

@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.

5,162 lines 215 kB
import { h as RenderTargetTexture, C as Constants, T as Texture, P as PostProcess, O as Observable, M as Matrix, i as Vector4, L as Logger, a as EffectRenderer, E as EffectWrapper, j as Color4, k as Engine, V as Vector3, S as ShaderStore, l as MaterialFlags, m as VertexBuffer, n as PrepareDefinesAndAttributesForMorphTargets, o as PushAttributesForInstances, p as PrepareStringDefinesForClipPlanes, q as BindSceneUniformBuffer, r as BindClipPlane, s as BindMorphTargetParameters, t as Material, A as AddClipPlaneUniforms, _ as _WarnImport, U as UniqueIdGenerator, b as Tools, u as __decorate, v as serialize, w as MaterialPluginBase, x as PBRBaseMaterial, y as MaterialDefines, z as expandToProperty, R as RegisterClass, D as Scene, F as SceneComponentConstants, G as EngineStore, Q as Quaternion } from './index-D8dpgsp6.esm.js';
import { ShaderMaterial } from './shaderMaterial-CIQQ8ruH.esm.js';
import './engine.multiRender-BedRhStz.esm.js';
import { P as ProceduralTexture } from './iblCdfGenerator-DMrEIzBO.esm.js';
import './bumpFragment-DxcEUwXQ.esm.js';
import './helperFunctions--IdAVuO_.esm.js';
import './sceneUboDeclaration-B4scSg5L.esm.js';
import './bumpVertex-uF9SoczK.esm.js';
import { R as RawTexture } from './rawTexture-CaxT6-BM.esm.js';
import { S as StandardMaterial } from './standardMaterial-x6uLYrgd.esm.js';
import './iblCdfGeneratorSceneComponent-BQctLKpx.esm.js';

/**
 * A multi render target, like a render target provides the ability to render to a texture.
 * Unlike the render target, it can render to several draw buffers (render textures) in one draw.
 * This is specially interesting in deferred rendering or for any effects requiring more than
 * just one color from a single pass.
 */
class MultiRenderTarget extends RenderTargetTexture {
    /**
     * Get if draw buffers (render textures) are currently supported by the used hardware and browser.
     */
    get isSupported() {
        return this._engine?.getCaps().drawBuffersExtension ?? false;
    }
    /**
     * Get the list of textures generated by the multi render target.
     */
    get textures() {
        return this._textures;
    }
    /**
     * Gets the number of textures in this MRT. This number can be different from `_textures.length` in case a depth texture is generated.
     */
    get count() {
        return this._count;
    }
    /**
     * Get the depth texture generated by the multi render target if options.generateDepthTexture has been set
     */
    get depthTexture() {
        return this._textures[this._textures.length - 1];
    }
    /**
     * Set the wrapping mode on U of all the textures we are rendering to.
     * Can be any of the Texture. (CLAMP_ADDRESSMODE, MIRROR_ADDRESSMODE or WRAP_ADDRESSMODE)
     */
    set wrapU(wrap) {
        if (this._textures) {
            for (let i = 0; i < this._textures.length; i++) {
                this._textures[i].wrapU = wrap;
            }
        }
    }
    /**
     * Set the wrapping mode on V of all the textures we are rendering to.
     * Can be any of the Texture. (CLAMP_ADDRESSMODE, MIRROR_ADDRESSMODE or WRAP_ADDRESSMODE)
     */
    set wrapV(wrap) {
        if (this._textures) {
            for (let i = 0; i < this._textures.length; i++) {
                this._textures[i].wrapV = wrap;
            }
        }
    }
    /**
     * Instantiate a new multi render target texture.
     * A multi render target, like a render target provides the ability to render to a texture.
     * Unlike the render target, it can render to several draw buffers (render textures) in one draw.
     * This is specially interesting in deferred rendering or for any effects requiring more than
     * just one color from a single pass.
     * @param name Define the name of the texture
     * @param size Define the size of the buffers to render to
     * @param count Define the number of target we are rendering into
     * @param scene Define the scene the texture belongs to
     * @param options Define the options used to create the multi render target
     * @param textureNames Define the names to set to the textures (if count \> 0 - optional)
     */
    constructor(name, size, count, scene, options, textureNames) {
        const generateMipMaps = options && options.generateMipMaps ? options.generateMipMaps : false;
        const generateDepthTexture = options && options.generateDepthTexture ? options.generateDepthTexture : false;
        const depthTextureFormat = options && options.depthTextureFormat ? options.depthTextureFormat : Constants.TEXTUREFORMAT_DEPTH16;
        const doNotChangeAspectRatio = !options || options.doNotChangeAspectRatio === undefined ? true : options.doNotChangeAspectRatio;
        const drawOnlyOnFirstAttachmentByDefault = options && options.drawOnlyOnFirstAttachmentByDefault ? options.drawOnlyOnFirstAttachmentByDefault : false;
        super(name, size, scene, generateMipMaps, doNotChangeAspectRatio, undefined, undefined, undefined, undefined, undefined, undefined, undefined, true);
        if (!this.isSupported) {
            this.dispose();
            return;
        }
        this._textureNames = textureNames;
        const types = [];
        const samplingModes = [];
        const useSRGBBuffers = [];
        const formats = [];
        const targetTypes = [];
        const faceIndex = [];
        const layerIndex = [];
        const layerCounts = [];
        this._initTypes(count, types, samplingModes, useSRGBBuffers, formats, targetTypes, faceIndex, layerIndex, layerCounts, options);
        const generateDepthBuffer = !options || options.generateDepthBuffer === undefined ? true : options.generateDepthBuffer;
        const generateStencilBuffer = !options || options.generateStencilBuffer === undefined ? false : options.generateStencilBuffer;
        const samples = options && options.samples ? options.samples : 1;
        this._multiRenderTargetOptions = {
            samplingModes: samplingModes,
            generateMipMaps: generateMipMaps,
            generateDepthBuffer: generateDepthBuffer,
            generateStencilBuffer: generateStencilBuffer,
            generateDepthTexture: generateDepthTexture,
            depthTextureFormat: depthTextureFormat,
            types: types,
            textureCount: count,
            useSRGBBuffers: useSRGBBuffers,
            samples,
            formats: formats,
            targetTypes: targetTypes,
            faceIndex: faceIndex,
            layerIndex: layerIndex,
            layerCounts: layerCounts,
            labels: textureNames,
            label: name,
        };
        this._count = count;
        this._drawOnlyOnFirstAttachmentByDefault = drawOnlyOnFirstAttachmentByDefault;
        if (count > 0) {
            this._createInternalTextures();
            this._createTextures(textureNames);
        }
    }
    _initTypes(count, types, samplingModes, useSRGBBuffers, formats, targets, faceIndex, layerIndex, layerCounts, options) {
        for (let i = 0; i < count; i++) {
            if (options && options.types && options.types[i] !== undefined) {
                types.push(options.types[i]);
            }
            else {
                types.push(options && options.defaultType ? options.defaultType : Constants.TEXTURETYPE_UNSIGNED_BYTE);
            }
            if (options && options.samplingModes && options.samplingModes[i] !== undefined) {
                samplingModes.push(options.samplingModes[i]);
            }
            else {
                samplingModes.push(Texture.BILINEAR_SAMPLINGMODE);
            }
            if (options && options.useSRGBBuffers && options.useSRGBBuffers[i] !== undefined) {
                useSRGBBuffers.push(options.useSRGBBuffers[i]);
            }
            else {
                useSRGBBuffers.push(false);
            }
            if (options && options.formats && options.formats[i] !== undefined) {
                formats.push(options.formats[i]);
            }
            else {
                formats.push(Constants.TEXTUREFORMAT_RGBA);
            }
            if (options && options.targetTypes && options.targetTypes[i] !== undefined) {
                targets.push(options.targetTypes[i]);
            }
            else {
                targets.push(Constants.TEXTURE_2D);
            }
            if (options && options.faceIndex && options.faceIndex[i] !== undefined) {
                faceIndex.push(options.faceIndex[i]);
            }
            else {
                faceIndex.push(0);
            }
            if (options && options.layerIndex && options.layerIndex[i] !== undefined) {
                layerIndex.push(options.layerIndex[i]);
            }
            else {
                layerIndex.push(0);
            }
            if (options && options.layerCounts && options.layerCounts[i] !== undefined) {
                layerCounts.push(options.layerCounts[i]);
            }
            else {
                layerCounts.push(1);
            }
        }
    }
    _createInternaTextureIndexMapping() {
        const mapMainInternalTexture2Index = {};
        const mapInternalTexture2MainIndex = [];
        if (!this._renderTarget) {
            return mapInternalTexture2MainIndex;
        }
        const internalTextures = this._renderTarget.textures;
        for (let i = 0; i < internalTextures.length; i++) {
            const texture = internalTextures[i];
            if (!texture) {
                continue;
            }
            const mainIndex = mapMainInternalTexture2Index[texture.uniqueId];
            if (mainIndex !== undefined) {
                mapInternalTexture2MainIndex[i] = mainIndex;
            }
            else {
                mapMainInternalTexture2Index[texture.uniqueId] = i;
            }
        }
        return mapInternalTexture2MainIndex;
    }
    /**
     * @internal
     */
    _rebuild(fromContextLost = false, forceFullRebuild = false, textureNames) {
        if (this._count < 1 || fromContextLost) {
            return;
        }
        const mapInternalTexture2MainIndex = this._createInternaTextureIndexMapping();
        this.releaseInternalTextures();
        this._createInternalTextures();
        if (forceFullRebuild) {
            this._releaseTextures();
            this._createTextures(textureNames);
        }
        const internalTextures = this._renderTarget.textures;
        for (let i = 0; i < internalTextures.length; i++) {
            const texture = this._textures[i];
            if (mapInternalTexture2MainIndex[i] !== undefined) {
                this._renderTarget.setTexture(internalTextures[mapInternalTexture2MainIndex[i]], i);
            }
            texture._texture = internalTextures[i];
            if (texture._texture) {
                texture._noMipmap = !texture._texture.useMipMaps;
                texture._useSRGBBuffer = texture._texture._useSRGBBuffer;
            }
        }
        if (this.samples !== 1) {
            this._renderTarget.setSamples(this.samples, !this._drawOnlyOnFirstAttachmentByDefault, true);
        }
    }
    _createInternalTextures() {
        this._renderTarget = this._getEngine().createMultipleRenderTarget(this._size, this._multiRenderTargetOptions, !this._drawOnlyOnFirstAttachmentByDefault);
        this._texture = this._renderTarget.texture;
    }
    _releaseTextures() {
        if (this._textures) {
            for (let i = 0; i < this._textures.length; i++) {
                this._textures[i]._texture = null; // internal textures are released by a call to releaseInternalTextures()
                this._textures[i].dispose();
            }
        }
    }
    _createTextures(textureNames) {
        const internalTextures = this._renderTarget.textures;
        this._textures = [];
        for (let i = 0; i < internalTextures.length; i++) {
            const texture = new Texture(null, this.getScene());
            if (textureNames?.[i]) {
                texture.name = textureNames[i];
            }
            texture._texture = internalTextures[i];
            if (texture._texture) {
                texture._noMipmap = !texture._texture.useMipMaps;
                texture._useSRGBBuffer = texture._texture._useSRGBBuffer;
            }
            this._textures.push(texture);
        }
    }
    /**
     * Replaces an internal texture within the MRT. Useful to share textures between MultiRenderTarget.
     * @param texture The new texture to set in the MRT
     * @param index The index of the texture to replace
     * @param disposePrevious Set to true if the previous internal texture should be disposed
     */
    setInternalTexture(texture, index, disposePrevious = true) {
        if (!this.renderTarget) {
            return;
        }
        if (index === 0) {
            this._texture = texture;
        }
        this.renderTarget.setTexture(texture, index, disposePrevious);
        if (!this.textures[index]) {
            this.textures[index] = new Texture(null, this.getScene());
            this.textures[index].name = this._textureNames?.[index] ?? this.textures[index].name;
        }
        this.textures[index]._texture = texture;
        this.textures[index]._noMipmap = !texture.useMipMaps;
        this.textures[index]._useSRGBBuffer = texture._useSRGBBuffer;
        this._count = this.renderTarget.textures ? this.renderTarget.textures.length : 0;
        if (this._multiRenderTargetOptions.types) {
            this._multiRenderTargetOptions.types[index] = texture.type;
        }
        if (this._multiRenderTargetOptions.samplingModes) {
            this._multiRenderTargetOptions.samplingModes[index] = texture.samplingMode;
        }
        if (this._multiRenderTargetOptions.useSRGBBuffers) {
            this._multiRenderTargetOptions.useSRGBBuffers[index] = texture._useSRGBBuffer;
        }
        if (this._multiRenderTargetOptions.targetTypes && this._multiRenderTargetOptions.targetTypes[index] !== -1) {
            let target = 0;
            if (texture.is2DArray) {
                target = Constants.TEXTURE_2D_ARRAY;
            }
            else if (texture.isCube) {
                target = Constants.TEXTURE_CUBE_MAP;
            } /*else if (texture.isCubeArray) {
                target = Constants.TEXTURE_CUBE_MAP_ARRAY;
            }*/
            else if (texture.is3D) {
                target = Constants.TEXTURE_3D;
            }
            else {
                target = Constants.TEXTURE_2D;
            }
            this._multiRenderTargetOptions.targetTypes[index] = target;
        }
    }
    /**
     * Changes an attached texture's face index or layer.
     * @param index The index of the texture to modify the attachment of
     * @param layerIndex The layer index of the texture to be attached to the framebuffer
     * @param faceIndex The face index of the texture to be attached to the framebuffer
     */
    setLayerAndFaceIndex(index, layerIndex = -1, faceIndex = -1) {
        if (!this.textures[index] || !this.renderTarget) {
            return;
        }
        if (this._multiRenderTargetOptions.layerIndex) {
            this._multiRenderTargetOptions.layerIndex[index] = layerIndex;
        }
        if (this._multiRenderTargetOptions.faceIndex) {
            this._multiRenderTargetOptions.faceIndex[index] = faceIndex;
        }
        this.renderTarget.setLayerAndFaceIndex(index, layerIndex, faceIndex);
    }
    /**
     * Changes every attached texture's face index or layer.
     * @param layerIndices The layer indices of the texture to be attached to the framebuffer
     * @param faceIndices The face indices of the texture to be attached to the framebuffer
     */
    setLayerAndFaceIndices(layerIndices, faceIndices) {
        if (!this.renderTarget) {
            return;
        }
        this._multiRenderTargetOptions.layerIndex = layerIndices;
        this._multiRenderTargetOptions.faceIndex = faceIndices;
        this.renderTarget.setLayerAndFaceIndices(layerIndices, faceIndices);
    }
    /**
     * Define the number of samples used if MSAA is enabled.
     */
    get samples() {
        return this._samples;
    }
    set samples(value) {
        if (this._renderTarget) {
            this._samples = this._renderTarget.setSamples(value);
        }
        else {
            // In case samples are set with 0 textures created, we must save the desired samples value
            this._samples = value;
        }
    }
    /**
     * Resize all the textures in the multi render target.
     * Be careful as it will recreate all the data in the new texture.
     * @param size Define the new size
     */
    resize(size) {
        this._processSizeParameter(size);
        this._rebuild(false, undefined, this._textureNames);
    }
    /**
     * Changes the number of render targets in this MRT
     * Be careful as it will recreate all the data in the new texture.
     * @param count new texture count
     * @param options Specifies texture types and sampling modes for new textures
     * @param textureNames Specifies the names of the textures (optional)
     */
    updateCount(count, options, textureNames) {
        this._multiRenderTargetOptions.textureCount = count;
        this._count = count;
        const types = [];
        const samplingModes = [];
        const useSRGBBuffers = [];
        const formats = [];
        const targetTypes = [];
        const faceIndex = [];
        const layerIndex = [];
        const layerCounts = [];
        this._textureNames = textureNames;
        this._initTypes(count, types, samplingModes, useSRGBBuffers, formats, targetTypes, faceIndex, layerIndex, layerCounts, options);
        this._multiRenderTargetOptions.types = types;
        this._multiRenderTargetOptions.samplingModes = samplingModes;
        this._multiRenderTargetOptions.useSRGBBuffers = useSRGBBuffers;
        this._multiRenderTargetOptions.formats = formats;
        this._multiRenderTargetOptions.targetTypes = targetTypes;
        this._multiRenderTargetOptions.faceIndex = faceIndex;
        this._multiRenderTargetOptions.layerIndex = layerIndex;
        this._multiRenderTargetOptions.layerCounts = layerCounts;
        this._multiRenderTargetOptions.labels = textureNames;
        this._rebuild(false, true, textureNames);
    }
    _unbindFrameBuffer(engine, faceIndex) {
        if (this._renderTarget) {
            engine.unBindMultiColorAttachmentFramebuffer(this._renderTarget, this.isCube, () => {
                this.onAfterRenderObservable.notifyObservers(faceIndex);
            });
        }
    }
    /**
     * Dispose the render targets and their associated resources
     * @param doNotDisposeInternalTextures if set to true, internal textures won't be disposed (default: false).
     */
    dispose(doNotDisposeInternalTextures = false) {
        this._releaseTextures();
        if (!doNotDisposeInternalTextures) {
            this.releaseInternalTextures();
        }
        else {
            // Prevent internal texture dispose in super.dispose
            this._texture = null;
        }
        super.dispose();
    }
    /**
     * Release all the underlying texture used as draw buffers (render textures).
     */
    releaseInternalTextures() {
        const internalTextures = this._renderTarget?.textures;
        if (!internalTextures) {
            return;
        }
        for (let i = internalTextures.length - 1; i >= 0; i--) {
            this._textures[i]._texture = null;
        }
        this._renderTarget?.dispose();
        this._renderTarget = null;
    }
}

/**
 * Voxel-based shadow rendering for IBL's.
 * This should not be instanciated directly, as it is part of a scene component
 * @internal
 * @see https://playground.babylonjs.com/#8R5SSE#222
 */
class _IblShadowsVoxelRenderer {
    /**
     * Return the voxel grid texture.
     * @returns The voxel grid texture.
     */
    getVoxelGrid() {
        if (this._triPlanarVoxelization) {
            return this._voxelGridRT;
        }
        else {
            return this._voxelGridZaxis;
        }
    }
    /**
     * The debug pass post process
     * @returns The debug pass post process
     */
    getDebugPassPP() {
        if (!this._voxelDebugPass) {
            this._createDebugPass();
        }
        return this._voxelDebugPass;
    }
    /**
     * Whether to use tri-planar voxelization. More expensive, but can help with artifacts.
     */
    get triPlanarVoxelization() {
        return this._triPlanarVoxelization;
    }
    /**
     * Whether to use tri-planar voxelization. More expensive, but can help with artifacts.
     */
    set triPlanarVoxelization(enabled) {
        if (this._triPlanarVoxelization === enabled) {
            return;
        }
        this._triPlanarVoxelization = enabled;
        this._disposeVoxelTextures();
        this._createTextures();
    }
    /**
     * Set the matrix to use for scaling the world space to voxel space
     * @param matrix The matrix to use for scaling the world space to voxel space
     */
    setWorldScaleMatrix(matrix) {
        this._invWorldScaleMatrix = matrix;
    }
    /**
     * @returns Whether voxelization is currently happening.
     */
    isVoxelizationInProgress() {
        return this._voxelizationInProgress;
    }
    /**
     * Resolution of the voxel grid. The final resolution will be 2^resolutionExp.
     */
    get voxelResolutionExp() {
        return this._voxelResolutionExp;
    }
    /**
     * Resolution of the voxel grid. The final resolution will be 2^resolutionExp.
     */
    set voxelResolutionExp(resolutionExp) {
        if (this._voxelResolutionExp === resolutionExp && this._voxelGridZaxis) {
            return;
        }
        this._voxelResolutionExp = Math.round(Math.min(Math.max(resolutionExp, 3), 9));
        this._voxelResolution = Math.pow(2.0, this._voxelResolutionExp);
        this._disposeVoxelTextures();
        this._createTextures();
    }
    /**
     * Shows only the voxels that were rendered along a particular axis (while using triPlanarVoxelization).
     * If not set, the combined voxel grid will be shown.
     * Note: This only works when the debugMipNumber is set to 0 because we don't generate mips for each axis.
     * @param axis The axis to show (0 = x, 1 = y, 2 = z)
     */
    set voxelDebugAxis(axis) {
        this._voxelDebugAxis = axis;
    }
    get voxelDebugAxis() {
        return this._voxelDebugAxis;
    }
    /**
     * Sets params that control the position and scaling of the debug display on the screen.
     * @param x Screen X offset of the debug display (0-1)
     * @param y Screen Y offset of the debug display (0-1)
     * @param widthScale X scale of the debug display (0-1)
     * @param heightScale Y scale of the debug display (0-1)
     */
    setDebugDisplayParams(x, y, widthScale, heightScale) {
        this._debugSizeParams.set(x, y, widthScale, heightScale);
    }
    /**
     * The mip level to show in the debug display
     * @param mipNum The mip level to show in the debug display
     */
    setDebugMipNumber(mipNum) {
        this._debugMipNumber = mipNum;
    }
    /**
     * Sets the name of the debug pass
     */
    get debugPassName() {
        return this._debugPassName;
    }
    /**
     * Enable or disable the debug view for this pass
     */
    get voxelDebugEnabled() {
        return this._voxelDebugEnabled;
    }
    set voxelDebugEnabled(enabled) {
        if (this._voxelDebugEnabled === enabled) {
            return;
        }
        this._voxelDebugEnabled = enabled;
        if (enabled) {
            this._voxelSlabDebugRT = new RenderTargetTexture("voxelSlabDebug", { width: this._engine.getRenderWidth(), height: this._engine.getRenderHeight() }, this._scene, {
                generateDepthBuffer: true,
                generateMipMaps: false,
                type: Constants.TEXTURETYPE_UNSIGNED_BYTE,
                format: Constants.TEXTUREFORMAT_RGBA,
                samplingMode: Constants.TEXTURE_NEAREST_SAMPLINGMODE,
            });
            this._voxelSlabDebugRT.noPrePassRenderer = true;
        }
        if (this._voxelSlabDebugRT) {
            this._removeVoxelRTs([this._voxelSlabDebugRT]);
        }
        // Add the slab debug RT if needed.
        if (this._voxelDebugEnabled) {
            this._addRTsForRender([this._voxelSlabDebugRT], this._includedMeshes, this._voxelDebugAxis, 1, true);
            this._setDebugBindingsBound = this._setDebugBindings.bind(this);
            this._scene.onBeforeRenderObservable.add(this._setDebugBindingsBound);
        }
        else {
            this._scene.onBeforeRenderObservable.removeCallback(this._setDebugBindingsBound);
        }
    }
    /**
     * Creates the debug post process effect for this pass
     */
    _createDebugPass() {
        const isWebGPU = this._engine.isWebGPU;
        if (!this._voxelDebugPass) {
            const debugOptions = {
                width: this._engine.getRenderWidth(),
                height: this._engine.getRenderHeight(),
                textureFormat: Constants.TEXTUREFORMAT_RGBA,
                textureType: Constants.TEXTURETYPE_UNSIGNED_BYTE,
                samplingMode: Constants.TEXTURE_NEAREST_SAMPLINGMODE,
                uniforms: ["sizeParams", "mipNumber"],
                samplers: ["voxelTexture", "voxelSlabTexture"],
                engine: this._engine,
                reusable: false,
                shaderLanguage: isWebGPU ? 1 /* ShaderLanguage.WGSL */ : 0 /* ShaderLanguage.GLSL */,
                extraInitializations: (useWebGPU, list) => {
                    if (this._isVoxelGrid3D) {
                        if (useWebGPU) {
                            list.push(import('./iblVoxelGrid3dDebug.fragment-R7XG8QvM.esm.js'));
                        }
                        else {
                            list.push(import('./iblVoxelGrid3dDebug.fragment-DxFThDbA.esm.js'));
                        }
                        return;
                    }
                    if (useWebGPU) {
                        list.push(import('./iblVoxelGrid2dArrayDebug.fragment-ZtkL0hBh.esm.js'));
                    }
                    else {
                        list.push(import('./iblVoxelGrid2dArrayDebug.fragment-D_caYvQD.esm.js'));
                    }
                },
            };
            this._voxelDebugPass = new PostProcess(this.debugPassName, this._isVoxelGrid3D ? "iblVoxelGrid3dDebug" : "iblVoxelGrid2dArrayDebug", debugOptions);
            this._voxelDebugPass.onApplyObservable.add((effect) => {
                if (this._voxelDebugAxis === 0) {
                    effect.setTexture("voxelTexture", this._voxelGridXaxis);
                }
                else if (this._voxelDebugAxis === 1) {
                    effect.setTexture("voxelTexture", this._voxelGridYaxis);
                }
                else if (this._voxelDebugAxis === 2) {
                    effect.setTexture("voxelTexture", this._voxelGridZaxis);
                }
                else {
                    effect.setTexture("voxelTexture", this.getVoxelGrid());
                }
                effect.setTexture("voxelSlabTexture", this._voxelSlabDebugRT);
                effect.setVector4("sizeParams", this._debugSizeParams);
                effect.setFloat("mipNumber", this._debugMipNumber);
            });
        }
    }
    /**
     * Instanciates the voxel renderer
     * @param scene Scene to attach to
     * @param iblShadowsRenderPipeline The render pipeline this pass is associated with
     * @param resolutionExp Resolution of the voxel grid. The final resolution will be 2^resolutionExp.
     * @param triPlanarVoxelization Whether to use tri-planar voxelization. More expensive, but can help with artifacts.
     * @returns The voxel renderer
     */
    constructor(scene, iblShadowsRenderPipeline, resolutionExp = 6, triPlanarVoxelization = true) {
        this._voxelMrtsXaxis = [];
        this._voxelMrtsYaxis = [];
        this._voxelMrtsZaxis = [];
        this._isVoxelGrid3D = true;
        /**
         * Observable that triggers when the voxelization is complete
         */
        this.onVoxelizationCompleteObservable = new Observable();
        this._renderTargets = [];
        this._triPlanarVoxelization = true;
        this._voxelizationInProgress = false;
        this._invWorldScaleMatrix = Matrix.Identity();
        this._voxelResolution = 64;
        this._voxelResolutionExp = 6;
        this._mipArray = [];
        this._voxelDebugEnabled = false;
        this._voxelDebugAxis = -1;
        this._debugSizeParams = new Vector4(0.0, 0.0, 0.0, 0.0);
        this._includedMeshes = [];
        this._debugMipNumber = 0;
        this._debugPassName = "Voxelization Debug Pass";
        this._scene = scene;
        this._engine = scene.getEngine();
        this._triPlanarVoxelization = triPlanarVoxelization;
        if (!this._engine.getCaps().drawBuffersExtension) {
            Logger.Error("Can't do voxel rendering without the draw buffers extension.");
        }
        const isWebGPU = this._engine.isWebGPU;
        this._maxDrawBuffers = this._engine.getCaps().maxDrawBuffers || 0;
        this._copyMipEffectRenderer = new EffectRenderer(this._engine);
        this._copyMipEffectWrapper = new EffectWrapper({
            engine: this._engine,
            fragmentShader: "copyTexture3DLayerToTexture",
            useShaderStore: true,
            uniformNames: ["layerNum"],
            samplerNames: ["textureSampler"],
            shaderLanguage: isWebGPU ? 1 /* ShaderLanguage.WGSL */ : 0 /* ShaderLanguage.GLSL */,
            extraInitializationsAsync: async () => {
                if (isWebGPU) {
                    await import('./copyTexture3DLayerToTexture.fragment-Bo1g4A7k.esm.js');
                }
                else {
                    await import('./copyTexture3DLayerToTexture.fragment-l3k-us16.esm.js');
                }
            },
        });
        this.voxelResolutionExp = resolutionExp;
    }
    _generateMipMaps() {
        const iterations = Math.ceil(Math.log2(this._voxelResolution));
        for (let i = 1; i < iterations + 1; i++) {
            this._generateMipMap(i);
        }
    }
    _generateMipMap(lodLevel) {
        // Generate a mip map for the given level by triggering the render of the procedural mip texture.
        const mipTarget = this._mipArray[lodLevel - 1];
        if (!mipTarget) {
            return;
        }
        mipTarget.setTexture("srcMip", lodLevel === 1 ? this.getVoxelGrid() : this._mipArray[lodLevel - 2]);
        mipTarget.render();
    }
    _copyMipMaps() {
        const iterations = Math.ceil(Math.log2(this._voxelResolution));
        for (let i = 1; i < iterations + 1; i++) {
            this._copyMipMap(i);
        }
    }
    _copyMipMap(lodLevel) {
        // Now, copy this mip into the mip chain of the voxel grid.
        // TODO - this currently isn't working. "textureSampler" isn't being properly set to mipTarget.
        const mipTarget = this._mipArray[lodLevel - 1];
        if (!mipTarget) {
            return;
        }
        const voxelGrid = this.getVoxelGrid();
        let rt;
        if (voxelGrid instanceof RenderTargetTexture && voxelGrid.renderTarget) {
            rt = voxelGrid.renderTarget;
        }
        else {
            rt = voxelGrid._rtWrapper;
        }
        if (rt) {
            this._copyMipEffectRenderer.saveStates();
            const bindSize = mipTarget.getSize().width;
            // Render to each layer of the voxel grid.
            for (let layer = 0; layer < bindSize; layer++) {
                this._engine.bindFramebuffer(rt, 0, bindSize, bindSize, true, lodLevel, layer);
                this._copyMipEffectRenderer.applyEffectWrapper(this._copyMipEffectWrapper);
                this._copyMipEffectWrapper.effect.setTexture("textureSampler", mipTarget);
                this._copyMipEffectWrapper.effect.setInt("layerNum", layer);
                this._copyMipEffectRenderer.draw();
                this._engine.unBindFramebuffer(rt, true);
            }
            this._copyMipEffectRenderer.restoreStates();
        }
    }
    _computeNumberOfSlabs() {
        return Math.ceil(this._voxelResolution / this._maxDrawBuffers);
    }
    _createTextures() {
        const isWebGPU = this._engine.isWebGPU;
        const size = {
            width: this._voxelResolution,
            height: this._voxelResolution,
            layers: this._isVoxelGrid3D ? undefined : this._voxelResolution,
            depth: this._isVoxelGrid3D ? this._voxelResolution : undefined,
        };
        const voxelAxisOptions = {
            generateDepthBuffer: false,
            generateMipMaps: false,
            type: Constants.TEXTURETYPE_UNSIGNED_BYTE,
            format: Constants.TEXTUREFORMAT_R,
            samplingMode: Constants.TEXTURE_NEAREST_SAMPLINGMODE,
        };
        // We can render up to maxDrawBuffers voxel slices of the grid per render.
        // We call this a slab.
        const numSlabs = this._computeNumberOfSlabs();
        const voxelCombinedOptions = {
            generateDepthBuffer: false,
            generateMipMaps: true,
            type: Constants.TEXTURETYPE_UNSIGNED_BYTE,
            format: Constants.TEXTUREFORMAT_R,
            samplingMode: Constants.TEXTURE_NEAREST_NEAREST_MIPNEAREST,
            shaderLanguage: isWebGPU ? 1 /* ShaderLanguage.WGSL */ : 0 /* ShaderLanguage.GLSL */,
            extraInitializationsAsync: async () => {
                if (isWebGPU) {
                    await import('./iblCombineVoxelGrids.fragment-Cjc42P8L.esm.js');
                }
                else {
                    await import('./iblCombineVoxelGrids.fragment-DHgt4SDo.esm.js');
                }
            },
        };
        if (this._triPlanarVoxelization) {
            this._voxelGridXaxis = new RenderTargetTexture("voxelGridXaxis", size, this._scene, voxelAxisOptions);
            this._voxelGridYaxis = new RenderTargetTexture("voxelGridYaxis", size, this._scene, voxelAxisOptions);
            this._voxelGridZaxis = new RenderTargetTexture("voxelGridZaxis", size, this._scene, voxelAxisOptions);
            this._voxelMrtsXaxis = this._createVoxelMRTs("x_axis_", this._voxelGridXaxis, numSlabs);
            this._voxelMrtsYaxis = this._createVoxelMRTs("y_axis_", this._voxelGridYaxis, numSlabs);
            this._voxelMrtsZaxis = this._createVoxelMRTs("z_axis_", this._voxelGridZaxis, numSlabs);
            this._voxelGridRT = new ProceduralTexture("combinedVoxelGrid", size, "iblCombineVoxelGrids", this._scene, voxelCombinedOptions, false);
            this._scene.proceduralTextures.splice(this._scene.proceduralTextures.indexOf(this._voxelGridRT), 1);
            this._voxelGridRT.setFloat("layer", 0.0);
            this._voxelGridRT.setTexture("voxelXaxisSampler", this._voxelGridXaxis);
            this._voxelGridRT.setTexture("voxelYaxisSampler", this._voxelGridYaxis);
            this._voxelGridRT.setTexture("voxelZaxisSampler", this._voxelGridZaxis);
            // We will render this only after voxelization is completed for the 3 axes.
            this._voxelGridRT.autoClear = false;
            this._voxelGridRT.wrapU = Texture.CLAMP_ADDRESSMODE;
            this._voxelGridRT.wrapV = Texture.CLAMP_ADDRESSMODE;
        }
        else {
            this._voxelGridZaxis = new RenderTargetTexture("voxelGridZaxis", size, this._scene, voxelCombinedOptions);
            this._voxelMrtsZaxis = this._createVoxelMRTs("z_axis_", this._voxelGridZaxis, numSlabs);
        }
        const generateVoxelMipOptions = {
            generateDepthBuffer: false,
            generateMipMaps: false,
            type: Constants.TEXTURETYPE_UNSIGNED_BYTE,
            format: Constants.TEXTUREFORMAT_R,
            samplingMode: Constants.TEXTURE_NEAREST_SAMPLINGMODE,
            shaderLanguage: isWebGPU ? 1 /* ShaderLanguage.WGSL */ : 0 /* ShaderLanguage.GLSL */,
            extraInitializationsAsync: async () => {
                if (isWebGPU) {
                    await import('./iblGenerateVoxelMip.fragment-D_a84S4y.esm.js');
                }
                else {
                    await import('./iblGenerateVoxelMip.fragment-BRWa9ilC.esm.js');
                }
            },
        };
        this._mipArray = new Array(Math.ceil(Math.log2(this._voxelResolution)));
        for (let mipIdx = 1; mipIdx <= this._mipArray.length; mipIdx++) {
            const mipDim = this._voxelResolution >> mipIdx;
            const mipSize = { width: mipDim, height: mipDim, depth: mipDim };
            this._mipArray[mipIdx - 1] = new ProceduralTexture("voxelMip" + mipIdx, mipSize, "iblGenerateVoxelMip", this._scene, generateVoxelMipOptions, false);
            this._scene.proceduralTextures.splice(this._scene.proceduralTextures.indexOf(this._mipArray[mipIdx - 1]), 1);
            const mipTarget = this._mipArray[mipIdx - 1];
            mipTarget.autoClear = false;
            mipTarget.wrapU = Texture.CLAMP_ADDRESSMODE;
            mipTarget.wrapV = Texture.CLAMP_ADDRESSMODE;
            mipTarget.setTexture("srcMip", mipIdx > 1 ? this._mipArray[mipIdx - 2] : this.getVoxelGrid());
            mipTarget.setInt("layerNum", 0);
        }
        this._createVoxelMaterials();
    }
    _createVoxelMRTs(name, voxelRT, numSlabs) {
        voxelRT.wrapU = Texture.CLAMP_ADDRESSMODE;
        voxelRT.wrapV = Texture.CLAMP_ADDRESSMODE;
        voxelRT.noPrePassRenderer = true;
        const mrtArray = [];
        const targetTypes = new Array(this._maxDrawBuffers).fill(this._isVoxelGrid3D ? Constants.TEXTURE_3D : Constants.TEXTURE_2D_ARRAY);
        for (let mrtIndex = 0; mrtIndex < numSlabs; mrtIndex++) {
            let layerIndices = new Array(this._maxDrawBuffers).fill(0);
            layerIndices = layerIndices.map((value, index) => mrtIndex * this._maxDrawBuffers + index);
            let textureNames = new Array(this._maxDrawBuffers).fill("");
            textureNames = textureNames.map((value, index) => "voxel_grid_" + name + (mrtIndex * this._maxDrawBuffers + index));
            const mrt = new MultiRenderTarget("mrt_" + name + mrtIndex, { width: this._voxelResolution, height: this._voxelResolution, depth: this._isVoxelGrid3D ? this._voxelResolution : undefined }, this._maxDrawBuffers, // number of draw buffers
            this._scene, {
                types: new Array(this._maxDrawBuffers).fill(Constants.TEXTURETYPE_UNSIGNED_BYTE),
                samplingModes: new Array(this._maxDrawBuffers).fill(Constants.TEXTURE_TRILINEAR_SAMPLINGMODE),
                generateMipMaps: false,
                targetTypes,
                formats: new Array(this._maxDrawBuffers).fill(Constants.TEXTUREFORMAT_R),
                faceIndex: new Array(this._maxDrawBuffers).fill(0),
                layerIndex: layerIndices,
                layerCounts: new Array(this._maxDrawBuffers).fill(this._voxelResolution),
                generateDepthBuffer: false,
                generateStencilBuffer: false,
            }, textureNames);
            mrt.clearColor = new Color4(0, 0, 0, 1);
            mrt.noPrePassRenderer = true;
            for (let i = 0; i < this._maxDrawBuffers; i++) {
                mrt.setInternalTexture(voxelRT.getInternalTexture(), i);
            }
            mrtArray.push(mrt);
        }
        return mrtArray;
    }
    _disposeVoxelTextures() {
        this._stopVoxelization();
        for (let i = 0; i < this._voxelMrtsZaxis.length; i++) {
            if (this._triPlanarVoxelization) {
                this._voxelMrtsXaxis[i].dispose(true);
                this._voxelMrtsYaxis[i].dispose(true);
            }
            this._voxelMrtsZaxis[i].dispose(true);
        }
        if (this._triPlanarVoxelization) {
            this._voxelGridXaxis?.dispose();
            this._voxelGridYaxis?.dispose();
            this._voxelGridRT?.dispose();
        }
        this._voxelGridZaxis?.dispose();
        for (const mip of this._mipArray) {
            mip.dispose();
        }
        this._voxelMaterial?.dispose();
        this._voxelSlabDebugMaterial?.dispose();
        this._mipArray = [];
        this._voxelMrtsXaxis = [];
        this._voxelMrtsYaxis = [];
        this._voxelMrtsZaxis = [];
    }
    _createVoxelMaterials() {
        const isWebGPU = this._engine.isWebGPU;
        this._voxelMaterial = new ShaderMaterial("voxelization", this._scene, "iblVoxelGrid", {
            uniforms: ["world", "viewMatrix", "invWorldScale", "nearPlane", "farPlane", "stepSize"],
            defines: ["MAX_DRAW_BUFFERS " + this._maxDrawBuffers],
            shaderLanguage: isWebGPU ? 1 /* ShaderLanguage.WGSL */ : 0 /* ShaderLanguage.GLSL */,
            extraInitializationsAsync: async () => {
                if (isWebGPU) {
                    await Promise.all([import('./iblVoxelGrid.fragment-D8UCqyOS.esm.js'), import('./iblVoxelGrid.vertex-CVMW7kBF.esm.js')]);
                }
                else {
                    await Promise.all([import('./iblVoxelGrid.fragment-CUpbUbS8.esm.js'), import('./iblVoxelGrid.vertex-DALgrvlq.esm.js')]);
                }
            },
        });
        this._voxelMaterial.cullBackFaces = false;
        this._voxelMaterial.backFaceCulling = false;
        this._voxelMaterial.depthFunction = Engine.ALWAYS;
        this._voxelSlabDebugMaterial = new ShaderMaterial("voxelSlabDebug", this._scene, "iblVoxelSlabDebug", {
            uniforms: ["world", "viewMatrix", "cameraViewMatrix", "projection", "invWorldScale", "nearPlane", "farPlane", "stepSize"],
            defines: ["MAX_DRAW_BUFFERS " + this._maxDrawBuffers],
            shaderLanguage: isWebGPU ? 1 /* ShaderLanguage.WGSL */ : 0 /* ShaderLanguage.GLSL */,
            extraInitializationsAsync: async () => {
                if (isWebGPU) {
                    await Promise.all([import('./iblVoxelSlabDebug.fragment-_dUPvylU.esm.js'), import('./iblVoxelSlabDebug.vertex-7mC27qNM.esm.js')]);
                }
                else {
                    await Promise.all([import('./iblVoxelSlabDebug.fragment-i_oz6VAp.esm.js'), import('./iblVoxelSlabDebug.vertex-CXUfoZdv.esm.js')]);
                }
            },
        });
    }
    _setDebugBindings() {
        this._voxelSlabDebugMaterial.setMatrix("projection", this._scene.activeCamera.getProjectionMatrix());
        this._voxelSlabDebugMaterial.setMatrix("cameraViewMatrix", this._scene.activeCamera.getViewMatrix());
    }
    /**
     * Checks if the voxel renderer is ready to voxelize scene
     * @returns true if the voxel renderer is ready to voxelize scene
     */
    isReady() {
        let allReady = this.getVoxelGrid().isReady();
        for (let i = 0; i < this._mipArray.length; i++) {
            const mipReady = this._mipArray[i].isReady();
            allReady &&= mipReady;
        }
        if (!allReady || this._voxelizationInProgress) {
            return false;
        }
        return true;
    }
    /**
     * If the MRT's are already in the list of render targets, this will
     * remove them so that they don't get rendered again.
     */
    _stopVoxelization() {
        // If the MRT's are already in the list of render targets, remove them.
        this._removeVoxelRTs(this._voxelMrtsXaxis);
        this._removeVoxelRTs(this._voxelMrtsYaxis);
        this._removeVoxelRTs(this._voxelMrtsZaxis);
    }
    _removeVoxelRTs(rts) {
        // const currentRTs = this._scene.customRenderTargets;
        const rtIdx = this._renderTargets.findIndex((rt) => {
            if (rt === rts[0]) {
                return true;
            }
            return false;
        });
        if (rtIdx >= 0) {
            this._renderTargets.splice(rtIdx, rts.length);
        }
        else {
            const rtIdx = this._scene.customRenderTargets.findIndex((rt) => {
                if (rt === rts[0]) {
                    return true;
                }
                return false;
            });
            if (rtIdx >= 0) {
                this._scene.customRenderTargets.splice(rtIdx, rts.length);
            }
        }
    }
    /**
     * Renders voxel grid of scene for IBL shadows
     * @param includedMeshes
     */
    updateVoxelGrid(includedMeshes) {
        this._stopVoxelization();
        this._includedMeshes = includedMeshes;
        this._voxelizationInProgress = true;
        if (this._triPlanarVoxelization) {
            this._addRTsForRender(this._voxelMrtsXaxis, includedMeshes, 0);
            this._addRTsForRender(this._voxelMrtsYaxis, includedMeshes, 1);
            this._addRTsForRender(this._voxelMrtsZaxis, includedMeshes, 2);
        }
        else {
            this._addRTsForRender(this._voxelMrtsZaxis, includedMeshes, 2);
        }
        if (this._voxelDebugEnabled) {
            this._addRTsForRender([this._voxelSlabDebugRT], includedMeshes, this._voxelDebugAxis, 1, true);
        }
        this._renderVoxelGridBound = this._renderVoxelGrid.bind(this);
        this._scene.onAfterRenderObservable.add(this._renderVoxelGridBound);
    }
    _renderVoxelGrid() {
        if (this._voxelizationInProgress) {
            let allReady = this.getVoxelGrid().isReady();
            for (let i = 0; i < this._mipArray.length; i++) {
                const mipReady = this._mipArray[i].isReady();
                allReady &&= mipReady;
            }
            for (let i = 0; i < this._renderTargets.length; i++) {
                const rttReady = this._renderTargets[i].isReadyForRendering();
                allReady &&= rttReady;
            }
            if (allReady) {
                for (const rt of this._renderTargets) {
                    rt.render();
                }
                this._stopVoxelization();
                if (this._triPlanarVoxelization) {
                    this._voxelGridRT.render();
                }
                this._generateMipMaps();
                // eslint-disable-next-line @typescript-eslint/no-floating-promises, github/no-then
                this._copyMipEffectWrapper.effect.whenCompiledAsync().then(() => {
                    this._copyMipMaps();
                    this._scene.onAfterRenderObservable.removeCallback(this._renderVoxelGridBound);
                    this._voxelizationInProgress = false;
                    this.onVoxelizationCompleteObservable.notifyObservers();
                });
            }
        }
    }
    _addRTsForRender(mrts, includedMeshes, axis, shaderType = 0, continuousRender = false) {
        const slabSize = 1.0 / this._computeNumberOfSlabs();
        let voxelMaterial;
        if (shaderType === 0) {
            voxelMaterial = this._voxelMaterial;
        }
        else {
            voxelMaterial = this._voxelSlabDebugMaterial;
        }
        // We need to update the world scale uniform for every mesh being rendered to the voxel grid.
        for (let mrtIndex = 0; mrtIndex < mrts.length; mrtIndex++) {
            const mrt = mrts[mrtIndex];
            mrt.renderList = [];
            const nearPlane = mrtIndex * slabSize;
            const farPlane = (mrtIndex + 1) * slabSize;
            const stepSize = slabSize / this._maxDrawBuffers;
            const cameraPosition = new Vector3(0, 0, 0);
            let targetPosition = new Vector3(0, 0, 1);
            if (axis === 0) {
                targetPosition = new Vector3(1, 0, 0);
            }
            else if (axis === 1) {
                targetPosition = new Vector3(0, 1, 0);
            }
            let upDirection = new Vector3(0, 1, 0);
            if (axis === 1) {
                upDirection = new Vector3(1, 0, 0);
            }
            mrt.onBeforeRenderObservable.add(() => {
                voxelMaterial.setMatrix("viewMatrix", Matrix.LookAtLH(cameraPosition, targetPosition, upDirection));
                voxelMaterial.setMatrix("invWorldScale", this._invWorldScaleMatrix);
                voxelMaterial.setFloat("nearPlane", nearPlane);
                voxelMaterial.setFloat("farPlane", farPlane);
                voxelMaterial.setFloat("stepSize", stepSize);
            });
            // Set this material on every mesh in the scene (for this RT)
            if (includedMeshes.length === 0) {
                return;
            }
            for (const mesh of includedMeshes) {
                if (mesh) {
                    if (mesh.subMeshes && mesh.subMeshes.length > 0) {
                        mrt.renderList?.push(mesh);
                        mrt.setMaterialForRendering(mesh, voxelMaterial);
                    }
                    const meshes = mesh.getChildMeshes();
                    for (const childMesh of meshes) {
                        if (childMesh.subMeshes && childMesh.subMeshes.length > 0) {
                            mrt.renderList?.push(childMesh);
                            mrt.setMaterialForRendering(childMesh, voxelMaterial);
                        }
                    }
                }
            }
        }
        // Add the MRT's to render.
        if (continuousRender) {
            for (const mrt of mrts) {
                if (this._scene.customRenderTargets.indexOf(mrt) === -1) {
                    this._scene.customRenderTargets.push(mrt);
                }
            }
        }
        else {
            this._renderTargets = this._renderTargets.concat(mrts);
        }
    }
    /**
     * Called by the pipeline to resize resources.
     */
    resize() {
        this._voxelSlabDebugRT?.resize({ width: this._scene.getEngine().getRenderWidth(), height: this._scene.getEngine().getRenderHeight() });
    }
    /**
     * Disposes the voxel renderer and associated resources
     */
    dispose() {
        this._disposeVoxelTextures();
        if (this._voxelSlabDebugRT) {
            this._removeVoxelRTs([this._voxelSlabDebugRT]);
            this._voxelSlabDebugRT.dispose();
        }
        if (this._voxelDebugPass) {
            this._voxelDebugPass.dispose();
        }
        // TODO - dispose all created voxel materials.
    }
}

// Do not edit.
const name$4 = "mrtFragmentDeclaration";
const shader$4 = `#if defined(WEBGL2) || defined(WEBGPU) || defined(NATIVE)
layout(location=0) out vec4 glFragData[{X}];
#endif
`;
// Sideeffect
if (!ShaderStore.IncludesShadersStore[name$4]) {
    ShaderStore.IncludesShadersStore[name$4] = shader$4;
}

// Do not edit.
const name$3 = "geometryPixelShader";
const shader$3 = `#extension GL_EXT_draw_buffers : require
#if defined(BUMP) || !defined(NORMAL)
#extension GL_OES_standard_derivatives : enable
#endif
precision highp float;
#ifdef BUMP
varying mat4 vWorldView;varying vec3 vNormalW;
#else
varying vec3 vNormalV;
#endif
varying vec4 vViewPos;
#if defined(POSITION) || defined(BUMP)
varying vec3 vPositionW;
#endif
#if defined(VELOCITY) || defined(VELOCITY_LINEAR)
varying vec4 vCurrentPosition;varying vec4 vPreviousPosition;
#endif
#ifdef NEED_UV
varying vec2 vUV;
#endif
#ifdef BUMP
uniform vec3 vBumpInfos;uniform vec2 vTangentSpaceParams;
#endif
#if defined(REFLECTIVITY)
#if defined(ORMTEXTURE) || defined(SPECULARGLOSSINESSTEXTURE) || defined(REFLECTIVITYTEXTURE)
uniform sampler2D reflectivitySampler;varying vec2 vReflectivityUV;
#endif
#ifdef ALBEDOTEXTURE
varying vec2 vAlbedoUV;uniform sampler2D albedoSampler;
#endif
#ifdef REFLECTIVITYCOLOR
uniform vec3 reflectivityColor;
#endif
#ifdef ALBEDOCOLOR
uniform vec3 albedoColor;
#endif
#ifdef METALLIC
uniform float metallic;
#endif
#if defined(ROUGHNESS) || defined(GLOSSINESS)
uniform float glossiness;
#endif
#endif
#if defined(ALPHATEST) && defined(NEED_UV)
uniform sampler2D diffuseSampler;
#endif
#include<clipPlaneFragmentDeclaration>
#include<mrtFragmentDeclaration>[SCENE_MRT_COUNT]
#include<bumpFragmentMainFunctions>
#include<bumpFragmentFunctions>
#include<helperFunctions>
void main() {
#include<clipPlaneFragment>
#ifdef ALPHATEST
if (texture2D(diffuseSampler,vUV).a<0.4)
discard;
#endif
vec3 normalOutput;
#ifdef BUMP
vec3 normalW=normalize(vNormalW);
#include<bumpFragment>
#ifdef NORMAL_WORLDSPACE
normalOutput=normalW;
#else
normalOutput=normalize(vec3(vWorldView*vec4(normalW,0.0)));
#endif
#else
normalOutput=normalize(vNormalV);
#endif
#ifdef ENCODE_NORMAL
normalOutput=normalOutput*0.5+0.5;
#endif
#ifdef DEPTH
gl_FragData[DEPTH_INDEX]=vec4(vViewPos.z/vViewPos.w,0.0,0.0,1.0);
#endif
#ifdef NORMAL
gl_FragData[NORMAL_INDEX]=vec4(normalOutput,1.0);
#endif
#ifdef SCREENSPACE_DEPTH
gl_FragData[SCREENSPACE_DEPTH_INDEX]=vec4(gl_FragCoord.z,0.0,0.0,1.0);
#endif
#ifdef POSITION
gl_FragData[POSITION_INDEX]=vec4(vPositionW,1.0);
#endif
#ifdef VELOCITY
vec2 a=(vCurrentPosition.xy/vCurrentPosition.w)*0.5+0.5;vec2 b=(vPreviousPosition.xy/vPreviousPosition.w)*0.5+0.5;vec2 velocity=abs(a-b);velocity=vec2(pow(velocity.x,1.0/3.0),pow(velocity.y,1.0/3.0))*sign(a-b)*0.5+0.5;gl_FragData[VELOCITY_INDEX]=vec4(velocity,0.0,1.0);
#endif
#ifdef VELOCITY_LINEAR
vec2 velocity=vec2(0.5)*((vPreviousPosition.xy/vPreviousPosition.w) -
(vCurrentPosition.xy/vCurrentPosition.w));gl_FragData[VELOCITY_LINEAR_INDEX]=vec4(velocity,0.0,1.0);
#endif
#ifdef REFLECTIVITY
vec4 reflectivity=vec4(0.0,0.0,0.0,1.0);
#ifdef METALLICWORKFLOW
float metal=1.0;float roughness=1.0;
#ifdef ORMTEXTURE
metal*=texture2D(reflectivitySampler,vReflectivityUV).b;roughness*=texture2D(reflectivitySampler,vReflectivityUV).g;
#endif
#ifdef METALLIC
metal*=metallic;
#endif
#ifdef ROUGHNESS
roughness*=(1.0-glossiness); 
#endif
reflectivity.a-=roughness;vec3 color=vec3(1.0);
#ifdef ALBEDOTEXTURE
color=texture2D(albedoSampler,vAlbedoUV).rgb;
#ifdef GAMMAALBEDO
color=toLinearSpace(color);
#endif
#endif
#ifdef ALBEDOCOLOR
color*=albedoColor.xyz;
#endif
reflectivity.rgb=mix(vec3(0.04),color,metal);
#else
#if defined(SPECULARGLOSSINESSTEXTURE) || defined(REFLECTIVITYTEXTURE)
reflectivity=texture2D(reflectivitySampler,vReflectivityUV);
#ifdef GAMMAREFLECTIVITYTEXTURE
reflectivity.rgb=toLinearSpace(reflectivity.rgb);
#endif
#else 
#ifdef REFLECTIVITYCOLOR
reflectivity.rgb=toLinearSpace(reflectivityColor.xyz);reflectivity.a=1.0;
#endif
#endif
#ifdef GLOSSINESSS
reflectivity.a*=glossiness; 
#endif
#endif
gl_FragData[REFLECTIVITY_INDEX]=reflectivity;
#endif
}
`;
// Sideeffect
if (!ShaderStore.ShadersStore[name$3]) {
    ShaderStore.ShadersStore[name$3] = shader$3;
}
/** @internal */
const geometryPixelShader = { name: name$3, shader: shader$3 };

var geometry_fragment = /*#__PURE__*/Object.freeze({
    __proto__: null,
    geometryPixelShader: geometryPixelShader
});

// Do not edit.
const name$2 = "geometryVertexDeclaration";
const shader$2 = `uniform mat4 viewProjection;uniform mat4 view;`;
// Sideeffect
if (!ShaderStore.IncludesShadersStore[name$2]) {
    ShaderStore.IncludesShadersStore[name$2] = shader$2;
}

// Do not edit.
const name$1 = "geometryUboDeclaration";
const shader$1 = `#include<sceneUboDeclaration>
`;
// Sideeffect
if (!ShaderStore.IncludesShadersStore[name$1]) {
    ShaderStore.IncludesShadersStore[name$1] = shader$1;
}

// Do not edit.
const name = "geometryVertexShader";
const shader = `precision highp float;
#include<bonesDeclaration>
#include<bakedVertexAnimationDeclaration>
#include<morphTargetsVertexGlobalDeclaration>
#include<morphTargetsVertexDeclaration>[0..maxSimultaneousMorphTargets]
#include<instancesDeclaration>
#include<__decl__geometryVertex>
#include<clipPlaneVertexDeclaration>
attribute vec3 position;attribute vec3 normal;
#ifdef NEED_UV
varying vec2 vUV;
#ifdef ALPHATEST
uniform mat4 diffuseMatrix;
#endif
#ifdef BUMP
uniform mat4 bumpMatrix;varying vec2 vBumpUV;
#endif
#ifdef REFLECTIVITY
uniform mat4 reflectivityMatrix;uniform mat4 albedoMatrix;varying vec2 vReflectivityUV;varying vec2 vAlbedoUV;
#endif
#ifdef UV1
attribute vec2 uv;
#endif
#ifdef UV2
attribute vec2 uv2;
#endif
#endif
#ifdef BUMP
varying mat4 vWorldView;
#endif
#ifdef BUMP
varying vec3 vNormalW;
#else
varying vec3 vNormalV;
#endif
varying vec4 vViewPos;
#if defined(POSITION) || defined(BUMP)
varying vec3 vPositionW;
#endif
#if defined(VELOCITY) || defined(VELOCITY_LINEAR)
uniform mat4 previousViewProjection;varying vec4 vCurrentPosition;varying vec4 vPreviousPosition;
#endif
#define CUSTOM_VERTEX_DEFINITIONS
void main(void)
{vec3 positionUpdated=position;vec3 normalUpdated=normal;
#ifdef UV1
vec2 uvUpdated=uv;
#endif
#ifdef UV2
vec2 uv2Updated=uv2;
#endif
#include<morphTargetsVertexGlobal>
#include<morphTargetsVertex>[0..maxSimultaneousMorphTargets]
#include<instancesVertex>
#if (defined(VELOCITY) || defined(VELOCITY_LINEAR)) && !defined(BONES_VELOCITY_ENABLED)
vCurrentPosition=viewProjection*finalWorld*vec4(positionUpdated,1.0);vPreviousPosition=previousViewProjection*finalPreviousWorld*vec4(positionUpdated,1.0);
#endif
#include<bonesVertex>
#include<bakedVertexAnimation>
vec4 worldPos=vec4(finalWorld*vec4(positionUpdated,1.0));
#ifdef BUMP
vWorldView=view*finalWorld;mat3 normalWorld=mat3(finalWorld);vNormalW=normalize(normalWorld*normalUpdated);
#else
#ifdef NORMAL_WORLDSPACE
vNormalV=normalize(vec3(finalWorld*vec4(normalUpdated,0.0)));
#else
vNormalV=normalize(vec3((view*finalWorld)*vec4(normalUpdated,0.0)));
#endif
#endif
vViewPos=view*worldPos;
#if (defined(VELOCITY) || defined(VELOCITY_LINEAR)) && defined(BONES_VELOCITY_ENABLED)
vCurrentPosition=viewProjection*finalWorld*vec4(positionUpdated,1.0);
#if NUM_BONE_INFLUENCERS>0
mat4 previousInfluence;previousInfluence=mPreviousBones[int(matricesIndices[0])]*matricesWeights[0];
#if NUM_BONE_INFLUENCERS>1
previousInfluence+=mPreviousBones[int(matricesIndices[1])]*matricesWeights[1];
#endif
#if NUM_BONE_INFLUENCERS>2
previousInfluence+=mPreviousBones[int(matricesIndices[2])]*matricesWeights[2];
#endif
#if NUM_BONE_INFLUENCERS>3
previousInfluence+=mPreviousBones[int(matricesIndices[3])]*matricesWeights[3];
#endif
#if NUM_BONE_INFLUENCERS>4
previousInfluence+=mPreviousBones[int(matricesIndicesExtra[0])]*matricesWeightsExtra[0];
#endif
#if NUM_BONE_INFLUENCERS>5
previousInfluence+=mPreviousBones[int(matricesIndicesExtra[1])]*matricesWeightsExtra[1];
#endif
#if NUM_BONE_INFLUENCERS>6
previousInfluence+=mPreviousBones[int(matricesIndicesExtra[2])]*matricesWeightsExtra[2];
#endif
#if NUM_BONE_INFLUENCERS>7
previousInfluence+=mPreviousBones[int(matricesIndicesExtra[3])]*matricesWeightsExtra[3];
#endif
vPreviousPosition=previousViewProjection*finalPreviousWorld*previousInfluence*vec4(positionUpdated,1.0);
#else
vPreviousPosition=previousViewProjection*finalPreviousWorld*vec4(positionUpdated,1.0);
#endif
#endif
#if defined(POSITION) || defined(BUMP)
vPositionW=worldPos.xyz/worldPos.w;
#endif
gl_Position=viewProjection*finalWorld*vec4(positionUpdated,1.0);
#include<clipPlaneVertex>
#ifdef NEED_UV
#ifdef UV1
#if defined(ALPHATEST) && defined(ALPHATEST_UV1)
vUV=vec2(diffuseMatrix*vec4(uvUpdated,1.0,0.0));
#else
vUV=uvUpdated;
#endif
#ifdef BUMP_UV1
vBumpUV=vec2(bumpMatrix*vec4(uvUpdated,1.0,0.0));
#endif
#ifdef REFLECTIVITY_UV1
vReflectivityUV=vec2(reflectivityMatrix*vec4(uvUpdated,1.0,0.0));
#endif
#ifdef ALBEDO_UV1
vAlbedoUV=vec2(albedoMatrix*vec4(uvUpdated,1.0,0.0));
#endif
#endif
#ifdef UV2
#if defined(ALPHATEST) && defined(ALPHATEST_UV2)
vUV=vec2(diffuseMatrix*vec4(uv2Updated,1.0,0.0));
#else
vUV=uv2Updated;
#endif
#ifdef BUMP_UV2
vBumpUV=vec2(bumpMatrix*vec4(uv2Updated,1.0,0.0));
#endif
#ifdef REFLECTIVITY_UV2
vReflectivityUV=vec2(reflectivityMatrix*vec4(uv2Updated,1.0,0.0));
#endif
#ifdef ALBEDO_UV2
vAlbedoUV=vec2(albedoMatrix*vec4(uv2Updated,1.0,0.0));
#endif
#endif
#endif
#include<bumpVertex>
}
`;
// Sideeffect
if (!ShaderStore.ShadersStore[name]) {
    ShaderStore.ShadersStore[name] = shader;
}
/** @internal */
const geometryVertexShader = { name, shader };

var geometry_vertex = /*#__PURE__*/Object.freeze({
    __proto__: null,
    geometryVertexShader: geometryVertexShader
});

/** list the uniforms used by the geometry renderer */
const Uniforms = [
    "world",
    "mBones",
    "viewProjection",
    "diffuseMatrix",
    "view",
    "previousWorld",
    "previousViewProjection",
    "mPreviousBones",
    "bumpMatrix",
    "reflectivityMatrix",
    "albedoMatrix",
    "reflectivityColor",
    "albedoColor",
    "metallic",
    "glossiness",
    "vTangentSpaceParams",
    "vBumpInfos",
    "morphTargetInfluences",
    "morphTargetCount",
    "morphTargetTextureInfo",
    "morphTargetTextureIndices",
    "boneTextureWidth",
];
AddClipPlaneUniforms(Uniforms);
/**
 * This renderer is helpful to fill one of the render target with a geometry buffer.
 */
class GeometryBufferRenderer {
    /**
     * Gets a boolean indicating if normals are encoded in the [0,1] range in the render target. If true, you should do `normal = normal_rt * 2.0 - 1.0` to get the right normal
     */
    get normalsAreUnsigned() {
        return this._normalsAreUnsigned;
    }
    /**
     * @internal
     * Sets up internal structures to share outputs with PrePassRenderer
     * This method should only be called by the PrePassRenderer itself
     */
    _linkPrePassRenderer(prePassRenderer) {
        this._linkedWithPrePass = true;
        this._prePassRenderer = prePassRenderer;
        if (this._multiRenderTarget) {
            // prevents clearing of the RT since it's done by prepass
            this._multiRenderTarget.onClearObservable.clear();
            this._multiRenderTarget.onClearObservable.add(() => {
                // pass
            });
        }
    }
    /**
     * @internal
     * Separates internal structures from PrePassRenderer so the geometry buffer can now operate by itself.
     * This method should only be called by the PrePassRenderer itself
     */
    _unlinkPrePassRenderer() {
        this._linkedWithPrePass = false;
        this._createRenderTargets();
    }
    /**
     * @internal
     * Resets the geometry buffer layout
     */
    _resetLayout() {
        this._enableDepth = true;
        this._enableNormal = true;
        this._enablePosition = false;
        this._enableReflectivity = false;
        this._enableVelocity = false;
        this._enableVelocityLinear = false;
        this._enableScreenspaceDepth = false;
        this._attachmentsFromPrePass = [];
    }
    /**
     * @internal
     * Replaces a texture in the geometry buffer renderer
     * Useful when linking textures of the prepass renderer
     */
    _forceTextureType(geometryBufferType, index) {
        if (geometryBufferType === GeometryBufferRenderer.POSITION_TEXTURE_TYPE) {
            this._positionIndex = index;
            this._enablePosition = true;
        }
        else if (geometryBufferType === GeometryBufferRenderer.VELOCITY_TEXTURE_TYPE) {
            this._velocityIndex = index;
            this._enableVelocity = true;
        }
        else if (geometryBufferType === GeometryBufferRenderer.VELOCITY_LINEAR_TEXTURE_TYPE) {
            this._velocityLinearIndex = index;
            this._enableVelocityLinear = true;
        }
        else if (geometryBufferType === GeometryBufferRenderer.REFLECTIVITY_TEXTURE_TYPE) {
            this._reflectivityIndex = index;
            this._enableReflectivity = true;
        }
        else if (geometryBufferType === GeometryBufferRenderer.DEPTH_TEXTURE_TYPE) {
            this._depthIndex = index;
            this._enableDepth = true;
        }
        else if (geometryBufferType === GeometryBufferRenderer.NORMAL_TEXTURE_TYPE) {
            this._normalIndex = index;
            this._enableNormal = true;
        }
        else if (geometryBufferType === GeometryBufferRenderer.SCREENSPACE_DEPTH_TEXTURE_TYPE) {
            this._screenspaceDepthIndex = index;
            this._enableScreenspaceDepth = true;
        }
    }
    /**
     * @internal
     * Sets texture attachments
     * Useful when linking textures of the prepass renderer
     */
    _setAttachments(attachments) {
        this._attachmentsFromPrePass = attachments;
    }
    /**
     * @internal
     * Replaces the first texture which is hard coded as a depth texture in the geometry buffer
     * Useful when linking textures of the prepass renderer
     */
    _linkInternalTexture(internalTexture) {
        this._multiRenderTarget.setInternalTexture(internalTexture, 0, false);
    }
    /**
     * Gets the render list (meshes to be rendered) used in the G buffer.
     */
    get renderList() {
        return this._multiRenderTarget.renderList;
    }
    /**
     * Set the render list (meshes to be rendered) used in the G buffer.
     */
    set renderList(meshes) {
        this._multiRenderTarget.renderList = meshes;
    }
    /**
     * Gets whether or not G buffer are supported by the running hardware.
     * This requires draw buffer supports
     */
    get isSupported() {
        return this._multiRenderTarget.isSupported;
    }
    /**
     * Returns the index of the given texture type in the G-Buffer textures array
     * @param textureType The texture type constant. For example GeometryBufferRenderer.POSITION_TEXTURE_INDEX
     * @returns the index of the given texture type in the G-Buffer textures array
     */
    getTextureIndex(textureType) {
        switch (textureType) {
            case GeometryBufferRenderer.POSITION_TEXTURE_TYPE:
                return this._positionIndex;
            case GeometryBufferRenderer.VELOCITY_TEXTURE_TYPE:
                return this._velocityIndex;
            case GeometryBufferRenderer.VELOCITY_LINEAR_TEXTURE_TYPE:
                return this._velocityLinearIndex;
            case GeometryBufferRenderer.REFLECTIVITY_TEXTURE_TYPE:
                return this._reflectivityIndex;
            case GeometryBufferRenderer.DEPTH_TEXTURE_TYPE:
                return this._depthIndex;
            case GeometryBufferRenderer.NORMAL_TEXTURE_TYPE:
                return this._normalIndex;
            case GeometryBufferRenderer.SCREENSPACE_DEPTH_TEXTURE_TYPE:
                return this._screenspaceDepthIndex;
            default:
                return -1;
        }
    }
    /**
     * @returns a boolean indicating if object's depths are enabled for the G buffer.
     */
    get enableDepth() {
        return this._enableDepth;
    }
    /**
     * Sets whether or not object's depths are enabled for the G buffer.
     */
    set enableDepth(enable) {
        this._enableDepth = enable;
        if (!this._linkedWithPrePass) {
            this.dispose();
            this._createRenderTargets();
        }
    }
    /**
     * @returns a boolean indicating if object's normals are enabled for the G buffer.
     */
    get enableNormal() {
        return this._enableNormal;
    }
    /**
     * Sets whether or not object's normals are enabled for the G buffer.
     */
    set enableNormal(enable) {
        this._enableNormal = enable;
        if (!this._linkedWithPrePass) {
            this.dispose();
            this._createRenderTargets();
        }
    }
    /**
     * @returns a boolean indicating if objects positions are enabled for the G buffer.
     */
    get enablePosition() {
        return this._enablePosition;
    }
    /**
     * Sets whether or not objects positions are enabled for the G buffer.
     */
    set enablePosition(enable) {
        this._enablePosition = enable;
        // PrePass handles index and texture links
        if (!this._linkedWithPrePass) {
            this.dispose();
            this._createRenderTargets();
        }
    }
    /**
     * @returns a boolean indicating if objects velocities are enabled for the G buffer.
     */
    get enableVelocity() {
        return this._enableVelocity;
    }
    /**
     * Sets whether or not objects velocities are enabled for the G buffer.
     */
    set enableVelocity(enable) {
        this._enableVelocity = enable;
        if (!enable) {
            this._previousTransformationMatrices = {};
        }
        if (!this._linkedWithPrePass) {
            this.dispose();
            this._createRenderTargets();
        }
        this._scene.needsPreviousWorldMatrices = enable;
    }
    /**
     * @returns a boolean indicating if object's linear velocities are enabled for the G buffer.
     */
    get enableVelocityLinear() {
        return this._enableVelocityLinear;
    }
    /**
     * Sets whether or not object's linear velocities are enabled for the G buffer.
     */
    set enableVelocityLinear(enable) {
        this._enableVelocityLinear = enable;
        if (!this._linkedWithPrePass) {
            this.dispose();
            this._createRenderTargets();
        }
    }
    /**
     * Gets a boolean indicating if objects reflectivity are enabled in the G buffer.
     */
    get enableReflectivity() {
        return this._enableReflectivity;
    }
    /**
     * Sets whether or not objects reflectivity are enabled for the G buffer.
     * For Metallic-Roughness workflow with ORM texture, we assume that ORM texture is defined according to the default layout:
     * pbr.useRoughnessFromMetallicTextureAlpha = false;
     * pbr.useRoughnessFromMetallicTextureGreen = true;
     * pbr.useMetallnessFromMetallicTextureBlue = true;
     */
    set enableReflectivity(enable) {
        this._enableReflectivity = enable;
        if (!this._linkedWithPrePass) {
            this.dispose();
            this._createRenderTargets();
        }
    }
    /**
     * Sets whether or not objects screenspace depth are enabled for the G buffer.
     */
    get enableScreenspaceDepth() {
        return this._enableScreenspaceDepth;
    }
    set enableScreenspaceDepth(enable) {
        this._enableScreenspaceDepth = enable;
        if (!this._linkedWithPrePass) {
            this.dispose();
            this._createRenderTargets();
        }
    }
    /**
     * Gets the scene associated with the buffer.
     */
    get scene() {
        return this._scene;
    }
    /**
     * Gets the ratio used by the buffer during its creation.
     * How big is the buffer related to the main canvas.
     */
    get ratio() {
        return typeof this._ratioOrDimensions === "object" ? 1 : this._ratioOrDimensions;
    }
    /**
     * Gets the shader language used in this material.
     */
    get shaderLanguage() {
        return this._shaderLanguage;
    }
    /**
     * Creates a new G Buffer for the scene
     * @param scene The scene the buffer belongs to
     * @param ratioOrDimensions How big is the buffer related to the main canvas (default: 1). You can also directly pass a width and height for the generated textures
     * @param depthFormat Format of the depth texture (default: Constants.TEXTUREFORMAT_DEPTH16)
     * @param textureTypesAndFormats The types and formats of textures to create as render targets. If not provided, all textures will be RGBA and float or half float, depending on the engine capabilities.
     */
    constructor(scene, ratioOrDimensions = 1, depthFormat = Constants.TEXTUREFORMAT_DEPTH16, textureTypesAndFormats) {
        /**
         * Dictionary used to store the previous transformation matrices of each rendered mesh
         * in order to compute objects velocities when enableVelocity is set to "true"
         * @internal
         */
        this._previousTransformationMatrices = {};
        /**
         * Dictionary used to store the previous bones transformation matrices of each rendered mesh
         * in order to compute objects velocities when enableVelocity is set to "true"
         * @internal
         */
        this._previousBonesTransformationMatrices = {};
        /**
         * Array used to store the ignored skinned meshes while computing velocity map (typically used by the motion blur post-process).
         * Avoids computing bones velocities and computes only mesh's velocity itself (position, rotation, scaling).
         */
        this.excludedSkinnedMeshesFromVelocity = [];
        /** Gets or sets a boolean indicating if transparent meshes should be rendered */
        this.renderTransparentMeshes = true;
        /**
         * Gets or sets a boolean indicating if normals should be generated in world space (default: false, meaning normals are generated in view space)
         */
        this.generateNormalsInWorldSpace = false;
        this._normalsAreUnsigned = false;
        this._resizeObserver = null;
        this._enableDepth = true;
        this._enableNormal = true;
        this._enablePosition = false;
        this._enableVelocity = false;
        this._enableVelocityLinear = false;
        this._enableReflectivity = false;
        this._enableScreenspaceDepth = false;
        this._clearColor = new Color4(0, 0, 0, 0);
        this._clearDepthColor = new Color4(0, 0, 0, 1); // sets an invalid value by default - depth in the depth texture is view.z, so 0 is not possible because view.z can't be less than camera.minZ
        this._positionIndex = -1;
        this._velocityIndex = -1;
        this._velocityLinearIndex = -1;
        this._reflectivityIndex = -1;
        this._depthIndex = -1;
        this._normalIndex = -1;
        this._screenspaceDepthIndex = -1;
        this._linkedWithPrePass = false;
        /**
         * If set to true (default: false), the depth texture will be cleared with the depth value corresponding to the far plane (1 in normal mode, 0 in reverse depth buffer mode)
         * If set to false, the depth texture is always cleared with 0.
         */
        this.useSpecificClearForDepthTexture = false;
        /** Shader language used by the material */
        this._shaderLanguage = 0 /* ShaderLanguage.GLSL */;
        this._shadersLoaded = false;
        this._scene = scene;
        this._ratioOrDimensions = ratioOrDimensions;
        this._useUbo = scene.getEngine().supportsUniformBuffers;
        this._depthFormat = depthFormat;
        this._textureTypesAndFormats = textureTypesAndFormats || {};
        // eslint-disable-next-line @typescript-eslint/no-floating-promises
        this._initShaderSourceAsync();
        GeometryBufferRenderer._SceneComponentInitialization(this._scene);
        // Render target
        this._createRenderTargets();
    }
    async _initShaderSourceAsync() {
        const engine = this._scene.getEngine();
        if (engine.isWebGPU && !GeometryBufferRenderer.ForceGLSL) {
            this._shaderLanguage = 1 /* ShaderLanguage.WGSL */;
            await Promise.all([import('./geometry.vertex-BYyquaIG.esm.js'), import('./geometry.fragment-bRDJFXuD.esm.js')]);
        }
        else {
            await Promise.all([Promise.resolve().then(function () { return geometry_vertex; }), Promise.resolve().then(function () { return geometry_fragment; })]);
        }
        this._shadersLoaded = true;
    }
    /**
     * Checks whether everything is ready to render a submesh to the G buffer.
     * @param subMesh the submesh to check readiness for
     * @param useInstances is the mesh drawn using instance or not
     * @returns true if ready otherwise false
     */
    isReady(subMesh, useInstances) {
        if (!this._shadersLoaded) {
            return false;
        }
        const material = subMesh.getMaterial();
        if (material && material.disableDepthWrite) {
            return false;
        }
        const defines = [];
        const attribs = [VertexBuffer.PositionKind, VertexBuffer.NormalKind];
        const mesh = subMesh.getMesh();
        let uv1 = false;
        let uv2 = false;
        const color = false;
        if (material) {
            let needUv = false;
            // Alpha test
            if (material.needAlphaTestingForMesh(mesh) && material.getAlphaTestTexture()) {
                defines.push("#define ALPHATEST");
                defines.push(`#define ALPHATEST_UV${material.getAlphaTestTexture().coordinatesIndex + 1}`);
                needUv = true;
            }
            // Normal map texture
            if ((material.bumpTexture || material.normalTexture) && MaterialFlags.BumpTextureEnabled) {
                const texture = material.bumpTexture || material.normalTexture;
                defines.push("#define BUMP");
                defines.push(`#define BUMP_UV${texture.coordinatesIndex + 1}`);
                needUv = true;
            }
            if (this._enableReflectivity) {
                let metallicWorkflow = false;
                // for PBR materials: cf. https://doc.babylonjs.com/features/featuresDeepDive/materials/using/masterPBR
                if (material.getClassName() === "PBRMetallicRoughnessMaterial") {
                    // if it is a PBR material in MetallicRoughness Mode:
                    if (material.metallicRoughnessTexture) {
                        defines.push("#define ORMTEXTURE");
                        defines.push(`#define REFLECTIVITY_UV${material.metallicRoughnessTexture.coordinatesIndex + 1}`);
                        defines.push("#define METALLICWORKFLOW");
                        needUv = true;
                        metallicWorkflow = true;
                    }
                    // null or undefined
                    if (material.metallic != null) {
                        defines.push("#define METALLIC");
                        defines.push("#define METALLICWORKFLOW");
                        metallicWorkflow = true;
                    }
                    // null or undefined
                    if (material.roughness != null) {
                        defines.push("#define ROUGHNESS");
                        defines.push("#define METALLICWORKFLOW");
                        metallicWorkflow = true;
                    }
                    if (metallicWorkflow) {
                        if (material.baseTexture) {
                            defines.push("#define ALBEDOTEXTURE");
                            defines.push(`#define ALBEDO_UV${material.baseTexture.coordinatesIndex + 1}`);
                            if (material.baseTexture.gammaSpace) {
                                defines.push("#define GAMMAALBEDO");
                            }
                            needUv = true;
                        }
                        if (material.baseColor) {
                            defines.push("#define ALBEDOCOLOR");
                        }
                    }
                }
                else if (material.getClassName() === "PBRSpecularGlossinessMaterial") {
                    // if it is a PBR material in Specular/Glossiness Mode:
                    if (material.specularGlossinessTexture) {
                        defines.push("#define SPECULARGLOSSINESSTEXTURE");
                        defines.push(`#define REFLECTIVITY_UV${material.specularGlossinessTexture.coordinatesIndex + 1}`);
                        needUv = true;
                        if (material.specularGlossinessTexture.gammaSpace) {
                            defines.push("#define GAMMAREFLECTIVITYTEXTURE");
                        }
                    }
                    else {
                        if (material.specularColor) {
                            defines.push("#define REFLECTIVITYCOLOR");
                        }
                    }
                    // null or undefined
                    if (material.glossiness != null) {
                        defines.push("#define GLOSSINESS");
                    }
                }
                else if (material.getClassName() === "PBRMaterial") {
                    // if it is the bigger PBRMaterial
                    if (material.metallicTexture) {
                        defines.push("#define ORMTEXTURE");
                        defines.push(`#define REFLECTIVITY_UV${material.metallicTexture.coordinatesIndex + 1}`);
                        defines.push("#define METALLICWORKFLOW");
                        needUv = true;
                        metallicWorkflow = true;
                    }
                    // null or undefined
                    if (material.metallic != null) {
                        defines.push("#define METALLIC");
                        defines.push("#define METALLICWORKFLOW");
                        metallicWorkflow = true;
                    }
                    // null or undefined
                    if (material.roughness != null) {
                        defines.push("#define ROUGHNESS");
                        defines.push("#define METALLICWORKFLOW");
                        metallicWorkflow = true;
                    }
                    if (metallicWorkflow) {
                        if (material.albedoTexture) {
                            defines.push("#define ALBEDOTEXTURE");
                            defines.push(`#define ALBEDO_UV${material.albedoTexture.coordinatesIndex + 1}`);
                            if (material.albedoTexture.gammaSpace) {
                                defines.push("#define GAMMAALBEDO");
                            }
                            needUv = true;
                        }
                        if (material.albedoColor) {
                            defines.push("#define ALBEDOCOLOR");
                        }
                    }
                    else {
                        // SpecularGlossiness Model
                        if (material.reflectivityTexture) {
                            defines.push("#define SPECULARGLOSSINESSTEXTURE");
                            defines.push(`#define REFLECTIVITY_UV${material.reflectivityTexture.coordinatesIndex + 1}`);
                            if (material.reflectivityTexture.gammaSpace) {
                                defines.push("#define GAMMAREFLECTIVITYTEXTURE");
                            }
                            needUv = true;
                        }
                        else if (material.reflectivityColor) {
                            defines.push("#define REFLECTIVITYCOLOR");
                        }
                        // null or undefined
                        if (material.microSurface != null) {
                            defines.push("#define GLOSSINESS");
                        }
                    }
                }
                else if (material.getClassName() === "StandardMaterial") {
                    // if StandardMaterial:
                    if (material.specularTexture) {
                        defines.push("#define REFLECTIVITYTEXTURE");
                        defines.push(`#define REFLECTIVITY_UV${material.specularTexture.coordinatesIndex + 1}`);
                        if (material.specularTexture.gammaSpace) {
                            defines.push("#define GAMMAREFLECTIVITYTEXTURE");
                        }
                        needUv = true;
                    }
                    if (material.specularColor) {
                        defines.push("#define REFLECTIVITYCOLOR");
                    }
                }
            }
            if (needUv) {
                defines.push("#define NEED_UV");
                if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
                    attribs.push(VertexBuffer.UVKind);
                    defines.push("#define UV1");
                    uv1 = true;
                }
                if (mesh.isVerticesDataPresent(VertexBuffer.UV2Kind)) {
                    attribs.push(VertexBuffer.UV2Kind);
                    defines.push("#define UV2");
                    uv2 = true;
                }
            }
        }
        // Buffers
        if (this._enableDepth) {
            defines.push("#define DEPTH");
            defines.push("#define DEPTH_INDEX " + this._depthIndex);
        }
        if (this._enableNormal) {
            defines.push("#define NORMAL");
            defines.push("#define NORMAL_INDEX " + this._normalIndex);
        }
        if (this._enablePosition) {
            defines.push("#define POSITION");
            defines.push("#define POSITION_INDEX " + this._positionIndex);
        }
        if (this._enableVelocity) {
            defines.push("#define VELOCITY");
            defines.push("#define VELOCITY_INDEX " + this._velocityIndex);
            if (this.excludedSkinnedMeshesFromVelocity.indexOf(mesh) === -1) {
                defines.push("#define BONES_VELOCITY_ENABLED");
            }
        }
        if (this._enableVelocityLinear) {
            defines.push("#define VELOCITY_LINEAR");
            defines.push("#define VELOCITY_LINEAR_INDEX " + this._velocityLinearIndex);
            if (this.excludedSkinnedMeshesFromVelocity.indexOf(mesh) === -1) {
                defines.push("#define BONES_VELOCITY_ENABLED");
            }
        }
        if (this._enableReflectivity) {
            defines.push("#define REFLECTIVITY");
            defines.push("#define REFLECTIVITY_INDEX " + this._reflectivityIndex);
        }
        if (this._enableScreenspaceDepth) {
            if (this._screenspaceDepthIndex !== -1) {
                defines.push("#define SCREENSPACE_DEPTH_INDEX " + this._screenspaceDepthIndex);
                defines.push("#define SCREENSPACE_DEPTH");
            }
        }
        if (this.generateNormalsInWorldSpace) {
            defines.push("#define NORMAL_WORLDSPACE");
        }
        if (this._normalsAreUnsigned) {
            defines.push("#define ENCODE_NORMAL");
        }
        // Bones
        if (mesh.useBones && mesh.computeBonesUsingShaders && mesh.skeleton) {
            attribs.push(VertexBuffer.MatricesIndicesKind);
            attribs.push(VertexBuffer.MatricesWeightsKind);
            if (mesh.numBoneInfluencers > 4) {
                attribs.push(VertexBuffer.MatricesIndicesExtraKind);
                attribs.push(VertexBuffer.MatricesWeightsExtraKind);
            }
            defines.push("#define NUM_BONE_INFLUENCERS " + mesh.numBoneInfluencers);
            defines.push("#define BONETEXTURE " + mesh.skeleton.isUsingTextureForMatrices);
            defines.push("#define BonesPerMesh " + (mesh.skeleton.bones.length + 1));
        }
        else {
            defines.push("#define NUM_BONE_INFLUENCERS 0");
            defines.push("#define BONETEXTURE false");
            defines.push("#define BonesPerMesh 0");
        }
        // Morph targets
        const numMorphInfluencers = mesh.morphTargetManager
            ? PrepareDefinesAndAttributesForMorphTargets(mesh.morphTargetManager, defines, attribs, mesh, true, // usePositionMorph
            true, // useNormalMorph
            false, // useTangentMorph
            uv1, // useUVMorph
            uv2, // useUV2Morph
            color // useColorMorph
            )
            : 0;
        // Instances
        if (useInstances) {
            defines.push("#define INSTANCES");
            PushAttributesForInstances(attribs, this._enableVelocity || this._enableVelocityLinear);
            if (subMesh.getRenderingMesh().hasThinInstances) {
                defines.push("#define THIN_INSTANCES");
            }
        }
        // Setup textures count
        if (this._linkedWithPrePass) {
            defines.push("#define SCENE_MRT_COUNT " + this._attachmentsFromPrePass.length);
        }
        else {
            defines.push("#define SCENE_MRT_COUNT " + this._multiRenderTarget.textures.length);
        }
        PrepareStringDefinesForClipPlanes(material, this._scene, defines);
        // Get correct effect
        const engine = this._scene.getEngine();
        const drawWrapper = subMesh._getDrawWrapper(undefined, true);
        const cachedDefines = drawWrapper.defines;
        const join = defines.join("\n");
        if (cachedDefines !== join) {
            drawWrapper.setEffect(engine.createEffect("geometry", {
                attributes: attribs,
                uniformsNames: Uniforms,
                samplers: ["diffuseSampler", "bumpSampler", "reflectivitySampler", "albedoSampler", "morphTargets", "boneSampler"],
                defines: join,
                onCompiled: null,
                fallbacks: null,
                onError: null,
                uniformBuffersNames: ["Scene"],
                indexParameters: { buffersCount: this._multiRenderTarget.textures.length - 1, maxSimultaneousMorphTargets: numMorphInfluencers },
                shaderLanguage: this.shaderLanguage,
            }, engine), join);
        }
        return drawWrapper.effect.isReady();
    }
    /**
     * Gets the current underlying G Buffer.
     * @returns the buffer
     */
    getGBuffer() {
        return this._multiRenderTarget;
    }
    /**
     * Gets the number of samples used to render the buffer (anti aliasing).
     */
    get samples() {
        return this._multiRenderTarget.samples;
    }
    /**
     * Sets the number of samples used to render the buffer (anti aliasing).
     */
    set samples(value) {
        this._multiRenderTarget.samples = value;
    }
    /**
     * Disposes the renderer and frees up associated resources.
     */
    dispose() {
        if (this._resizeObserver) {
            const engine = this._scene.getEngine();
            engine.onResizeObservable.remove(this._resizeObserver);
            this._resizeObserver = null;
        }
        this.getGBuffer().dispose();
    }
    _assignRenderTargetIndices() {
        const textureNames = [];
        const textureTypesAndFormats = [];
        let count = 0;
        if (this._enableDepth) {
            this._depthIndex = count;
            count++;
            textureNames.push("gBuffer_Depth");
            textureTypesAndFormats.push(this._textureTypesAndFormats[GeometryBufferRenderer.DEPTH_TEXTURE_TYPE]);
        }
        if (this._enableNormal) {
            this._normalIndex = count;
            count++;
            textureNames.push("gBuffer_Normal");
            textureTypesAndFormats.push(this._textureTypesAndFormats[GeometryBufferRenderer.NORMAL_TEXTURE_TYPE]);
        }
        if (this._enablePosition) {
            this._positionIndex = count;
            count++;
            textureNames.push("gBuffer_Position");
            textureTypesAndFormats.push(this._textureTypesAndFormats[GeometryBufferRenderer.POSITION_TEXTURE_TYPE]);
        }
        if (this._enableVelocity) {
            this._velocityIndex = count;
            count++;
            textureNames.push("gBuffer_Velocity");
            textureTypesAndFormats.push(this._textureTypesAndFormats[GeometryBufferRenderer.VELOCITY_TEXTURE_TYPE]);
        }
        if (this._enableVelocityLinear) {
            this._velocityLinearIndex = count;
            count++;
            textureNames.push("gBuffer_VelocityLinear");
            textureTypesAndFormats.push(this._textureTypesAndFormats[GeometryBufferRenderer.VELOCITY_LINEAR_TEXTURE_TYPE]);
        }
        if (this._enableReflectivity) {
            this._reflectivityIndex = count;
            count++;
            textureNames.push("gBuffer_Reflectivity");
            textureTypesAndFormats.push(this._textureTypesAndFormats[GeometryBufferRenderer.REFLECTIVITY_TEXTURE_TYPE]);
        }
        if (this._enableScreenspaceDepth) {
            this._screenspaceDepthIndex = count;
            count++;
            textureNames.push("gBuffer_ScreenspaceDepth");
            textureTypesAndFormats.push(this._textureTypesAndFormats[GeometryBufferRenderer.SCREENSPACE_DEPTH_TEXTURE_TYPE]);
        }
        return [count, textureNames, textureTypesAndFormats];
    }
    _createRenderTargets() {
        const engine = this._scene.getEngine();
        const [count, textureNames, textureTypesAndFormat] = this._assignRenderTargetIndices();
        let type = Constants.TEXTURETYPE_UNSIGNED_BYTE;
        if (engine._caps.textureFloat && engine._caps.textureFloatLinearFiltering) {
            type = Constants.TEXTURETYPE_FLOAT;
        }
        else if (engine._caps.textureHalfFloat && engine._caps.textureHalfFloatLinearFiltering) {
            type = Constants.TEXTURETYPE_HALF_FLOAT;
        }
        const dimensions = this._ratioOrDimensions.width !== undefined
            ? this._ratioOrDimensions
            : { width: engine.getRenderWidth() * this._ratioOrDimensions, height: engine.getRenderHeight() * this._ratioOrDimensions };
        const textureTypes = [];
        const textureFormats = [];
        for (const typeAndFormat of textureTypesAndFormat) {
            if (typeAndFormat) {
                textureTypes.push(typeAndFormat.textureType);
                textureFormats.push(typeAndFormat.textureFormat);
            }
            else {
                textureTypes.push(type);
                textureFormats.push(Constants.TEXTUREFORMAT_RGBA);
            }
        }
        this._normalsAreUnsigned =
            textureTypes[GeometryBufferRenderer.NORMAL_TEXTURE_TYPE] === Constants.TEXTURETYPE_UNSIGNED_INT_2_10_10_10_REV ||
                textureTypes[GeometryBufferRenderer.NORMAL_TEXTURE_TYPE] === Constants.TEXTURETYPE_UNSIGNED_INT_10F_11F_11F_REV;
        this._multiRenderTarget = new MultiRenderTarget("gBuffer", dimensions, count, this._scene, { generateMipMaps: false, generateDepthTexture: true, types: textureTypes, formats: textureFormats, depthTextureFormat: this._depthFormat }, textureNames.concat("gBuffer_DepthBuffer"));
        if (!this.isSupported) {
            return;
        }
        this._multiRenderTarget.wrapU = Texture.CLAMP_ADDRESSMODE;
        this._multiRenderTarget.wrapV = Texture.CLAMP_ADDRESSMODE;
        this._multiRenderTarget.refreshRate = 1;
        this._multiRenderTarget.renderParticles = false;
        this._multiRenderTarget.renderList = null;
        // Depth is always the first texture in the geometry buffer renderer!
        const layoutAttachmentsAll = [true];
        const layoutAttachmentsAllButDepth = [false];
        const layoutAttachmentsDepthOnly = [true];
        for (let i = 1; i < count; ++i) {
            layoutAttachmentsAll.push(true);
            layoutAttachmentsDepthOnly.push(false);
            layoutAttachmentsAllButDepth.push(true);
        }
        const attachmentsAll = engine.buildTextureLayout(layoutAttachmentsAll);
        const attachmentsAllButDepth = engine.buildTextureLayout(layoutAttachmentsAllButDepth);
        const attachmentsDepthOnly = engine.buildTextureLayout(layoutAttachmentsDepthOnly);
        this._multiRenderTarget.onClearObservable.add((engine) => {
            engine.bindAttachments(this.useSpecificClearForDepthTexture ? attachmentsAllButDepth : attachmentsAll);
            engine.clear(this._clearColor, true, true, true);
            if (this.useSpecificClearForDepthTexture) {
                engine.bindAttachments(attachmentsDepthOnly);
                engine.clear(this._clearDepthColor, true, true, true);
            }
            engine.bindAttachments(attachmentsAll);
        });
        this._resizeObserver = engine.onResizeObservable.add(() => {
            if (this._multiRenderTarget) {
                const dimensions = this._ratioOrDimensions.width !== undefined
                    ? this._ratioOrDimensions
                    : { width: engine.getRenderWidth() * this._ratioOrDimensions, height: engine.getRenderHeight() * this._ratioOrDimensions };
                this._multiRenderTarget.resize(dimensions);
            }
        });
        // Custom render function
        const renderSubMesh = (subMesh) => {
            const renderingMesh = subMesh.getRenderingMesh();
            const effectiveMesh = subMesh.getEffectiveMesh();
            const scene = this._scene;
            const engine = scene.getEngine();
            const material = subMesh.getMaterial();
            if (!material) {
                return;
            }
            effectiveMesh._internalAbstractMeshDataInfo._isActiveIntermediate = false;
            // Velocity
            if ((this._enableVelocity || this._enableVelocityLinear) && !this._previousTransformationMatrices[effectiveMesh.uniqueId]) {
                this._previousTransformationMatrices[effectiveMesh.uniqueId] = {
                    world: Matrix.Identity(),
                    viewProjection: scene.getTransformMatrix(),
                };
                if (renderingMesh.skeleton) {
                    const bonesTransformations = renderingMesh.skeleton.getTransformMatrices(renderingMesh);
                    this._previousBonesTransformationMatrices[renderingMesh.uniqueId] = this._copyBonesTransformationMatrices(bonesTransformations, new Float32Array(bonesTransformations.length));
                }
            }
            // Managing instances
            const batch = renderingMesh._getInstancesRenderList(subMesh._id, !!subMesh.getReplacementMesh());
            if (batch.mustReturn) {
                return;
            }
            const hardwareInstancedRendering = engine.getCaps().instancedArrays && (batch.visibleInstances[subMesh._id] !== null || renderingMesh.hasThinInstances);
            const world = effectiveMesh.getWorldMatrix();
            if (this.isReady(subMesh, hardwareInstancedRendering)) {
                const drawWrapper = subMesh._getDrawWrapper();
                if (!drawWrapper) {
                    return;
                }
                const effect = drawWrapper.effect;
                engine.enableEffect(drawWrapper);
                if (!hardwareInstancedRendering) {
                    renderingMesh._bind(subMesh, effect, material.fillMode);
                }
                if (!this._useUbo) {
                    effect.setMatrix("viewProjection", scene.getTransformMatrix());
                    effect.setMatrix("view", scene.getViewMatrix());
                }
                else {
                    BindSceneUniformBuffer(effect, this._scene.getSceneUniformBuffer());
                    this._scene.finalizeSceneUbo();
                }
                let sideOrientation;
                const instanceDataStorage = renderingMesh._instanceDataStorage;
                if (!instanceDataStorage.isFrozen && (material.backFaceCulling || material.sideOrientation !== null)) {
                    const mainDeterminant = effectiveMesh._getWorldMatrixDeterminant();
                    sideOrientation = material._getEffectiveOrientation(renderingMesh);
                    if (mainDeterminant < 0) {
                        sideOrientation = sideOrientation === Material.ClockWiseSideOrientation ? Material.CounterClockWiseSideOrientation : Material.ClockWiseSideOrientation;
                    }
                }
                else {
                    sideOrientation = renderingMesh._effectiveSideOrientation;
                }
                material._preBind(drawWrapper, sideOrientation);
                // Alpha test
                if (material.needAlphaTestingForMesh(effectiveMesh)) {
                    const alphaTexture = material.getAlphaTestTexture();
                    if (alphaTexture) {
                        effect.setTexture("diffuseSampler", alphaTexture);
                        effect.setMatrix("diffuseMatrix", alphaTexture.getTextureMatrix());
                    }
                }
                // Bump
                if ((material.bumpTexture || material.normalTexture) && scene.getEngine().getCaps().standardDerivatives && MaterialFlags.BumpTextureEnabled) {
                    const texture = material.bumpTexture || material.normalTexture;
                    effect.setFloat3("vBumpInfos", texture.coordinatesIndex, 1.0 / texture.level, material.parallaxScaleBias);
                    effect.setMatrix("bumpMatrix", texture.getTextureMatrix());
                    effect.setTexture("bumpSampler", texture);
                    effect.setFloat2("vTangentSpaceParams", material.invertNormalMapX ? -1 : 1.0, material.invertNormalMapY ? -1 : 1.0);
                }
                // Reflectivity
                if (this._enableReflectivity) {
                    // for PBR materials: cf. https://doc.babylonjs.com/features/featuresDeepDive/materials/using/masterPBR
                    if (material.getClassName() === "PBRMetallicRoughnessMaterial") {
                        // if it is a PBR material in MetallicRoughness Mode:
                        if (material.metallicRoughnessTexture !== null) {
                            effect.setTexture("reflectivitySampler", material.metallicRoughnessTexture);
                            effect.setMatrix("reflectivityMatrix", material.metallicRoughnessTexture.getTextureMatrix());
                        }
                        if (material.metallic !== null) {
                            effect.setFloat("metallic", material.metallic);
                        }
                        if (material.roughness !== null) {
                            effect.setFloat("glossiness", 1.0 - material.roughness);
                        }
                        if (material.baseTexture !== null) {
                            effect.setTexture("albedoSampler", material.baseTexture);
                            effect.setMatrix("albedoMatrix", material.baseTexture.getTextureMatrix());
                        }
                        if (material.baseColor !== null) {
                            effect.setColor3("albedoColor", material.baseColor);
                        }
                    }
                    else if (material.getClassName() === "PBRSpecularGlossinessMaterial") {
                        // if it is a PBR material in Specular/Glossiness Mode:
                        if (material.specularGlossinessTexture !== null) {
                            effect.setTexture("reflectivitySampler", material.specularGlossinessTexture);
                            effect.setMatrix("reflectivityMatrix", material.specularGlossinessTexture.getTextureMatrix());
                        }
                        else {
                            if (material.specularColor !== null) {
                                effect.setColor3("reflectivityColor", material.specularColor);
                            }
                        }
                        if (material.glossiness !== null) {
                            effect.setFloat("glossiness", material.glossiness);
                        }
                    }
                    else if (material.getClassName() === "PBRMaterial") {
                        // if it is the bigger PBRMaterial
                        if (material.metallicTexture !== null) {
                            effect.setTexture("reflectivitySampler", material.metallicTexture);
                            effect.setMatrix("reflectivityMatrix", material.metallicTexture.getTextureMatrix());
                        }
                        if (material.metallic !== null) {
                            effect.setFloat("metallic", material.metallic);
                        }
                        if (material.roughness !== null) {
                            effect.setFloat("glossiness", 1.0 - material.roughness);
                        }
                        if (material.roughness !== null || material.metallic !== null || material.metallicTexture !== null) {
                            // MetallicRoughness Model
                            if (material.albedoTexture !== null) {
                                effect.setTexture("albedoSampler", material.albedoTexture);
                                effect.setMatrix("albedoMatrix", material.albedoTexture.getTextureMatrix());
                            }
                            if (material.albedoColor !== null) {
                                effect.setColor3("albedoColor", material.albedoColor);
                            }
                        }
                        else {
                            // SpecularGlossiness Model
                            if (material.reflectivityTexture !== null) {
                                effect.setTexture("reflectivitySampler", material.reflectivityTexture);
                                effect.setMatrix("reflectivityMatrix", material.reflectivityTexture.getTextureMatrix());
                            }
                            else if (material.reflectivityColor !== null) {
                                effect.setColor3("reflectivityColor", material.reflectivityColor);
                            }
                            if (material.microSurface !== null) {
                                effect.setFloat("glossiness", material.microSurface);
                            }
                        }
                    }
                    else if (material.getClassName() === "StandardMaterial") {
                        // if StandardMaterial:
                        if (material.specularTexture !== null) {
                            effect.setTexture("reflectivitySampler", material.specularTexture);
                            effect.setMatrix("reflectivityMatrix", material.specularTexture.getTextureMatrix());
                        }
                        if (material.specularColor !== null) {
                            effect.setColor3("reflectivityColor", material.specularColor);
                        }
                    }
                }
                // Clip plane
                BindClipPlane(effect, material, this._scene);
                // Bones
                if (renderingMesh.useBones && renderingMesh.computeBonesUsingShaders && renderingMesh.skeleton) {
                    const skeleton = renderingMesh.skeleton;
                    if (skeleton.isUsingTextureForMatrices && effect.getUniformIndex("boneTextureWidth") > -1) {
                        const boneTexture = skeleton.getTransformMatrixTexture(renderingMesh);
                        effect.setTexture("boneSampler", boneTexture);
                        effect.setFloat("boneTextureWidth", 4.0 * (skeleton.bones.length + 1));
                    }
                    else {
                        effect.setMatrices("mBones", renderingMesh.skeleton.getTransformMatrices(renderingMesh));
                    }
                    if (this._enableVelocity || this._enableVelocityLinear) {
                        effect.setMatrices("mPreviousBones", this._previousBonesTransformationMatrices[renderingMesh.uniqueId]);
                    }
                }
                // Morph targets
                BindMorphTargetParameters(renderingMesh, effect);
                if (renderingMesh.morphTargetManager && renderingMesh.morphTargetManager.isUsingTextureForTargets) {
                    renderingMesh.morphTargetManager._bind(effect);
                }
                // Velocity
                if (this._enableVelocity || this._enableVelocityLinear) {
                    effect.setMatrix("previousWorld", this._previousTransformationMatrices[effectiveMesh.uniqueId].world);
                    effect.setMatrix("previousViewProjection", this._previousTransformationMatrices[effectiveMesh.uniqueId].viewProjection);
                }
                if (hardwareInstancedRendering && renderingMesh.hasThinInstances) {
                    effect.setMatrix("world", world);
                }
                // Draw
                renderingMesh._processRendering(effectiveMesh, subMesh, effect, material.fillMode, batch, hardwareInstancedRendering, (isInstance, w) => {
                    if (!isInstance) {
                        effect.setMatrix("world", w);
                    }
                });
            }
            // Velocity
            if (this._enableVelocity || this._enableVelocityLinear) {
                this._previousTransformationMatrices[effectiveMesh.uniqueId].world = world.clone();
                this._previousTransformationMatrices[effectiveMesh.uniqueId].viewProjection = this._scene.getTransformMatrix().clone();
                if (renderingMesh.skeleton) {
                    this._copyBonesTransformationMatrices(renderingMesh.skeleton.getTransformMatrices(renderingMesh), this._previousBonesTransformationMatrices[effectiveMesh.uniqueId]);
                }
            }
        };
        this._multiRenderTarget.customIsReadyFunction = (mesh, refreshRate, preWarm) => {
            if ((preWarm || refreshRate === 0) && mesh.subMeshes) {
                for (let i = 0; i < mesh.subMeshes.length; ++i) {
                    const subMesh = mesh.subMeshes[i];
                    const material = subMesh.getMaterial();
                    const renderingMesh = subMesh.getRenderingMesh();
                    if (!material) {
                        continue;
                    }
                    const batch = renderingMesh._getInstancesRenderList(subMesh._id, !!subMesh.getReplacementMesh());
                    const hardwareInstancedRendering = engine.getCaps().instancedArrays && (batch.visibleInstances[subMesh._id] !== null || renderingMesh.hasThinInstances);
                    if (!this.isReady(subMesh, hardwareInstancedRendering)) {
                        return false;
                    }
                }
            }
            return true;
        };
        this._multiRenderTarget.customRenderFunction = (opaqueSubMeshes, alphaTestSubMeshes, transparentSubMeshes, depthOnlySubMeshes) => {
            let index;
            if (this._linkedWithPrePass) {
                if (!this._prePassRenderer.enabled) {
                    return;
                }
                this._scene.getEngine().bindAttachments(this._attachmentsFromPrePass);
            }
            if (depthOnlySubMeshes.length) {
                engine.setColorWrite(false);
                for (index = 0; index < depthOnlySubMeshes.length; index++) {
                    renderSubMesh(depthOnlySubMeshes.data[index]);
                }
                engine.setColorWrite(true);
            }
            for (index = 0; index < opaqueSubMeshes.length; index++) {
                renderSubMesh(opaqueSubMeshes.data[index]);
            }
            engine.setDepthWrite(false);
            for (index = 0; index < alphaTestSubMeshes.length; index++) {
                renderSubMesh(alphaTestSubMeshes.data[index]);
            }
            if (this.renderTransparentMeshes) {
                for (index = 0; index < transparentSubMeshes.length; index++) {
                    renderSubMesh(transparentSubMeshes.data[index]);
                }
            }
            engine.setDepthWrite(true);
        };
    }
    // Copies the bones transformation matrices into the target array and returns the target's reference
    _copyBonesTransformationMatrices(source, target) {
        for (let i = 0; i < source.length; i++) {
            target[i] = source[i];
        }
        return target;
    }
}
/**
 * Force all the standard materials to compile to glsl even on WebGPU engines.
 * False by default. This is mostly meant for backward compatibility.
 */
GeometryBufferRenderer.ForceGLSL = false;
/**
 * Constant used to retrieve the depth texture index in the G-Buffer textures array
 * using getIndex(GeometryBufferRenderer.DEPTH_TEXTURE_INDEX)
 */
GeometryBufferRenderer.DEPTH_TEXTURE_TYPE = 0;
/**
 * Constant used to retrieve the normal texture index in the G-Buffer textures array
 * using getIndex(GeometryBufferRenderer.NORMAL_TEXTURE_INDEX)
 */
GeometryBufferRenderer.NORMAL_TEXTURE_TYPE = 1;
/**
 * Constant used to retrieve the position texture index in the G-Buffer textures array
 * using getIndex(GeometryBufferRenderer.POSITION_TEXTURE_INDEX)
 */
GeometryBufferRenderer.POSITION_TEXTURE_TYPE = 2;
/**
 * Constant used to retrieve the velocity texture index in the G-Buffer textures array
 * using getIndex(GeometryBufferRenderer.VELOCITY_TEXTURE_INDEX)
 */
GeometryBufferRenderer.VELOCITY_TEXTURE_TYPE = 3;
/**
 * Constant used to retrieve the reflectivity texture index in the G-Buffer textures array
 * using the getIndex(GeometryBufferRenderer.REFLECTIVITY_TEXTURE_TYPE)
 */
GeometryBufferRenderer.REFLECTIVITY_TEXTURE_TYPE = 4;
/**
 * Constant used to retrieve the screen-space depth texture index in the G-Buffer textures array
 * using getIndex(GeometryBufferRenderer.SCREENSPACE_DEPTH_TEXTURE_TYPE)
 */
GeometryBufferRenderer.SCREENSPACE_DEPTH_TEXTURE_TYPE = 5;
/**
 * Constant used to retrieve the linear velocity texture index in the G-Buffer textures array
 * using getIndex(GeometryBufferRenderer.VELOCITY_LINEAR_TEXTURE_TYPE)
 */
GeometryBufferRenderer.VELOCITY_LINEAR_TEXTURE_TYPE = 6;
/**
 * @internal
 */
GeometryBufferRenderer._SceneComponentInitialization = (_) => {
    throw _WarnImport("GeometryBufferRendererSceneComponent");
};

/**
 * Build cdf maps for IBL importance sampling during IBL shadow computation.
 * This should not be instantiated directly, as it is part of a scene component
 * @internal
 */
class _IblShadowsVoxelTracingPass {
    /**
     * The opacity of the shadow cast from the voxel grid
     */
    get voxelShadowOpacity() {
        return this._voxelShadowOpacity;
    }
    /**
     * The opacity of the shadow cast from the voxel grid
     */
    set voxelShadowOpacity(value) {
        this._voxelShadowOpacity = value;
    }
    /**
     * The opacity of the screen-space shadow
     */
    get ssShadowOpacity() {
        return this._ssShadowOpacity;
    }
    /**
     * The opacity of the screen-space shadow
     */
    set ssShadowOpacity(value) {
        this._ssShadowOpacity = value;
    }
    /**
     * The number of samples used in the screen space shadow pass.
     */
    get sssSamples() {
        return this._sssSamples;
    }
    /**
     * The number of samples used in the screen space shadow pass.
     */
    set sssSamples(value) {
        this._sssSamples = value;
    }
    /**
     * The stride used in the screen space shadow pass. This controls the distance between samples.
     */
    get sssStride() {
        return this._sssStride;
    }
    /**
     * The stride used in the screen space shadow pass. This controls the distance between samples.
     */
    set sssStride(value) {
        this._sssStride = value;
    }
    /**
     * The maximum distance that the screen-space shadow will be able to occlude.
     */
    get sssMaxDist() {
        return this._sssMaxDist;
    }
    /**
     * The maximum distance that the screen-space shadow will be able to occlude.
     */
    set sssMaxDist(value) {
        this._sssMaxDist = value;
    }
    /**
     * The thickness of the screen-space shadow
     */
    get sssThickness() {
        return this._sssThickness;
    }
    /**
     * The thickness of the screen-space shadow
     */
    set sssThickness(value) {
        this._sssThickness = value;
    }
    /**
     * The bias to apply to the voxel sampling in the direction of the surface normal of the geometry.
     */
    get voxelNormalBias() {
        return this._voxelNormalBias;
    }
    set voxelNormalBias(value) {
        this._voxelNormalBias = value;
    }
    /**
     * The bias to apply to the voxel sampling in the direction of the light.
     */
    get voxelDirectionBias() {
        return this._voxelDirectionBias;
    }
    set voxelDirectionBias(value) {
        this._voxelDirectionBias = value;
    }
    /**
     * The number of directions to sample for the voxel tracing.
     */
    get sampleDirections() {
        return this._sampleDirections;
    }
    /**
     * The number of directions to sample for the voxel tracing.
     */
    set sampleDirections(value) {
        this._sampleDirections = value;
    }
    /**
     * The current rotation of the environment map, in radians.
     */
    get envRotation() {
        return this._envRotation;
    }
    /**
     * The current rotation of the environment map, in radians.
     */
    set envRotation(value) {
        this._envRotation = value;
    }
    /**
     * Returns the output texture of the pass.
     * @returns The output texture.
     */
    getOutputTexture() {
        return this._outputTexture;
    }
    /**
     * Gets the debug pass post process. This will create the resources for the pass
     * if they don't already exist.
     * @returns The post process
     */
    getDebugPassPP() {
        if (!this._debugPassPP) {
            this._createDebugPass();
        }
        return this._debugPassPP;
    }
    /**
     * The name of the debug pass
     */
    get debugPassName() {
        return this._debugPassName;
    }
    /**
     * Set the matrix to use for scaling the world space to voxel space
     * @param matrix The matrix to use for scaling the world space to voxel space
     */
    setWorldScaleMatrix(matrix) {
        this._invWorldScaleMatrix = matrix;
    }
    /**
     * Render the shadows in color rather than black and white.
     * This is slightly more expensive than black and white shadows but can be much
     * more accurate when the strongest lights in the IBL are non-white.
     */
    set coloredShadows(value) {
        this._coloredShadows = value;
    }
    get coloredShadows() {
        return this._coloredShadows;
    }
    /**
     * Sets params that control the position and scaling of the debug display on the screen.
     * @param x Screen X offset of the debug display (0-1)
     * @param y Screen Y offset of the debug display (0-1)
     * @param widthScale X scale of the debug display (0-1)
     * @param heightScale Y scale of the debug display (0-1)
     */
    setDebugDisplayParams(x, y, widthScale, heightScale) {
        this._debugSizeParams.set(x, y, widthScale, heightScale);
    }
    /**
     * Creates the debug post process effect for this pass
     */
    _createDebugPass() {
        const isWebGPU = this._engine.isWebGPU;
        if (!this._debugPassPP) {
            const debugOptions = {
                width: this._engine.getRenderWidth(),
                height: this._engine.getRenderHeight(),
                uniforms: ["sizeParams"],
                samplers: ["debugSampler"],
                engine: this._engine,
                reusable: true,
                shaderLanguage: isWebGPU ? 1 /* ShaderLanguage.WGSL */ : 0 /* ShaderLanguage.GLSL */,
                extraInitializations: (useWebGPU, list) => {
                    if (useWebGPU) {
                        list.push(import('./iblShadowDebug.fragment-BJFf8S1x.esm.js'));
                    }
                    else {
                        list.push(import('./iblShadowDebug.fragment-BNh2chk1.esm.js'));
                    }
                },
            };
            this._debugPassPP = new PostProcess(this.debugPassName, "iblShadowDebug", debugOptions);
            this._debugPassPP.autoClear = false;
            this._debugPassPP.onApplyObservable.add((effect) => {
                // update the caustic texture with what we just rendered.
                effect.setTexture("debugSampler", this._outputTexture);
                effect.setVector4("sizeParams", this._debugSizeParams);
            });
        }
    }
    /**
     * Instantiates the shadow voxel-tracing pass
     * @param scene Scene to attach to
     * @param iblShadowsRenderPipeline The IBL shadows render pipeline
     * @returns The shadow voxel-tracing pass
     */
    constructor(scene, iblShadowsRenderPipeline) {
        this._voxelShadowOpacity = 1.0;
        this._sssSamples = 16;
        this._sssStride = 8;
        this._sssMaxDist = 0.05;
        this._sssThickness = 0.5;
        this._ssShadowOpacity = 1.0;
        this._cameraInvView = Matrix.Identity();
        this._cameraInvProj = Matrix.Identity();
        this._invWorldScaleMatrix = Matrix.Identity();
        this._frameId = 0;
        this._sampleDirections = 4;
        this._shadowParameters = new Vector4(0.0, 0.0, 0.0, 0.0);
        this._sssParameters = new Vector4(0.0, 0.0, 0.0, 0.0);
        this._opacityParameters = new Vector4(0.0, 0.0, 0.0, 0.0);
        this._voxelBiasParameters = new Vector4(0.0, 0.0, 0.0, 0.0);
        this._voxelNormalBias = 1.4;
        this._voxelDirectionBias = 1.75;
        /**
         * Is the effect enabled
         */
        this.enabled = true;
        /** Enable the debug view for this pass */
        this.debugEnabled = false;
        this._debugPassName = "Voxel Tracing Debug Pass";
        /** The default rotation of the environment map will align the shadows with the default lighting orientation */
        this._envRotation = 0.0;
        this._coloredShadows = false;
        this._debugVoxelMarchEnabled = false;
        this._debugSizeParams = new Vector4(0.0, 0.0, 0.0, 0.0);
        this._renderWhenGBufferReady = null;
        this._scene = scene;
        this._engine = scene.getEngine();
        this._renderPipeline = iblShadowsRenderPipeline;
        this._createTextures();
    }
    _createTextures() {
        const defines = this._createDefines();
        const isWebGPU = this._engine.isWebGPU;
        const textureOptions = {
            type: Constants.TEXTURETYPE_UNSIGNED_BYTE,
            format: Constants.TEXTUREFORMAT_RGBA,
            samplingMode: Constants.TEXTURE_NEAREST_SAMPLINGMODE,
            generateDepthBuffer: false,
            shaderLanguage: isWebGPU ? 1 /* ShaderLanguage.WGSL */ : 0 /* ShaderLanguage.GLSL */,
            extraInitializationsAsync: async () => {
                if (isWebGPU) {
                    await Promise.all([import('./iblShadowVoxelTracing.fragment-B4vTICnY.esm.js')]);
                }
                else {
                    await Promise.all([import('./iblShadowVoxelTracing.fragment-Ccwwp_3f.esm.js')]);
                }
            },
        };
        this._outputTexture = new ProceduralTexture("voxelTracingPass", {
            width: this._engine.getRenderWidth(),
            height: this._engine.getRenderHeight(),
        }, "iblShadowVoxelTracing", this._scene, textureOptions);
        this._outputTexture.refreshRate = -1;
        this._outputTexture.autoClear = false;
        this._outputTexture.defines = defines;
        // Need to set all the textures first so that the effect gets created with the proper uniforms.
        this._setBindings(this._scene.activeCamera);
        this._renderWhenGBufferReady = this._render.bind(this);
        // Don't start rendering until the first vozelization is done.
        this._renderPipeline.onVoxelizationCompleteObservable.addOnce(() => {
            this._scene.geometryBufferRenderer.getGBuffer().onAfterRenderObservable.add(this._renderWhenGBufferReady);
        });
    }
    _createDefines() {
        let defines = "";
        if (this._scene.useRightHandedSystem) {
            defines += "#define RIGHT_HANDED\n";
        }
        if (this._debugVoxelMarchEnabled) {
            defines += "#define VOXEL_MARCH_DIAGNOSTIC_INFO_OPTION 1u\n";
        }
        if (this._coloredShadows) {
            defines += "#define COLOR_SHADOWS 1u\n";
        }
        return defines;
    }
    _setBindings(camera) {
        this._outputTexture.defines = this._createDefines();
        this._outputTexture.setMatrix("viewMtx", camera.getViewMatrix());
        this._outputTexture.setMatrix("projMtx", camera.getProjectionMatrix());
        camera.getProjectionMatrix().invertToRef(this._cameraInvProj);
        camera.getViewMatrix().invertToRef(this._cameraInvView);
        this._outputTexture.setMatrix("invProjMtx", this._cameraInvProj);
        this._outputTexture.setMatrix("invViewMtx", this._cameraInvView);
        this._outputTexture.setMatrix("wsNormalizationMtx", this._invWorldScaleMatrix);
        this._frameId++;
        let rotation = 0.0;
        if (this._scene.environmentTexture) {
            rotation = this._scene.environmentTexture.rotationY ?? 0;
        }
        rotation = this._scene.useRightHandedSystem ? -(rotation + 0.5 * Math.PI) : rotation - 0.5 * Math.PI;
        rotation = rotation % (2.0 * Math.PI);
        this._shadowParameters.set(this._sampleDirections, this._frameId, 1.0, rotation);
        this._outputTexture.setVector4("shadowParameters", this._shadowParameters);
        const voxelGrid = this._renderPipeline._getVoxelGridTexture();
        const highestMip = Math.floor(Math.log2(voxelGrid.getSize().width));
        this._voxelBiasParameters.set(this._voxelNormalBias, this._voxelDirectionBias, highestMip, 0.0);
        this._outputTexture.setVector4("voxelBiasParameters", this._voxelBiasParameters);
        // SSS Options.
        this._sssParameters.set(this._sssSamples, this._sssStride, this._sssMaxDist, this._sssThickness);
        this._outputTexture.setVector4("sssParameters", this._sssParameters);
        this._opacityParameters.set(this._voxelShadowOpacity, this._ssShadowOpacity, 0.0, 0.0);
        this._outputTexture.setVector4("shadowOpacity", this._opacityParameters);
        this._outputTexture.setTexture("voxelGridSampler", voxelGrid);
        this._outputTexture.setTexture("blueNoiseSampler", this._renderPipeline._getNoiseTexture());
        const cdfGenerator = this._scene.iblCdfGenerator;
        if (!cdfGenerator) {
            Logger.Warn("IBLShadowsVoxelTracingPass: Can't bind for render because iblCdfGenerator is not enabled.");
            return false;
        }
        this._outputTexture.setTexture("icdfSampler", cdfGenerator.getIcdfTexture());
        if (this._coloredShadows && this._scene.environmentTexture) {
            this._outputTexture.setTexture("iblSampler", this._scene.environmentTexture);
        }
        const geometryBufferRenderer = this._scene.geometryBufferRenderer;
        if (!geometryBufferRenderer) {
            Logger.Warn("IBLShadowsVoxelTracingPass: Can't bind for render because GeometryBufferRenderer is not enabled.");
            return false;
        }
        const depthIndex = geometryBufferRenderer.getTextureIndex(GeometryBufferRenderer.SCREENSPACE_DEPTH_TEXTURE_TYPE);
        this._outputTexture.setTexture("depthSampler", geometryBufferRenderer.getGBuffer().textures[depthIndex]);
        const wnormalIndex = geometryBufferRenderer.getTextureIndex(GeometryBufferRenderer.NORMAL_TEXTURE_TYPE);
        this._outputTexture.setTexture("worldNormalSampler", geometryBufferRenderer.getGBuffer().textures[wnormalIndex]);
        return true;
    }
    _render() {
        if (this.enabled && this._outputTexture.isReady() && this._outputTexture.getEffect()?.isReady()) {
            if (this._setBindings(this._scene.activeCamera)) {
                this._outputTexture.render();
            }
        }
    }
    /**
     * Called by render pipeline when canvas resized.
     * @param scaleFactor The factor by which to scale the canvas size.
     */
    resize(scaleFactor = 1.0) {
        const newSize = {
            width: Math.max(1.0, Math.floor(this._engine.getRenderWidth() * scaleFactor)),
            height: Math.max(1.0, Math.floor(this._engine.getRenderHeight() * scaleFactor)),
        };
        // Don't resize if the size is the same as the current size.
        if (this._outputTexture.getSize().width === newSize.width && this._outputTexture.getSize().height === newSize.height) {
            return;
        }
        this._outputTexture.resize(newSize, false);
    }
    /**
     * Checks if the pass is ready
     * @returns true if the pass is ready
     */
    isReady() {
        return (this._outputTexture.isReady() &&
            !(this._debugPassPP && !this._debugPassPP.isReady()) &&
            this._scene.iblCdfGenerator &&
            this._scene.iblCdfGenerator.getIcdfTexture().isReady() &&
            this._renderPipeline._getVoxelGridTexture().isReady());
    }
    /**
     * Disposes the associated resources
     */
    dispose() {
        if (this._scene.geometryBufferRenderer && this._renderWhenGBufferReady) {
            const gBuffer = this._scene.geometryBufferRenderer.getGBuffer();
            gBuffer.onAfterRenderObservable.removeCallback(this._renderWhenGBufferReady);
        }
        this._outputTexture.dispose();
        if (this._debugPassPP) {
            this._debugPassPP.dispose();
        }
    }
}

/**
 * This should not be instanciated directly, as it is part of a scene component
 * @internal
 */
class _IblShadowsSpatialBlurPass {
    /**
     * Returns the output texture of the pass.
     * @returns The output texture.
     */
    getOutputTexture() {
        return this._outputTexture;
    }
    /**
     * Gets the debug pass post process
     * @returns The post process
     */
    getDebugPassPP() {
        if (!this._debugPassPP) {
            this._createDebugPass();
        }
        return this._debugPassPP;
    }
    /**
     * Sets the name of the debug pass
     */
    get debugPassName() {
        return this._debugPassName;
    }
    /**
     * The scale of the voxel grid in world space. This is used to scale the blur radius in world space.
     * @param scale The scale of the voxel grid in world space.
     */
    setWorldScale(scale) {
        this._worldScale = scale;
    }
    /**
     * Sets params that control the position and scaling of the debug display on the screen.
     * @param x Screen X offset of the debug display (0-1)
     * @param y Screen Y offset of the debug display (0-1)
     * @param widthScale X scale of the debug display (0-1)
     * @param heightScale Y scale of the debug display (0-1)
     */
    setDebugDisplayParams(x, y, widthScale, heightScale) {
        this._debugSizeParams.set(x, y, widthScale, heightScale);
    }
    /**
     * Creates the debug post process effect for this pass
     */
    _createDebugPass() {
        if (!this._debugPassPP) {
            const isWebGPU = this._engine.isWebGPU;
            const debugOptions = {
                width: this._engine.getRenderWidth(),
                height: this._engine.getRenderHeight(),
                textureFormat: Constants.TEXTUREFORMAT_RGBA,
                textureType: Constants.TEXTURETYPE_UNSIGNED_BYTE,
                samplingMode: Constants.TEXTURE_NEAREST_SAMPLINGMODE,
                uniforms: ["sizeParams"],
                samplers: ["debugSampler"],
                engine: this._engine,
                reusable: false,
                shaderLanguage: isWebGPU ? 1 /* ShaderLanguage.WGSL */ : 0 /* ShaderLanguage.GLSL */,
                extraInitializations: (useWebGPU, list) => {
                    if (useWebGPU) {
                        list.push(import('./iblShadowDebug.fragment-BJFf8S1x.esm.js'));
                    }
                    else {
                        list.push(import('./iblShadowDebug.fragment-BNh2chk1.esm.js'));
                    }
                },
            };
            this._debugPassPP = new PostProcess(this.debugPassName, "iblShadowDebug", debugOptions);
            this._debugPassPP.autoClear = false;
            this._debugPassPP.onApplyObservable.add((effect) => {
                // update the caustic texture with what we just rendered.
                effect.setTexture("debugSampler", this._outputTexture);
                effect.setVector4("sizeParams", this._debugSizeParams);
            });
        }
    }
    /**
     * Instanciates the importance sampling renderer
     * @param scene Scene to attach to
     * @param iblShadowsRenderPipeline The IBL shadows render pipeline
     * @returns The importance sampling renderer
     */
    constructor(scene, iblShadowsRenderPipeline) {
        this._worldScale = 1.0;
        this._blurParameters = new Vector4(0.0, 0.0, 0.0, 0.0);
        /**
         * Is the effect enabled
         */
        this.enabled = true;
        this._debugPassName = "Spatial Blur Debug Pass";
        /** Enable the debug view for this pass */
        this.debugEnabled = false;
        this._debugSizeParams = new Vector4(0.0, 0.0, 0.0, 0.0);
        this._renderWhenGBufferReady = null;
        this._scene = scene;
        this._engine = scene.getEngine();
        this._renderPipeline = iblShadowsRenderPipeline;
        this._createTextures();
    }
    _createTextures() {
        const isWebGPU = this._engine.isWebGPU;
        const textureOptions = {
            type: Constants.TEXTURETYPE_UNSIGNED_BYTE,
            format: Constants.TEXTUREFORMAT_RGBA,
            samplingMode: Constants.TEXTURE_NEAREST_SAMPLINGMODE,
            generateDepthBuffer: false,
            generateMipMaps: false,
            shaderLanguage: isWebGPU ? 1 /* ShaderLanguage.WGSL */ : 0 /* ShaderLanguage.GLSL */,
            extraInitializationsAsync: async () => {
                if (isWebGPU) {
                    await Promise.all([import('./iblShadowSpatialBlur.fragment-CM6QPqPX.esm.js')]);
                }
                else {
                    await Promise.all([import('./iblShadowSpatialBlur.fragment-C3XOZlPx.esm.js')]);
                }
            },
        };
        this._outputTexture = new ProceduralTexture("spatialBlurPass", {
            width: this._engine.getRenderWidth(),
            height: this._engine.getRenderHeight(),
        }, "iblShadowSpatialBlur", this._scene, textureOptions, false, false, Constants.TEXTURETYPE_UNSIGNED_BYTE);
        this._outputTexture.refreshRate = -1;
        this._outputTexture.autoClear = false;
        // Need to set all the textures first so that the effect gets created with the proper uniforms.
        this._setBindings();
        this._renderWhenGBufferReady = this._render.bind(this);
        // Don't start rendering until the first vozelization is done.
        this._renderPipeline.onVoxelizationCompleteObservable.addOnce(() => {
            this._scene.geometryBufferRenderer.getGBuffer().onAfterRenderObservable.add(this._renderWhenGBufferReady);
        });
    }
    _setBindings() {
        this._outputTexture.setTexture("voxelTracingSampler", this._renderPipeline._getVoxelTracingTexture());
        const iterationCount = 1;
        this._blurParameters.set(iterationCount, this._worldScale, 0.0, 0.0);
        this._outputTexture.setVector4("blurParameters", this._blurParameters);
        const geometryBufferRenderer = this._scene.geometryBufferRenderer;
        if (!geometryBufferRenderer) {
            return false;
        }
        const depthIndex = geometryBufferRenderer.getTextureIndex(GeometryBufferRenderer.SCREENSPACE_DEPTH_TEXTURE_TYPE);
        this._outputTexture.setTexture("depthSampler", geometryBufferRenderer.getGBuffer().textures[depthIndex]);
        const wnormalIndex = geometryBufferRenderer.getTextureIndex(GeometryBufferRenderer.NORMAL_TEXTURE_TYPE);
        this._outputTexture.setTexture("worldNormalSampler", geometryBufferRenderer.getGBuffer().textures[wnormalIndex]);
        return true;
    }
    _render() {
        if (this.enabled && this._outputTexture.isReady() && this._outputTexture.getEffect()?.isReady()) {
            if (this._setBindings()) {
                this._outputTexture.render();
            }
        }
    }
    /**
     * Called by render pipeline when canvas resized.
     * @param scaleFactor The factor by which to scale the canvas size.
     */
    resize(scaleFactor = 1.0) {
        const newSize = {
            width: Math.max(1.0, Math.floor(this._engine.getRenderWidth() * scaleFactor)),
            height: Math.max(1.0, Math.floor(this._engine.getRenderHeight() * scaleFactor)),
        };
        // Don't resize if the size is the same as the current size.
        if (this._outputTexture.getSize().width === newSize.width && this._outputTexture.getSize().height === newSize.height) {
            return;
        }
        this._outputTexture.resize(newSize, false);
    }
    /**
     * Checks if the pass is ready
     * @returns true if the pass is ready
     */
    isReady() {
        return this._outputTexture.isReady() && !(this._debugPassPP && !this._debugPassPP.isReady());
    }
    /**
     * Disposes the associated resources
     */
    dispose() {
        if (this._scene.geometryBufferRenderer && this._renderWhenGBufferReady) {
            const gBuffer = this._scene.geometryBufferRenderer.getGBuffer();
            gBuffer.onAfterRenderObservable.removeCallback(this._renderWhenGBufferReady);
        }
        this._outputTexture.dispose();
        if (this._debugPassPP) {
            this._debugPassPP.dispose();
        }
    }
}

/**
 * This should not be instantiated directly, as it is part of a scene component
 * @internal
 */
class _IblShadowsAccumulationPass {
    /**
     * Returns the output texture of the pass.
     * @returns The output texture.
     */
    getOutputTexture() {
        return this._outputTexture;
    }
    /**
     * Gets the debug pass post process
     * @returns The post process
     */
    getDebugPassPP() {
        if (!this._debugPassPP) {
            this._createDebugPass();
        }
        return this._debugPassPP;
    }
    /**
     * Gets the name of the debug pass
     * @returns The name of the debug pass
     */
    get debugPassName() {
        return this._debugPassName;
    }
    /**
     * A value that controls how much of the previous frame's accumulation to keep.
     * The higher the value, the faster the shadows accumulate but the more potential ghosting you'll see.
     */
    get remanence() {
        return this._remanence;
    }
    /**
     * A value that controls how much of the previous frame's accumulation to keep.
     * The higher the value, the faster the shadows accumulate but the more potential ghosting you'll see.
     */
    set remanence(value) {
        this._remanence = value;
    }
    /**
     * Reset the accumulation.
     */
    get reset() {
        return this._reset;
    }
    /**
     * Reset the accumulation.
     */
    set reset(value) {
        this._reset = value;
    }
    /**
     * Tell the pass that the camera is moving. This will cause the accumulation
     * rate to change.
     */
    set isMoving(value) {
        this._isMoving = value;
    }
    /**
     * Sets params that control the position and scaling of the debug display on the screen.
     * @param x Screen X offset of the debug display (0-1)
     * @param y Screen Y offset of the debug display (0-1)
     * @param widthScale X scale of the debug display (0-1)
     * @param heightScale Y scale of the debug display (0-1)
     */
    setDebugDisplayParams(x, y, widthScale, heightScale) {
        this._debugSizeParams.set(x, y, widthScale, heightScale);
    }
    /**
     * Creates the debug post process effect for this pass
     */
    _createDebugPass() {
        if (!this._debugPassPP) {
            const isWebGPU = this._engine.isWebGPU;
            const debugOptions = {
                width: this._engine.getRenderWidth(),
                height: this._engine.getRenderHeight(),
                textureFormat: Constants.TEXTUREFORMAT_RGBA,
                textureType: Constants.TEXTURETYPE_UNSIGNED_BYTE,
                samplingMode: Constants.TEXTURE_NEAREST_SAMPLINGMODE,
                uniforms: ["sizeParams"],
                samplers: ["debugSampler"],
                engine: this._engine,
                reusable: false,
                shaderLanguage: isWebGPU ? 1 /* ShaderLanguage.WGSL */ : 0 /* ShaderLanguage.GLSL */,
                extraInitializations: (useWebGPU, list) => {
                    if (useWebGPU) {
                        list.push(import('./iblShadowDebug.fragment-BJFf8S1x.esm.js'));
                    }
                    else {
                        list.push(import('./iblShadowDebug.fragment-BNh2chk1.esm.js'));
                    }
                },
            };
            this._debugPassPP = new PostProcess(this.debugPassName, "iblShadowDebug", debugOptions);
            this._debugPassPP.autoClear = false;
            this._debugPassPP.onApplyObservable.add((effect) => {
                // update the caustic texture with what we just rendered.
                effect.setTexture("debugSampler", this._outputTexture);
                effect.setVector4("sizeParams", this._debugSizeParams);
            });
        }
    }
    /**
     * Instantiates the accumulation pass
     * @param scene Scene to attach to
     * @param iblShadowsRenderPipeline The IBL shadows render pipeline
     * @returns The accumulation pass
     */
    constructor(scene, iblShadowsRenderPipeline) {
        this._accumulationParams = new Vector4(0.0, 0.0, 0.0, 0.0);
        /** Enable the debug view for this pass */
        this.debugEnabled = false;
        /**
         * Is the effect enabled
         */
        this.enabled = true;
        /**
         * Observable that triggers when the accumulation texture is ready
         */
        this.onReadyObservable = new Observable();
        this._debugPassName = "Shadow Accumulation Debug Pass";
        this._remanence = 0.9;
        this._reset = true;
        this._isMoving = false;
        this._debugSizeParams = new Vector4(0.0, 0.0, 0.0, 0.0);
        this._renderWhenGBufferReady = null;
        this._scene = scene;
        this._engine = scene.getEngine();
        this._renderPipeline = iblShadowsRenderPipeline;
        this._createTextures();
    }
    _createTextures() {
        const isWebGPU = this._engine.isWebGPU;
        const outputTextureOptions = {
            type: Constants.TEXTURETYPE_HALF_FLOAT,
            format: Constants.TEXTUREFORMAT_RGBA,
            samplingMode: Constants.TEXTURE_NEAREST_SAMPLINGMODE,
            generateDepthBuffer: false,
            generateMipMaps: false,
            shaderLanguage: isWebGPU ? 1 /* ShaderLanguage.WGSL */ : 0 /* ShaderLanguage.GLSL */,
            extraInitializationsAsync: async () => {
                if (isWebGPU) {
                    await Promise.all([import('./iblShadowAccumulation.fragment-B_xS-Nl5.esm.js')]);
                }
                else {
                    await Promise.all([import('./iblShadowAccumulation.fragment-DaKxONsW.esm.js')]);
                }
            },
        };
        this._outputTexture = new ProceduralTexture("shadowAccumulationPass", {
            width: this._engine.getRenderWidth(),
            height: this._engine.getRenderHeight(),
        }, "iblShadowAccumulation", this._scene, outputTextureOptions);
        this._outputTexture.refreshRate = 1;
        this._outputTexture.autoClear = false;
        this._outputTexture.onGeneratedObservable.addOnce(() => {
            this.onReadyObservable.notifyObservers();
        });
        // Need to set all the textures first so that the effect gets created with the proper uniforms.
        this._setOutputTextureBindings();
        this._renderWhenGBufferReady = this._render.bind(this);
        // Don't start rendering until the first vozelization is done.
        this._renderPipeline.onVoxelizationCompleteObservable.addOnce(() => {
            this._scene.geometryBufferRenderer.getGBuffer().onAfterRenderObservable.add(this._renderWhenGBufferReady);
        });
        // Create the accumulation texture for the previous frame.
        // We'll copy the output of the accumulation pass to this texture at the start of every frame.
        const accumulationOptions = {
            type: Constants.TEXTURETYPE_HALF_FLOAT,
            format: Constants.TEXTUREFORMAT_RGBA,
            samplingMode: Constants.TEXTURE_NEAREST_SAMPLINGMODE,
            generateDepthBuffer: false,
            generateMipMaps: false,
            shaderLanguage: isWebGPU ? 1 /* ShaderLanguage.WGSL */ : 0 /* ShaderLanguage.GLSL */,
            extraInitializationsAsync: async () => {
                if (isWebGPU) {
                    await Promise.all([import('./pass.fragment-DDzNjYH7.esm.js')]);
                }
                else {
                    await Promise.all([import('./pass.fragment-B86TCC95.esm.js')]);
                }
            },
        };
        this._oldAccumulationCopy = new ProceduralTexture("oldAccumulationRT", { width: this._engine.getRenderWidth(), height: this._engine.getRenderHeight() }, "pass", this._scene, accumulationOptions, false);
        this._oldAccumulationCopy.autoClear = false;
        this._oldAccumulationCopy.refreshRate = 1;
        this._oldAccumulationCopy.onBeforeGenerationObservable.add(this._setAccumulationCopyBindings.bind(this));
        this._setAccumulationCopyBindings();
        // Create the local position texture for the previous frame.
        // We'll copy the previous local position texture to this texture at the start of every frame.
        const localPositionOptions = {
            type: Constants.TEXTURETYPE_HALF_FLOAT,
            format: Constants.TEXTUREFORMAT_RGBA,
            samplingMode: Constants.TEXTURE_NEAREST_SAMPLINGMODE,
            generateDepthBuffer: false,
            generateMipMaps: false,
            shaderLanguage: isWebGPU ? 1 /* ShaderLanguage.WGSL */ : 0 /* ShaderLanguage.GLSL */,
            extraInitializationsAsync: async () => {
                if (isWebGPU) {
                    await Promise.all([import('./pass.fragment-DDzNjYH7.esm.js')]);
                }
                else {
                    await Promise.all([import('./pass.fragment-B86TCC95.esm.js')]);
                }
            },
        };
        this._oldPositionCopy = new ProceduralTexture("oldLocalPositionRT", { width: this._engine.getRenderWidth(), height: this._engine.getRenderHeight() }, "pass", this._scene, localPositionOptions, false);
        this._updatePositionCopy();
        this._oldPositionCopy.autoClear = false;
        this._oldPositionCopy.refreshRate = 1;
        this._oldPositionCopy.onBeforeGenerationObservable.add(this._updatePositionCopy.bind(this));
    }
    _setOutputTextureBindings() {
        const remanence = this._isMoving ? this.remanence : 0.99;
        this._accumulationParams.set(remanence, this.reset ? 1.0 : 0.0, this._renderPipeline.voxelGridSize, 0.0);
        this._outputTexture.setTexture("spatialBlurSampler", this._renderPipeline._getSpatialBlurTexture());
        this._outputTexture.setVector4("accumulationParameters", this._accumulationParams);
        this._outputTexture.setTexture("oldAccumulationSampler", this._oldAccumulationCopy ? this._oldAccumulationCopy : this._renderPipeline._dummyTexture2d);
        this._outputTexture.setTexture("prevPositionSampler", this._oldPositionCopy ? this._oldPositionCopy : this._renderPipeline._dummyTexture2d);
        const geometryBufferRenderer = this._scene.geometryBufferRenderer;
        if (!geometryBufferRenderer) {
            return false;
        }
        const velocityIndex = geometryBufferRenderer.getTextureIndex(GeometryBufferRenderer.VELOCITY_LINEAR_TEXTURE_TYPE);
        this._outputTexture.setTexture("motionSampler", geometryBufferRenderer.getGBuffer().textures[velocityIndex]);
        const wPositionIndex = geometryBufferRenderer.getTextureIndex(GeometryBufferRenderer.POSITION_TEXTURE_TYPE);
        this._outputTexture.setTexture("positionSampler", geometryBufferRenderer.getGBuffer().textures[wPositionIndex]);
        this.reset = false;
        this._isMoving = false;
        return true;
    }
    _updatePositionCopy() {
        const geometryBufferRenderer = this._scene.geometryBufferRenderer;
        const index = geometryBufferRenderer.getTextureIndex(GeometryBufferRenderer.POSITION_TEXTURE_TYPE);
        this._oldPositionCopy.setTexture("textureSampler", geometryBufferRenderer.getGBuffer().textures[index]);
    }
    _setAccumulationCopyBindings() {
        this._oldAccumulationCopy.setTexture("textureSampler", this._outputTexture);
    }
    _render() {
        if (this.enabled && this._outputTexture.isReady() && this._outputTexture.getEffect()?.isReady()) {
            if (this._setOutputTextureBindings()) {
                this._outputTexture.render();
            }
        }
    }
    /**
     * Called by render pipeline when canvas resized.
     * @param scaleFactor The factor by which to scale the canvas size.
     */
    resize(scaleFactor = 1.0) {
        const newSize = {
            width: Math.max(1.0, Math.floor(this._engine.getRenderWidth() * scaleFactor)),
            height: Math.max(1.0, Math.floor(this._engine.getRenderHeight() * scaleFactor)),
        };
        // Don't resize if the size is the same as the current size.
        if (this._outputTexture.getSize().width === newSize.width && this._outputTexture.getSize().height === newSize.height) {
            return;
        }
        this._outputTexture.resize(newSize, false);
        this._oldAccumulationCopy.resize(newSize, false);
        this._oldPositionCopy.resize({ width: this._engine.getRenderWidth(), height: this._engine.getRenderHeight() }, false);
        this.reset = true;
    }
    _disposeTextures() {
        this._oldAccumulationCopy.dispose();
        this._oldPositionCopy.dispose();
        this._outputTexture.dispose();
    }
    /**
     * Checks if the pass is ready
     * @returns true if the pass is ready
     */
    isReady() {
        return (this._oldAccumulationCopy &&
            this._oldAccumulationCopy.isReady() &&
            this._oldPositionCopy &&
            this._oldPositionCopy.isReady() &&
            this._outputTexture.isReady() &&
            !(this._debugPassPP && !this._debugPassPP.isReady()));
    }
    /**
     * Disposes the associated resources
     */
    dispose() {
        if (this._scene.geometryBufferRenderer && this._renderWhenGBufferReady) {
            const gBuffer = this._scene.geometryBufferRenderer.getGBuffer();
            gBuffer.onAfterRenderObservable.removeCallback(this._renderWhenGBufferReady);
        }
        this._disposeTextures();
        if (this._debugPassPP) {
            this._debugPassPP.dispose();
        }
        this.onReadyObservable.clear();
    }
}

/**
 * PostProcessRenderPipeline
 * @see https://doc.babylonjs.com/features/featuresDeepDive/postProcesses/postProcessRenderPipeline
 */
class PostProcessRenderPipeline {
    /**
     * Gets pipeline name
     */
    get name() {
        return this._name;
    }
    /** Gets the list of attached cameras */
    get cameras() {
        return this._cameras;
    }
    /**
     * Gets the active engine
     */
    get engine() {
        return this._engine;
    }
    /**
     * Initializes a PostProcessRenderPipeline
     * @param _engine engine to add the pipeline to
     * @param name name of the pipeline
     */
    constructor(_engine, name) {
        this._engine = _engine;
        /**
         * Gets the unique id of the post process rendering pipeline
         */
        this.uniqueId = UniqueIdGenerator.UniqueId;
        this._name = name;
        this._renderEffects = {};
        this._renderEffectsForIsolatedPass = new Array();
        this._cameras = [];
    }
    /**
     * Gets the class name
     * @returns "PostProcessRenderPipeline"
     */
    getClassName() {
        return "PostProcessRenderPipeline";
    }
    /**
     * If all the render effects in the pipeline are supported
     */
    get isSupported() {
        for (const renderEffectName in this._renderEffects) {
            if (Object.prototype.hasOwnProperty.call(this._renderEffects, renderEffectName)) {
                if (!this._renderEffects[renderEffectName].isSupported) {
                    return false;
                }
            }
        }
        return true;
    }
    /**
     * Adds an effect to the pipeline
     * @param renderEffect the effect to add
     */
    addEffect(renderEffect) {
        this._renderEffects[renderEffect._name] = renderEffect;
    }
    // private
    /** @internal */
    _rebuild() { }
    /**
     * @internal
     */
    _enableEffect(renderEffectName, cameras) {
        const renderEffects = this._renderEffects[renderEffectName];
        if (!renderEffects) {
            return;
        }
        renderEffects._enable(Tools.MakeArray(cameras || this._cameras));
    }
    /**
     * @internal
     */
    _disableEffect(renderEffectName, cameras) {
        const renderEffects = this._renderEffects[renderEffectName];
        if (!renderEffects) {
            return;
        }
        renderEffects._disable(Tools.MakeArray(cameras || this._cameras));
    }
    /**
     * @internal
     */
    _attachCameras(cameras, unique) {
        const cams = Tools.MakeArray(cameras || this._cameras);
        if (!cams) {
            return;
        }
        const indicesToDelete = [];
        let i;
        for (i = 0; i < cams.length; i++) {
            const camera = cams[i];
            if (!camera) {
                continue;
            }
            if (this._cameras.indexOf(camera) === -1) {
                this._cameras.push(camera);
            }
            else if (unique) {
                indicesToDelete.push(i);
            }
        }
        for (i = 0; i < indicesToDelete.length; i++) {
            cams.splice(indicesToDelete[i], 1);
        }
        for (const renderEffectName in this._renderEffects) {
            if (Object.prototype.hasOwnProperty.call(this._renderEffects, renderEffectName)) {
                this._renderEffects[renderEffectName]._attachCameras(cams);
            }
        }
    }
    /**
     * @internal
     */
    _detachCameras(cameras) {
        const cams = Tools.MakeArray(cameras || this._cameras);
        if (!cams) {
            return;
        }
        for (const renderEffectName in this._renderEffects) {
            if (Object.prototype.hasOwnProperty.call(this._renderEffects, renderEffectName)) {
                this._renderEffects[renderEffectName]._detachCameras(cams);
            }
        }
        for (let i = 0; i < cams.length; i++) {
            this._cameras.splice(this._cameras.indexOf(cams[i]), 1);
        }
    }
    /** @internal */
    _update() {
        for (const renderEffectName in this._renderEffects) {
            if (Object.prototype.hasOwnProperty.call(this._renderEffects, renderEffectName)) {
                this._renderEffects[renderEffectName]._update();
            }
        }
        for (let i = 0; i < this._cameras.length; i++) {
            if (!this._cameras[i]) {
                continue;
            }
            const cameraName = this._cameras[i].name;
            if (this._renderEffectsForIsolatedPass[cameraName]) {
                this._renderEffectsForIsolatedPass[cameraName]._update();
            }
        }
    }
    /** @internal */
    _reset() {
        this._renderEffects = {};
        this._renderEffectsForIsolatedPass = new Array();
    }
    _enableMSAAOnFirstPostProcess(sampleCount) {
        if (!this._engine._features.supportMSAA) {
            return false;
        }
        // Set samples of the very first post process to 4 to enable native anti-aliasing in browsers that support webGL 2.0 (See: https://github.com/BabylonJS/Babylon.js/issues/3754)
        const effectKeys = Object.keys(this._renderEffects);
        if (effectKeys.length > 0) {
            const postProcesses = this._renderEffects[effectKeys[0]].getPostProcesses();
            if (postProcesses) {
                postProcesses[0].samples = sampleCount;
            }
        }
        return true;
    }
    /**
     * Ensures that all post processes in the pipeline are the correct size according to the
     * the viewport's required size
     */
    _adaptPostProcessesToViewPort() {
        const effectKeys = Object.keys(this._renderEffects);
        for (const effectKey of effectKeys) {
            const postProcesses = this._renderEffects[effectKey].getPostProcesses();
            if (postProcesses) {
                for (const postProcess of postProcesses) {
                    postProcess.adaptScaleToCurrentViewport = true;
                }
            }
        }
    }
    /**
     * Sets the required values to the prepass renderer.
     * @param prePassRenderer defines the prepass renderer to setup.
     * @returns true if the pre pass is needed.
     */
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    setPrePassRenderer(prePassRenderer) {
        // Do Nothing by default
        return false;
    }
    /**
     * Disposes of the pipeline
     */
    dispose() {
        // Must be implemented by children
    }
}
__decorate([
    serialize()
], PostProcessRenderPipeline.prototype, "_name", void 0);

/**
 * This represents a set of one or more post processes in Babylon.
 * A post process can be used to apply a shader to a texture after it is rendered.
 * @example https://doc.babylonjs.com/features/featuresDeepDive/postProcesses/postProcessRenderPipeline
 */
class PostProcessRenderEffect {
    /**
     * Instantiates a post process render effect.
     * A post process can be used to apply a shader to a texture after it is rendered.
     * @param engine The engine the effect is tied to
     * @param name The name of the effect
     * @param getPostProcesses A function that returns a set of post processes which the effect will run in order to be run.
     * @param singleInstance False if this post process can be run on multiple cameras. (default: true)
     */
    constructor(engine, name, getPostProcesses, singleInstance = true) {
        this._name = name;
        this._singleInstance = singleInstance;
        this._getPostProcesses = getPostProcesses;
        this._cameras = {};
        this._indicesForCamera = {};
        this._postProcesses = {};
    }
    /**
     * Checks if all the post processes in the effect are supported.
     */
    get isSupported() {
        for (const index in this._postProcesses) {
            if (Object.prototype.hasOwnProperty.call(this._postProcesses, index)) {
                const pps = this._postProcesses[index];
                for (let ppIndex = 0; ppIndex < pps.length; ppIndex++) {
                    if (!pps[ppIndex].isSupported) {
                        return false;
                    }
                }
            }
        }
        return true;
    }
    /**
     * Updates the current state of the effect
     * @internal
     */
    _update() { }
    /**
     * Attaches the effect on cameras
     * @param cameras The camera to attach to.
     * @internal
     */
    _attachCameras(cameras) {
        let cameraKey;
        const cams = Tools.MakeArray(cameras || this._cameras);
        if (!cams) {
            return;
        }
        for (let i = 0; i < cams.length; i++) {
            const camera = cams[i];
            if (!camera) {
                continue;
            }
            const cameraName = camera.name;
            if (this._singleInstance) {
                cameraKey = 0;
            }
            else {
                cameraKey = cameraName;
            }
            if (!this._postProcesses[cameraKey]) {
                const postProcess = this._getPostProcesses();
                if (postProcess) {
                    this._postProcesses[cameraKey] = Array.isArray(postProcess) ? postProcess : [postProcess];
                }
            }
            if (!this._indicesForCamera[cameraName]) {
                this._indicesForCamera[cameraName] = [];
            }
            const pps = this._postProcesses[cameraKey];
            for (const postProcess of pps) {
                const index = camera.attachPostProcess(postProcess);
                this._indicesForCamera[cameraName].push(index);
            }
            if (!this._cameras[cameraName]) {
                this._cameras[cameraName] = camera;
            }
        }
    }
    /**
     * Detaches the effect on cameras
     * @param cameras The camera to detach from.
     * @internal
     */
    _detachCameras(cameras) {
        const cams = Tools.MakeArray(cameras || this._cameras);
        if (!cams) {
            return;
        }
        for (let i = 0; i < cams.length; i++) {
            const camera = cams[i];
            const cameraName = camera.name;
            const postProcesses = this._postProcesses[this._singleInstance ? 0 : cameraName];
            if (postProcesses) {
                for (const postProcess of postProcesses) {
                    camera.detachPostProcess(postProcess);
                }
            }
            if (this._cameras[cameraName]) {
                this._cameras[cameraName] = null;
            }
            delete this._indicesForCamera[cameraName];
        }
    }
    /**
     * Enables the effect on given cameras
     * @param cameras The camera to enable.
     * @internal
     */
    _enable(cameras) {
        const cams = Tools.MakeArray(cameras || this._cameras);
        if (!cams) {
            return;
        }
        for (let i = 0; i < cams.length; i++) {
            const camera = cams[i];
            const cameraName = camera.name;
            const cameraKey = this._singleInstance ? 0 : cameraName;
            for (let j = 0; j < this._indicesForCamera[cameraName].length; j++) {
                const index = this._indicesForCamera[cameraName][j];
                const postProcess = camera._postProcesses[index];
                if (postProcess === undefined || postProcess === null) {
                    cams[i].attachPostProcess(this._postProcesses[cameraKey][j], index);
                }
            }
        }
    }
    /**
     * Disables the effect on the given cameras
     * @param cameras The camera to disable.
     * @internal
     */
    _disable(cameras) {
        const cams = Tools.MakeArray(cameras || this._cameras);
        if (!cams) {
            return;
        }
        for (let i = 0; i < cams.length; i++) {
            const camera = cams[i];
            const cameraName = camera.name;
            const pps = this._postProcesses[this._singleInstance ? 0 : cameraName];
            for (const postProcess of pps) {
                camera.detachPostProcess(postProcess);
            }
        }
    }
    /**
     * Gets a list of the post processes contained in the effect.
     * @param camera The camera to get the post processes on.
     * @returns The list of the post processes in the effect.
     */
    getPostProcesses(camera) {
        if (this._singleInstance) {
            return this._postProcesses[0];
        }
        else {
            if (!camera) {
                return null;
            }
            return this._postProcesses[camera.name];
        }
    }
}

/**
 * Class used to store 3D textures containing user data
 */
class RawTexture3D extends Texture {
    /**
     * Gets the width of the texture
     */
    get width() {
        return this._texture ? this._texture.width : 0;
    }
    /**
     * Gets the height of the texture
     */
    get height() {
        return this._texture ? this._texture.height : 0;
    }
    /**
     * Gets the depth of the texture
     */
    get depth() {
        return this._texture ? this._texture.depth : 0;
    }
    /**
     * Create a new RawTexture3D
     * @param data defines the data of the texture
     * @param width defines the width of the texture
     * @param height defines the height of the texture
     * @param depth defines the depth of the texture
     * @param format defines the texture format to use
     * @param scene defines the hosting scene
     * @param generateMipMaps defines a boolean indicating if mip levels should be generated (true by default)
     * @param invertY defines if texture must be stored with Y axis inverted
     * @param samplingMode defines the sampling mode to use (Texture.TRILINEAR_SAMPLINGMODE by default)
     * @param textureType defines the texture Type (Engine.TEXTURETYPE_UNSIGNED_BYTE, Engine.TEXTURETYPE_FLOAT...)
     * @param creationFlags specific flags to use when creating the texture (Constants.TEXTURE_CREATIONFLAG_STORAGE for storage textures, for eg)
     */
    constructor(data, width, height, depth, 
    /** Gets or sets the texture format to use */
    format, scene, generateMipMaps = true, invertY = false, samplingMode = Texture.TRILINEAR_SAMPLINGMODE, textureType = Constants.TEXTURETYPE_UNSIGNED_BYTE, creationFlags) {
        super(null, scene, !generateMipMaps, invertY);
        this.format = format;
        this._texture = scene.getEngine().createRawTexture3D(data, width, height, depth, format, generateMipMaps, invertY, samplingMode, null, textureType, creationFlags);
        this.is3D = true;
    }
    /**
     * Update the texture with new data
     * @param data defines the data to store in the texture
     */
    update(data) {
        if (!this._texture) {
            return;
        }
        this._getEngine().updateRawTexture3D(this._texture, data, this._texture.format, this._texture.invertY, null, this._texture.type);
    }
}

/**
 * @internal
 */
class MaterialIBLShadowsRenderDefines extends MaterialDefines {
    constructor() {
        super(...arguments);
        this.RENDER_WITH_IBL_SHADOWS = false;
        this.COLORED_IBL_SHADOWS = false;
    }
}
/**
 * Plugin used to render the contribution from IBL shadows.
 */
class IBLShadowsPluginMaterial extends MaterialPluginBase {
    get isColored() {
        return this._isColored;
    }
    set isColored(value) {
        if (this._isColored === value) {
            return;
        }
        this._isColored = value;
        this._markAllSubMeshesAsTexturesDirty();
    }
    _markAllSubMeshesAsTexturesDirty() {
        this._enable(this._isEnabled);
        this._internalMarkAllSubMeshesAsTexturesDirty();
    }
    /**
     * Gets a boolean indicating that the plugin is compatible with a give shader language.
     * @returns true if the plugin is compatible with the shader language
     */
    isCompatible() {
        return true;
    }
    constructor(material) {
        super(material, IBLShadowsPluginMaterial.Name, 310, new MaterialIBLShadowsRenderDefines());
        /**
         * The opacity of the shadows.
         */
        this.shadowOpacity = 1.0;
        this._isEnabled = false;
        this._isColored = false;
        /**
         * Defines if the plugin is enabled in the material.
         */
        this.isEnabled = false;
        this._internalMarkAllSubMeshesAsTexturesDirty = material._dirtyCallbacks[Constants.MATERIAL_TextureDirtyFlag];
    }
    prepareDefines(defines) {
        defines.RENDER_WITH_IBL_SHADOWS = this._isEnabled;
        defines.COLORED_IBL_SHADOWS = this.isColored;
    }
    getClassName() {
        return "IBLShadowsPluginMaterial";
    }
    getUniforms() {
        return {
            ubo: [
                { name: "renderTargetSize", size: 2, type: "vec2" },
                { name: "shadowOpacity", size: 1, type: "float" },
            ],
            fragment: `#ifdef RENDER_WITH_IBL_SHADOWS
                    uniform vec2 renderTargetSize;
                    uniform float shadowOpacity;
                #endif`,
        };
    }
    getSamplers(samplers) {
        samplers.push("iblShadowsTexture");
    }
    bindForSubMesh(uniformBuffer) {
        if (this._isEnabled) {
            uniformBuffer.bindTexture("iblShadowsTexture", this.iblShadowsTexture);
            uniformBuffer.updateFloat2("renderTargetSize", this._material.getScene().getEngine().getRenderWidth(), this._material.getScene().getEngine().getRenderHeight());
            uniformBuffer.updateFloat("shadowOpacity", this.shadowOpacity);
        }
    }
    getCustomCode(shaderType, shaderLanguage) {
        let frag;
        if (shaderLanguage === 1 /* ShaderLanguage.WGSL */) {
            frag = {
                // eslint-disable-next-line @typescript-eslint/naming-convention
                CUSTOM_FRAGMENT_DEFINITIONS: `
                #ifdef RENDER_WITH_IBL_SHADOWS
                    var iblShadowsTextureSampler: sampler;
                    var iblShadowsTexture: texture_2d<f32>;

                    #ifdef COLORED_IBL_SHADOWS
                        fn computeIndirectShadow() -> vec3f {
                            var uv = fragmentInputs.position.xy / uniforms.renderTargetSize;
                            var shadowValue: vec3f = textureSample(iblShadowsTexture, iblShadowsTextureSampler, uv).rgb;
                            return mix(shadowValue, vec3f(1.0), 1.0 - uniforms.shadowOpacity);
                        }
                    #else
                        fn computeIndirectShadow() -> vec2f {
                            var uv = fragmentInputs.position.xy / uniforms.renderTargetSize;
                            var shadowValue: vec2f = textureSample(iblShadowsTexture, iblShadowsTextureSampler, uv).rg;
                            return mix(shadowValue, vec2f(1.0), 1.0 - uniforms.shadowOpacity);
                        }
                    #endif
                #endif
            `,
            };
            if (this._material instanceof PBRBaseMaterial) {
                // eslint-disable-next-line @typescript-eslint/naming-convention
                frag["CUSTOM_FRAGMENT_BEFORE_FINALCOLORCOMPOSITION"] = `
                #ifdef RENDER_WITH_IBL_SHADOWS
                    #ifndef UNLIT
                        #ifdef REFLECTION
                            #ifdef COLORED_IBL_SHADOWS
                                var shadowValue: vec3f = computeIndirectShadow();
                                finalIrradiance *= shadowValue;
                                finalRadianceScaled *= mix(vec3f(1.0), shadowValue, roughness);
                            #else
                                var shadowValue: vec2f = computeIndirectShadow();
                                finalIrradiance *= vec3f(shadowValue.x);
                                finalRadianceScaled *= vec3f(mix(pow(shadowValue.y, 4.0), shadowValue.x, roughness));
                            #endif
                        #endif
                    #else
                        finalDiffuse *= computeIndirectShadow().x;
                    #endif
                #endif
            `;
            }
            else {
                frag["CUSTOM_FRAGMENT_BEFORE_FRAGCOLOR"] = `
                #ifdef RENDER_WITH_IBL_SHADOWS
                    #ifdef COLORED_IBL_SHADOWS
                        var shadowValue: vec3f = computeIndirectShadow();
                        color *= toGammaSpace(vec4f(shadowValue, 1.0f));
                    #else
                        var shadowValue: vec2f = computeIndirectShadow();
                        color *= toGammaSpace(vec4f(shadowValue.x, shadowValue.x, shadowValue.x, 1.0f));
                    #endif
                #endif
            `;
            }
        }
        else {
            frag = {
                // eslint-disable-next-line @typescript-eslint/naming-convention
                CUSTOM_FRAGMENT_DEFINITIONS: `
                #ifdef RENDER_WITH_IBL_SHADOWS
                    uniform sampler2D iblShadowsTexture;
                #ifdef COLORED_IBL_SHADOWS
                    vec3 computeIndirectShadow() {
                        vec2 uv = gl_FragCoord.xy / renderTargetSize;
                        vec3 shadowValue = texture2D(iblShadowsTexture, uv).rgb;
                        return mix(shadowValue.rgb, vec3(1.0), 1.0 - shadowOpacity);
                    }
                #else
                    vec2 computeIndirectShadow() {
                        vec2 uv = gl_FragCoord.xy / renderTargetSize;
                        vec2 shadowValue = texture2D(iblShadowsTexture, uv).rg;
                        return mix(shadowValue.rg, vec2(1.0), 1.0 - shadowOpacity);
                    }
                #endif
                #endif
            `,
            };
            if (this._material instanceof PBRBaseMaterial) {
                // eslint-disable-next-line @typescript-eslint/naming-convention
                frag["CUSTOM_FRAGMENT_BEFORE_FINALCOLORCOMPOSITION"] = `
                #ifdef RENDER_WITH_IBL_SHADOWS
                    #ifndef UNLIT
                        #ifdef REFLECTION
                            #ifdef COLORED_IBL_SHADOWS
                                vec3 shadowValue = computeIndirectShadow();
                                finalIrradiance.rgb *= shadowValue.rgb;
                                finalRadianceScaled *= mix(vec3(1.0), shadowValue.rgb, roughness);
                            #else
                                vec2 shadowValue = computeIndirectShadow();
                                finalIrradiance *= shadowValue.x;
                                finalRadianceScaled *= mix(pow(shadowValue.y, 4.0), shadowValue.x, roughness);
                            #endif
                        #endif
                    #else
                        finalDiffuse *= computeIndirectShadow().x;
                    #endif
                #endif
            `;
            }
            else {
                frag["CUSTOM_FRAGMENT_BEFORE_FRAGCOLOR"] = `
                #ifdef RENDER_WITH_IBL_SHADOWS
                    #ifdef COLORED_IBL_SHADOWS
                        vec3 shadowValue = computeIndirectShadow();
                        color.rgb *= toGammaSpace(shadowValue.rgb);
                    #else
                        vec2 shadowValue = computeIndirectShadow();
                        color.rgb *= toGammaSpace(shadowValue.x);
                    #endif
                #endif
            `;
            }
        }
        return shaderType === "vertex" ? null : frag;
    }
}
/**
 * Defines the name of the plugin.
 */
IBLShadowsPluginMaterial.Name = "IBLShadowsPluginMaterial";
__decorate([
    serialize()
], IBLShadowsPluginMaterial.prototype, "shadowOpacity", void 0);
__decorate([
    serialize(),
    expandToProperty("_markAllSubMeshesAsTexturesDirty")
], IBLShadowsPluginMaterial.prototype, "isEnabled", void 0);
RegisterClass(`BABYLON.IBLShadowsPluginMaterial`, IBLShadowsPluginMaterial);

Object.defineProperty(Scene.prototype, "geometryBufferRenderer", {
    get: function () {
        return this._geometryBufferRenderer;
    },
    set: function (value) {
        if (value && value.isSupported) {
            this._geometryBufferRenderer = value;
        }
    },
    enumerable: true,
    configurable: true,
});
Scene.prototype.enableGeometryBufferRenderer = function (ratio = 1, depthFormat = Constants.TEXTUREFORMAT_DEPTH16, textureTypesAndFormats) {
    if (this._geometryBufferRenderer) {
        return this._geometryBufferRenderer;
    }
    this._geometryBufferRenderer = new GeometryBufferRenderer(this, ratio, depthFormat, textureTypesAndFormats);
    if (!this._geometryBufferRenderer.isSupported) {
        this._geometryBufferRenderer = null;
    }
    return this._geometryBufferRenderer;
};
Scene.prototype.disableGeometryBufferRenderer = function () {
    if (!this._geometryBufferRenderer) {
        return;
    }
    this._geometryBufferRenderer.dispose();
    this._geometryBufferRenderer = null;
};
/**
 * Defines the Geometry Buffer scene component responsible to manage a G-Buffer useful
 * in several rendering techniques.
 */
class GeometryBufferRendererSceneComponent {
    /**
     * Creates a new instance of the component for the given scene
     * @param scene Defines the scene to register the component in
     */
    constructor(scene) {
        /**
         * The component name helpful to identify the component in the list of scene components.
         */
        this.name = SceneComponentConstants.NAME_GEOMETRYBUFFERRENDERER;
        this.scene = scene;
    }
    /**
     * Registers the component in a given scene
     */
    register() {
        this.scene._gatherRenderTargetsStage.registerStep(SceneComponentConstants.STEP_GATHERRENDERTARGETS_GEOMETRYBUFFERRENDERER, this, this._gatherRenderTargets);
    }
    /**
     * Rebuilds the elements related to this component in case of
     * context lost for instance.
     */
    rebuild() {
        // Nothing to do for this component
    }
    /**
     * Disposes the component and the associated resources
     */
    dispose() {
        // Nothing to do for this component
    }
    _gatherRenderTargets(renderTargets) {
        if (this.scene._geometryBufferRenderer) {
            renderTargets.push(this.scene._geometryBufferRenderer.getGBuffer());
        }
    }
}
GeometryBufferRenderer._SceneComponentInitialization = (scene) => {
    // Register the G Buffer component to the scene.
    let component = scene._getComponent(SceneComponentConstants.NAME_GEOMETRYBUFFERRENDERER);
    if (!component) {
        component = new GeometryBufferRendererSceneComponent(scene);
        scene._addComponent(component);
    }
};

/**
 * Voxel-based shadow rendering for IBL's.
 * This should not be instanciated directly, as it is part of a scene component
 */
class IblShadowsRenderPipeline extends PostProcessRenderPipeline {
    /**
     * Reset the shadow accumulation. This has a similar affect to lowering the remanence for a single frame.
     * This is useful when making a sudden change to the IBL.
     */
    resetAccumulation() {
        this._accumulationPass.reset = true;
    }
    /**
     * How dark the shadows appear. 1.0 is full opacity, 0.0 is no shadows.
     */
    get shadowOpacity() {
        return this._shadowOpacity;
    }
    set shadowOpacity(value) {
        this._shadowOpacity = value;
        this._setPluginParameters();
    }
    /**
     * Render the shadows in color rather than black and white.
     * This is slightly more expensive than black and white shadows but can be much
     * more accurate when the strongest lights in the IBL are non-white.
     */
    get coloredShadows() {
        return this._coloredShadows;
    }
    set coloredShadows(value) {
        this._coloredShadows = value;
        this._voxelTracingPass.coloredShadows = value;
        this._setPluginParameters();
    }
    /**
     * A multiplier for the render size of the shadows. Used for rendering lower-resolution shadows.
     */
    get shadowRenderSizeFactor() {
        return this._renderSizeFactor;
    }
    set shadowRenderSizeFactor(value) {
        this._renderSizeFactor = Math.max(Math.min(value, 1.0), 0.0);
        this._voxelTracingPass.resize(value);
        this._spatialBlurPass.resize(value);
        this._accumulationPass.resize(value);
        this._setPluginParameters();
    }
    /**
     * How dark the voxel shadows appear. 1.0 is full opacity, 0.0 is no shadows.
     */
    get voxelShadowOpacity() {
        return this._voxelTracingPass?.voxelShadowOpacity;
    }
    set voxelShadowOpacity(value) {
        if (!this._voxelTracingPass) {
            return;
        }
        this._voxelTracingPass.voxelShadowOpacity = value;
    }
    /**
     * How dark the screen-space shadows appear. 1.0 is full opacity, 0.0 is no shadows.
     */
    get ssShadowOpacity() {
        return this._voxelTracingPass?.ssShadowOpacity;
    }
    set ssShadowOpacity(value) {
        if (!this._voxelTracingPass) {
            return;
        }
        this._voxelTracingPass.ssShadowOpacity = value;
    }
    /**
     * The number of samples used in the screen space shadow pass.
     */
    get ssShadowSampleCount() {
        return this._voxelTracingPass?.sssSamples;
    }
    set ssShadowSampleCount(value) {
        if (!this._voxelTracingPass) {
            return;
        }
        this._voxelTracingPass.sssSamples = value;
    }
    /**
     * The stride of the screen-space shadow pass. This controls the distance between samples
     * in pixels.
     */
    get ssShadowStride() {
        return this._voxelTracingPass?.sssStride;
    }
    set ssShadowStride(value) {
        if (!this._voxelTracingPass) {
            return;
        }
        this._voxelTracingPass.sssStride = value;
    }
    /**
     * A scale for the maximum distance a screen-space shadow can be cast in world-space.
     * The maximum distance that screen-space shadows cast is derived from the voxel size
     * and this value so shouldn't need to change if you scale your scene
     */
    get ssShadowDistanceScale() {
        return this._sssMaxDistScale;
    }
    set ssShadowDistanceScale(value) {
        this._sssMaxDistScale = value;
        this._updateSsShadowParams();
    }
    /**
     * Screen-space shadow thickness scale. This value controls the assumed thickness of
     * on-screen surfaces in world-space. It scales with the size of the shadow-casting
     * region so shouldn't need to change if you scale your scene.
     */
    get ssShadowThicknessScale() {
        return this._sssThicknessScale;
    }
    set ssShadowThicknessScale(value) {
        this._sssThicknessScale = value;
        this._updateSsShadowParams();
    }
    /**
     * Returns the texture containing the voxel grid data
     * @returns The texture containing the voxel grid data
     * @internal
     */
    _getVoxelGridTexture() {
        const tex = this._voxelRenderer?.getVoxelGrid();
        if (tex && tex.isReady()) {
            return tex;
        }
        return this._dummyTexture3d;
    }
    /**
     * Returns the noise texture.
     * @returns The noise texture.
     * @internal
     */
    _getNoiseTexture() {
        const tex = this._noiseTexture;
        if (tex && tex.isReady()) {
            return tex;
        }
        return this._dummyTexture2d;
    }
    /**
     * Returns the voxel-tracing texture.
     * @returns The voxel-tracing texture.
     * @internal
     */
    _getVoxelTracingTexture() {
        const tex = this._voxelTracingPass?.getOutputTexture();
        if (tex && tex.isReady()) {
            return tex;
        }
        return this._dummyTexture2d;
    }
    /**
     * Returns the spatial blur texture.
     * @returns The spatial blur texture.
     * @internal
     */
    _getSpatialBlurTexture() {
        const tex = this._spatialBlurPass.getOutputTexture();
        if (tex && tex.isReady()) {
            return tex;
        }
        return this._dummyTexture2d;
    }
    /**
     * Returns the accumulated shadow texture.
     * @returns The accumulated shadow texture.
     * @internal
     */
    _getAccumulatedTexture() {
        const tex = this._accumulationPass?.getOutputTexture();
        if (tex && tex.isReady()) {
            return tex;
        }
        return this._dummyTexture2d;
    }
    /**
     * Turn on or off the debug view of the G-Buffer. This will display only the targets
     * of the g-buffer that are used by the shadow pipeline.
     */
    get gbufferDebugEnabled() {
        return this._gbufferDebugEnabled;
    }
    set gbufferDebugEnabled(enabled) {
        if (enabled && !this.allowDebugPasses) {
            Logger.Warn("Can't enable G-Buffer debug view without setting allowDebugPasses to true.");
            return;
        }
        this._gbufferDebugEnabled = enabled;
        if (enabled) {
            this._enableEffect(this._getGBufferDebugPass().name, this.cameras);
        }
        else {
            this._disableEffect(this._getGBufferDebugPass().name, this.cameras);
        }
    }
    /**
     * Turn on or off the debug view of the CDF importance sampling data
     */
    get cdfDebugEnabled() {
        return this.scene.iblCdfGenerator ? this.scene.iblCdfGenerator.debugEnabled : false;
    }
    /**
     * Turn on or off the debug view of the CDF importance sampling data
     */
    set cdfDebugEnabled(enabled) {
        if (!this.scene.iblCdfGenerator) {
            return;
        }
        if (enabled && !this.allowDebugPasses) {
            Logger.Warn("Can't enable importance sampling debug view without setting allowDebugPasses to true.");
            return;
        }
        if (enabled === this.scene.iblCdfGenerator.debugEnabled) {
            return;
        }
        this.scene.iblCdfGenerator.debugEnabled = enabled;
        if (enabled) {
            this._enableEffect(this.scene.iblCdfGenerator.debugPassName, this.cameras);
        }
        else {
            this._disableEffect(this.scene.iblCdfGenerator.debugPassName, this.cameras);
        }
    }
    /**
     * This displays the voxel grid in slices spread across the screen.
     * It also displays what slices of the model are stored in each layer
     * of the voxel grid. Each red stripe represents one layer while each gradient
     * (from bright red to black) represents the layers rendered in a single draw call.
     */
    get voxelDebugEnabled() {
        return this._voxelRenderer?.voxelDebugEnabled;
    }
    set voxelDebugEnabled(enabled) {
        if (!this._voxelRenderer) {
            return;
        }
        if (enabled && !this.allowDebugPasses) {
            Logger.Warn("Can't enable voxel debug view without setting allowDebugPasses to true.");
            return;
        }
        this._voxelRenderer.voxelDebugEnabled = enabled;
        if (enabled) {
            this._enableEffect(this._voxelRenderer.debugPassName, this.cameras);
        }
        else {
            this._disableEffect(this._voxelRenderer.debugPassName, this.cameras);
        }
    }
    /**
     * When using tri-planar voxelization (the default), this value can be used to
     * display only the voxelization result for that axis. z-axis = 0, y-axis = 1, x-axis = 2
     */
    get voxelDebugAxis() {
        return this._voxelRenderer?.voxelDebugAxis;
    }
    set voxelDebugAxis(axisNum) {
        if (!this._voxelRenderer) {
            return;
        }
        this._voxelRenderer.voxelDebugAxis = axisNum;
    }
    /**
     * Displays a given mip of the voxel grid. `voxelDebugAxis` must be undefined in this
     * case because we only generate mips for the combined voxel grid.
     */
    set voxelDebugDisplayMip(mipNum) {
        if (!this._voxelRenderer) {
            return;
        }
        this._voxelRenderer.setDebugMipNumber(mipNum);
    }
    /**
     * Display the debug view for just the shadow samples taken this frame.
     */
    get voxelTracingDebugEnabled() {
        return this._voxelTracingPass?.debugEnabled;
    }
    set voxelTracingDebugEnabled(enabled) {
        if (!this._voxelTracingPass) {
            return;
        }
        if (enabled && !this.allowDebugPasses) {
            Logger.Warn("Can't enable voxel tracing debug view without setting allowDebugPasses to true.");
            return;
        }
        if (enabled === this._voxelTracingPass.debugEnabled) {
            return;
        }
        this._voxelTracingPass.debugEnabled = enabled;
        if (enabled) {
            this._enableEffect(this._voxelTracingPass.debugPassName, this.cameras);
        }
        else {
            this._disableEffect(this._voxelTracingPass.debugPassName, this.cameras);
        }
    }
    /**
     * Display the debug view for the spatial blur pass
     */
    get spatialBlurPassDebugEnabled() {
        return this._spatialBlurPass.debugEnabled;
    }
    set spatialBlurPassDebugEnabled(enabled) {
        if (!this._spatialBlurPass) {
            return;
        }
        if (enabled && !this.allowDebugPasses) {
            Logger.Warn("Can't enable spatial blur debug view without setting allowDebugPasses to true.");
            return;
        }
        if (enabled === this._spatialBlurPass.debugEnabled) {
            return;
        }
        this._spatialBlurPass.debugEnabled = enabled;
        if (enabled) {
            this._enableEffect(this._spatialBlurPass.debugPassName, this.cameras);
        }
        else {
            this._disableEffect(this._spatialBlurPass.debugPassName, this.cameras);
        }
    }
    /**
     * Display the debug view for the shadows accumulated over time.
     */
    get accumulationPassDebugEnabled() {
        return this._accumulationPass?.debugEnabled;
    }
    set accumulationPassDebugEnabled(enabled) {
        if (!this._accumulationPass) {
            return;
        }
        if (enabled && !this.allowDebugPasses) {
            Logger.Warn("Can't enable accumulation pass debug view without setting allowDebugPasses to true.");
            return;
        }
        if (enabled === this._accumulationPass.debugEnabled) {
            return;
        }
        this._accumulationPass.debugEnabled = enabled;
        if (enabled) {
            this._enableEffect(this._accumulationPass.debugPassName, this.cameras);
        }
        else {
            this._disableEffect(this._accumulationPass.debugPassName, this.cameras);
        }
    }
    /**
     * Add a mesh to be used for shadow-casting in the IBL shadow pipeline.
     * These meshes will be written to the voxel grid.
     * @param mesh A mesh or list of meshes that you want to cast shadows
     */
    addShadowCastingMesh(mesh) {
        if (Array.isArray(mesh)) {
            for (const m of mesh) {
                if (m && this._shadowCastingMeshes.indexOf(m) === -1) {
                    this._shadowCastingMeshes.push(m);
                }
            }
        }
        else {
            if (mesh && this._shadowCastingMeshes.indexOf(mesh) === -1) {
                this._shadowCastingMeshes.push(mesh);
            }
        }
    }
    /**
     * Remove a mesh from the shadow-casting list. The mesh will no longer be written
     * to the voxel grid and will not cast shadows.
     * @param mesh The mesh or list of meshes that you don't want to cast shadows.
     */
    removeShadowCastingMesh(mesh) {
        if (Array.isArray(mesh)) {
            for (const m of mesh) {
                const index = this._shadowCastingMeshes.indexOf(m);
                if (index !== -1) {
                    this._shadowCastingMeshes.splice(index, 1);
                }
            }
        }
        else {
            const index = this._shadowCastingMeshes.indexOf(mesh);
            if (index !== -1) {
                this._shadowCastingMeshes.splice(index, 1);
            }
        }
    }
    /**
     * Clear the list of shadow-casting meshes. This will remove all meshes from the list
     */
    clearShadowCastingMeshes() {
        this._shadowCastingMeshes.length = 0;
    }
    /**
     * The exponent of the resolution of the voxel shadow grid. Higher resolutions will result in sharper
     * shadows but are more expensive to compute and require more memory.
     * The resolution is calculated as 2 to the power of this number.
     */
    get resolutionExp() {
        return this._voxelRenderer.voxelResolutionExp;
    }
    set resolutionExp(newResolution) {
        if (newResolution === this._voxelRenderer.voxelResolutionExp) {
            return;
        }
        if (this._voxelRenderer.isVoxelizationInProgress()) {
            Logger.Warn("Can't change the resolution of the voxel grid while voxelization is in progress.");
            return;
        }
        this._voxelRenderer.voxelResolutionExp = Math.max(1, Math.min(newResolution, 8));
        this._accumulationPass.reset = true;
    }
    /**
     * The number of different directions to sample during the voxel tracing pass
     */
    get sampleDirections() {
        return this._voxelTracingPass?.sampleDirections;
    }
    /**
     * The number of different directions to sample during the voxel tracing pass
     */
    set sampleDirections(value) {
        if (!this._voxelTracingPass) {
            return;
        }
        this._voxelTracingPass.sampleDirections = value;
    }
    /**
     * The decree to which the shadows persist between frames. 0.0 is no persistence, 1.0 is full persistence.
     **/
    get shadowRemanence() {
        return this._accumulationPass?.remanence;
    }
    /**
     * The decree to which the shadows persist between frames. 0.0 is no persistence, 1.0 is full persistence.
     **/
    set shadowRemanence(value) {
        if (!this._accumulationPass) {
            return;
        }
        this._accumulationPass.remanence = value;
    }
    /**
     * The global Y-axis rotation of the IBL for shadows. This should match the Y-rotation of the environment map applied to materials, skybox, etc.
     */
    get envRotation() {
        return this._voxelTracingPass?.envRotation;
    }
    /**
     * The global Y-axis rotation of the IBL for shadows. This should match the Y-rotation of the environment map applied to materials, skybox, etc.
     */
    set envRotation(value) {
        if (!this._voxelTracingPass) {
            return;
        }
        this._voxelTracingPass.envRotation = value;
        this._accumulationPass.reset = true;
    }
    /**
     * Allow debug passes to be enabled. Default is false.
     */
    get allowDebugPasses() {
        return this._allowDebugPasses;
    }
    /**
     * Allow debug passes to be enabled. Default is false.
     */
    set allowDebugPasses(value) {
        if (this._allowDebugPasses === value) {
            return;
        }
        this._allowDebugPasses = value;
        if (value && this.scene.iblCdfGenerator) {
            if (this.scene.iblCdfGenerator.isReady()) {
                this._createDebugPasses();
            }
            else {
                this.scene.iblCdfGenerator.onGeneratedObservable.addOnce(() => {
                    this._createDebugPasses();
                });
            }
        }
        else {
            this._disposeDebugPasses();
        }
    }
    /**
     *  Support test.
     */
    static get IsSupported() {
        const engine = EngineStore.LastCreatedEngine;
        if (!engine) {
            return false;
        }
        return engine._features.supportIBLShadows;
    }
    /**
     * Toggle the shadow tracing on or off
     * @param enabled Toggle the shadow tracing on or off
     */
    toggleShadow(enabled) {
        this._enabled = enabled;
        this._voxelTracingPass.enabled = enabled;
        this._spatialBlurPass.enabled = enabled;
        this._accumulationPass.enabled = enabled;
        for (const mat of this._materialsWithRenderPlugin) {
            if (mat.pluginManager) {
                const plugin = mat.pluginManager.getPlugin(IBLShadowsPluginMaterial.Name);
                plugin.isEnabled = enabled;
            }
        }
        this._setPluginParameters();
    }
    /**
     * Trigger the scene to be re-voxelized. This should be run when any shadow-casters have been added, removed or moved.
     */
    updateVoxelization() {
        if (this._shadowCastingMeshes.length === 0) {
            Logger.Warn("IBL Shadows: updateVoxelization called with no shadow-casting meshes to voxelize.");
            return;
        }
        this._voxelRenderer.updateVoxelGrid(this._shadowCastingMeshes);
        this._voxelRenderer.onVoxelizationCompleteObservable.addOnce(() => {
            this.onVoxelizationCompleteObservable.notifyObservers();
        });
        this._updateSsShadowParams();
    }
    /**
     * Trigger the scene bounds of shadow-casters to be calculated. This is the world size that the voxel grid will cover and will always be a cube.
     */
    updateSceneBounds() {
        const bounds = {
            min: new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE),
            max: new Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE),
        };
        for (const mesh of this._shadowCastingMeshes) {
            const localBounds = mesh.getHierarchyBoundingVectors(true);
            bounds.min = Vector3.Minimize(bounds.min, localBounds.min);
            bounds.max = Vector3.Maximize(bounds.max, localBounds.max);
        }
        const size = bounds.max.subtract(bounds.min);
        this.voxelGridSize = Math.max(size.x, size.y, size.z);
        if (this._shadowCastingMeshes.length === 0 || !isFinite(this.voxelGridSize) || this.voxelGridSize === 0) {
            Logger.Warn("IBL Shadows: Scene size is invalid. Can't update bounds.");
            this.voxelGridSize = 1.0;
            return;
        }
        const halfSize = this.voxelGridSize / 2.0;
        const centre = bounds.max.add(bounds.min).multiplyByFloats(-0.5, -0.5, -0.5);
        const invWorldScaleMatrix = Matrix.Compose(new Vector3(1.0 / halfSize, 1.0 / halfSize, 1.0 / halfSize), new Quaternion(), new Vector3(0, 0, 0));
        const invTranslationMatrix = Matrix.Compose(new Vector3(1.0, 1.0, 1.0), new Quaternion(), centre);
        invTranslationMatrix.multiplyToRef(invWorldScaleMatrix, invWorldScaleMatrix);
        this._voxelTracingPass.setWorldScaleMatrix(invWorldScaleMatrix);
        this._voxelRenderer.setWorldScaleMatrix(invWorldScaleMatrix);
        // Set world scale for spatial blur.
        this._spatialBlurPass.setWorldScale(halfSize * 2.0);
        this._updateSsShadowParams();
    }
    /**
     * @param name The rendering pipeline name
     * @param scene The scene linked to this pipeline
     * @param options Options to configure the pipeline
     * @param cameras Cameras to apply the pipeline to.
     */
    constructor(name, scene, options = {}, cameras) {
        super(scene.getEngine(), name);
        this._allowDebugPasses = false;
        this._debugPasses = [];
        this._shadowCastingMeshes = [];
        this._shadowOpacity = 0.8;
        this._enabled = true;
        this._coloredShadows = false;
        this._materialsWithRenderPlugin = [];
        /**
         * Observable that triggers when the shadow renderer is ready
         */
        this.onShadowTextureReadyObservable = new Observable();
        /**
         * Observable that triggers when a new IBL is set and the importance sampling is ready
         */
        this.onNewIblReadyObservable = new Observable();
        /**
         * Observable that triggers when the voxelization is complete
         */
        this.onVoxelizationCompleteObservable = new Observable();
        /**
         * The current world-space size of that the voxel grid covers in the scene.
         */
        this.voxelGridSize = 1.0;
        this._renderSizeFactor = 1.0;
        this._gbufferDebugEnabled = false;
        this._gBufferDebugSizeParams = new Vector4(0.0, 0.0, 0.0, 0.0);
        this.scene = scene;
        this._cameras = cameras || [scene.activeCamera];
        // Create the dummy textures to be used when the pipeline is not ready
        const blackPixels = new Uint8Array([0, 0, 0, 255]);
        this._dummyTexture2d = new RawTexture(blackPixels, 1, 1, Engine.TEXTUREFORMAT_RGBA, scene, false);
        this._dummyTexture3d = new RawTexture3D(blackPixels, 1, 1, 1, Engine.TEXTUREFORMAT_RGBA, scene, false);
        // Setup the geometry buffer target formats
        const textureTypesAndFormats = {};
        textureTypesAndFormats[GeometryBufferRenderer.SCREENSPACE_DEPTH_TEXTURE_TYPE] = { textureFormat: Constants.TEXTUREFORMAT_R, textureType: Constants.TEXTURETYPE_FLOAT };
        textureTypesAndFormats[GeometryBufferRenderer.VELOCITY_LINEAR_TEXTURE_TYPE] = { textureFormat: Constants.TEXTUREFORMAT_RG, textureType: Constants.TEXTURETYPE_HALF_FLOAT };
        textureTypesAndFormats[GeometryBufferRenderer.POSITION_TEXTURE_TYPE] = { textureFormat: Constants.TEXTUREFORMAT_RGBA, textureType: Constants.TEXTURETYPE_HALF_FLOAT };
        textureTypesAndFormats[GeometryBufferRenderer.NORMAL_TEXTURE_TYPE] = { textureFormat: Constants.TEXTUREFORMAT_RGBA, textureType: Constants.TEXTURETYPE_HALF_FLOAT };
        const geometryBufferRenderer = scene.enableGeometryBufferRenderer(undefined, Constants.TEXTUREFORMAT_DEPTH32_FLOAT, textureTypesAndFormats);
        if (!geometryBufferRenderer) {
            Logger.Error("Geometry buffer renderer is required for IBL shadows to work.");
            return;
        }
        this._geometryBufferRenderer = geometryBufferRenderer;
        this._geometryBufferRenderer.enableScreenspaceDepth = true;
        this._geometryBufferRenderer.enableVelocityLinear = true;
        this._geometryBufferRenderer.enablePosition = true;
        this._geometryBufferRenderer.enableNormal = true;
        this._geometryBufferRenderer.generateNormalsInWorldSpace = true;
        this.scene.enableIblCdfGenerator();
        this.shadowOpacity = options.shadowOpacity || 0.8;
        this._voxelRenderer = new _IblShadowsVoxelRenderer(this.scene, this, options ? options.resolutionExp : 6, options.triPlanarVoxelization !== undefined ? options.triPlanarVoxelization : true);
        this._voxelTracingPass = new _IblShadowsVoxelTracingPass(this.scene, this);
        this._spatialBlurPass = new _IblShadowsSpatialBlurPass(this.scene, this);
        this._accumulationPass = new _IblShadowsAccumulationPass(this.scene, this);
        this._accumulationPass.onReadyObservable.addOnce(() => {
            this.onShadowTextureReadyObservable.notifyObservers();
        });
        this.sampleDirections = options.sampleDirections || 2;
        this.voxelShadowOpacity = options.voxelShadowOpacity ?? 1.0;
        this.envRotation = options.envRotation ?? 0.0;
        this.shadowRenderSizeFactor = options.shadowRenderSizeFactor || 1.0;
        this.ssShadowOpacity = options.ssShadowsEnabled === undefined || options.ssShadowsEnabled ? 1.0 : 0.0;
        this.ssShadowDistanceScale = options.ssShadowDistanceScale || 1.25;
        this.ssShadowSampleCount = options.ssShadowSampleCount || 16;
        this.ssShadowStride = options.ssShadowStride || 8;
        this.ssShadowThicknessScale = options.ssShadowThicknessScale || 1.0;
        this.shadowRemanence = options.shadowRemanence ?? 0.75;
        this._noiseTexture = new Texture("https://assets.babylonjs.com/textures/blue_noise/blue_noise_rgb.png", this.scene, false, true, Constants.TEXTURE_NEAREST_SAMPLINGMODE);
        scene.postProcessRenderPipelineManager.addPipeline(this);
        this.scene.onActiveCameraChanged.add(this._listenForCameraChanges.bind(this));
        this.scene.onBeforeRenderObservable.add(this._updateBeforeRender.bind(this));
        this._listenForCameraChanges();
        this.scene.getEngine().onResizeObservable.add(this._handleResize.bind(this));
        // Assigning the shadow texture to the materials needs to be done after the RT's are created.
        if (this.scene.iblCdfGenerator) {
            this.scene.iblCdfGenerator.onGeneratedObservable.add(() => {
                this._setPluginParameters();
                this.onNewIblReadyObservable.notifyObservers();
            });
        }
    }
    _handleResize() {
        this._voxelRenderer.resize();
        this._voxelTracingPass.resize(this.shadowRenderSizeFactor);
        this._spatialBlurPass.resize(this.shadowRenderSizeFactor);
        this._accumulationPass.resize(this.shadowRenderSizeFactor);
        this._setPluginParameters();
    }
    _getGBufferDebugPass() {
        if (this._gbufferDebugPass) {
            return this._gbufferDebugPass;
        }
        const isWebGPU = this.engine.isWebGPU;
        const textureNames = ["depthSampler", "normalSampler", "positionSampler", "velocitySampler"];
        const options = {
            width: this.scene.getEngine().getRenderWidth(),
            height: this.scene.getEngine().getRenderHeight(),
            samplingMode: Constants.TEXTURE_NEAREST_SAMPLINGMODE,
            engine: this.scene.getEngine(),
            textureType: Constants.TEXTURETYPE_UNSIGNED_BYTE,
            textureFormat: Constants.TEXTUREFORMAT_RGBA,
            uniforms: ["sizeParams"],
            samplers: textureNames,
            reusable: false,
            shaderLanguage: isWebGPU ? 1 /* ShaderLanguage.WGSL */ : 0 /* ShaderLanguage.GLSL */,
            extraInitializations: (useWebGPU, list) => {
                if (useWebGPU) {
                    list.push(import('./iblShadowGBufferDebug.fragment-BaMlloco.esm.js'));
                }
                else {
                    list.push(import('./iblShadowGBufferDebug.fragment-cKnGzUq_.esm.js'));
                }
            },
        };
        this._gbufferDebugPass = new PostProcess("iblShadowGBufferDebug", "iblShadowGBufferDebug", options);
        if (this.engine.isWebGPU) {
            this._gbufferDebugPass.samples = this.engine.currentSampleCount ?? 1;
        }
        this._gbufferDebugPass.autoClear = false;
        this._gbufferDebugPass.onApplyObservable.add((effect) => {
            const depthIndex = this._geometryBufferRenderer.getTextureIndex(GeometryBufferRenderer.SCREENSPACE_DEPTH_TEXTURE_TYPE);
            effect.setTexture("depthSampler", this._geometryBufferRenderer.getGBuffer().textures[depthIndex]);
            const normalIndex = this._geometryBufferRenderer.getTextureIndex(GeometryBufferRenderer.NORMAL_TEXTURE_TYPE);
            effect.setTexture("normalSampler", this._geometryBufferRenderer.getGBuffer().textures[normalIndex]);
            const positionIndex = this._geometryBufferRenderer.getTextureIndex(GeometryBufferRenderer.POSITION_TEXTURE_TYPE);
            effect.setTexture("positionSampler", this._geometryBufferRenderer.getGBuffer().textures[positionIndex]);
            const velocityIndex = this._geometryBufferRenderer.getTextureIndex(GeometryBufferRenderer.VELOCITY_LINEAR_TEXTURE_TYPE);
            effect.setTexture("velocitySampler", this._geometryBufferRenderer.getGBuffer().textures[velocityIndex]);
            effect.setVector4("sizeParams", this._gBufferDebugSizeParams);
            if (this.scene.activeCamera) {
                effect.setFloat("maxDepth", this.scene.activeCamera.maxZ);
            }
        });
        return this._gbufferDebugPass;
    }
    _createDebugPasses() {
        if (this.scene.iblCdfGenerator) {
            this._debugPasses = [{ pass: this.scene.iblCdfGenerator.getDebugPassPP(), enabled: this.cdfDebugEnabled }];
        }
        else {
            this._debugPasses = [];
        }
        this._debugPasses.push({ pass: this._voxelRenderer.getDebugPassPP(), enabled: this.voxelDebugEnabled }, { pass: this._voxelTracingPass.getDebugPassPP(), enabled: this.voxelTracingDebugEnabled }, { pass: this._spatialBlurPass.getDebugPassPP(), enabled: this.spatialBlurPassDebugEnabled }, { pass: this._accumulationPass.getDebugPassPP(), enabled: this.accumulationPassDebugEnabled }, { pass: this._getGBufferDebugPass(), enabled: this.gbufferDebugEnabled });
        for (let i = 0; i < this._debugPasses.length; i++) {
            if (!this._debugPasses[i].pass) {
                continue;
            }
            this.addEffect(new PostProcessRenderEffect(this.scene.getEngine(), this._debugPasses[i].pass.name, () => {
                return this._debugPasses[i].pass;
            }, true));
        }
        const cameras = this.cameras.slice();
        this.scene.postProcessRenderPipelineManager.detachCamerasFromRenderPipeline(this.name, this.cameras);
        this.scene.postProcessRenderPipelineManager.attachCamerasToRenderPipeline(this.name, cameras);
        for (let i = 0; i < this._debugPasses.length; i++) {
            if (!this._debugPasses[i].pass) {
                continue;
            }
            if (this._debugPasses[i].enabled) {
                this._enableEffect(this._debugPasses[i].pass.name, this.cameras);
            }
            else {
                this._disableEffect(this._debugPasses[i].pass.name, this.cameras);
            }
        }
    }
    _disposeEffectPasses() {
        this.scene.postProcessRenderPipelineManager.detachCamerasFromRenderPipeline(this.name, this.cameras);
        this._disposeDebugPasses();
        this._reset();
    }
    _disposeDebugPasses() {
        for (let i = 0; i < this._debugPasses.length; i++) {
            this._disableEffect(this._debugPasses[i].pass.name, this.cameras);
            this._debugPasses[i].pass.dispose();
        }
        this._debugPasses = [];
    }
    _updateDebugPasses() {
        let count = 0;
        if (this._gbufferDebugEnabled) {
            count++;
        }
        if (this.cdfDebugEnabled) {
            count++;
        }
        if (this.voxelDebugEnabled) {
            count++;
        }
        if (this.voxelTracingDebugEnabled) {
            count++;
        }
        if (this.spatialBlurPassDebugEnabled) {
            count++;
        }
        if (this.accumulationPassDebugEnabled) {
            count++;
        }
        const rows = Math.ceil(Math.sqrt(count));
        const cols = Math.ceil(count / rows);
        const width = 1.0 / cols;
        const height = 1.0 / rows;
        let x = 0;
        let y = 0;
        if (this.gbufferDebugEnabled) {
            this._gBufferDebugSizeParams.set(x, y, cols, rows);
            x -= width;
            if (x <= -1) {
                x = 0;
                y -= height;
            }
        }
        if (this.cdfDebugEnabled && this.scene.iblCdfGenerator) {
            this.scene.iblCdfGenerator.setDebugDisplayParams(x, y, cols, rows);
            x -= width;
            if (x <= -1) {
                x = 0;
                y -= height;
            }
        }
        if (this.voxelDebugEnabled) {
            this._voxelRenderer.setDebugDisplayParams(x, y, cols, rows);
            x -= width;
            if (x <= -1) {
                x = 0;
                y -= height;
            }
        }
        if (this.voxelTracingDebugEnabled) {
            this._voxelTracingPass.setDebugDisplayParams(x, y, cols, rows);
            x -= width;
            if (x <= -1) {
                x = 0;
                y -= height;
            }
        }
        if (this.spatialBlurPassDebugEnabled) {
            this._spatialBlurPass.setDebugDisplayParams(x, y, cols, rows);
            x -= width;
            if (x <= -1) {
                x = 0;
                y -= height;
            }
        }
        if (this.accumulationPassDebugEnabled) {
            this._accumulationPass.setDebugDisplayParams(x, y, cols, rows);
            x -= width;
            if (x <= -1) {
                x = 0;
                y -= height;
            }
        }
    }
    /**
     * Update the SS shadow max distance and thickness based on the voxel grid size and resolution.
     * The max distance should be just a little larger than the world size of a single voxel.
     */
    _updateSsShadowParams() {
        this._voxelTracingPass.sssMaxDist = (this._sssMaxDistScale * this.voxelGridSize) / (1 << this.resolutionExp);
        this._voxelTracingPass.sssThickness = this._sssThicknessScale * 0.005 * this.voxelGridSize;
    }
    /**
     * Apply the shadows to a material or array of materials. If no material is provided, all
     * materials in the scene will be added.
     * @param material Material that will be affected by the shadows. If not provided, all materials of the scene will be affected.
     */
    addShadowReceivingMaterial(material) {
        if (material) {
            if (Array.isArray(material)) {
                for (const m of material) {
                    this._addShadowSupportToMaterial(m);
                }
            }
            else {
                this._addShadowSupportToMaterial(material);
            }
        }
        else {
            for (const mat of this.scene.materials) {
                this._addShadowSupportToMaterial(mat);
            }
        }
    }
    /**
     * Remove a material from the list of materials that receive shadows. If no material
     * is provided, all materials in the scene will be removed.
     * @param material The material or array of materials that will no longer receive shadows
     */
    removeShadowReceivingMaterial(material) {
        if (Array.isArray(material)) {
            for (const m of material) {
                const matIndex = this._materialsWithRenderPlugin.indexOf(m);
                if (matIndex !== -1) {
                    this._materialsWithRenderPlugin.splice(matIndex, 1);
                    // eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain
                    const plugin = m.pluginManager?.getPlugin(IBLShadowsPluginMaterial.Name);
                    plugin.isEnabled = false;
                }
            }
        }
        else {
            const matIndex = this._materialsWithRenderPlugin.indexOf(material);
            if (matIndex !== -1) {
                this._materialsWithRenderPlugin.splice(matIndex, 1);
                const plugin = material.pluginManager.getPlugin(IBLShadowsPluginMaterial.Name);
                plugin.isEnabled = false;
            }
        }
    }
    /**
     * Clear the list of materials that receive shadows. This will remove all materials from the list
     */
    clearShadowReceivingMaterials() {
        for (const mat of this._materialsWithRenderPlugin) {
            const plugin = mat.pluginManager?.getPlugin(IBLShadowsPluginMaterial.Name);
            if (plugin) {
                plugin.isEnabled = false;
            }
        }
        this._materialsWithRenderPlugin.length = 0;
    }
    _addShadowSupportToMaterial(material) {
        if (!(material instanceof PBRBaseMaterial) && !(material instanceof StandardMaterial)) {
            return;
        }
        let plugin = material.pluginManager?.getPlugin(IBLShadowsPluginMaterial.Name);
        if (!plugin) {
            plugin = new IBLShadowsPluginMaterial(material);
        }
        if (this._materialsWithRenderPlugin.indexOf(material) !== -1) {
            return;
        }
        if (this._enabled) {
            plugin.iblShadowsTexture = this._getAccumulatedTexture().getInternalTexture();
            plugin.shadowOpacity = this.shadowOpacity;
        }
        plugin.isEnabled = this._enabled;
        plugin.isColored = this._coloredShadows;
        this._materialsWithRenderPlugin.push(material);
    }
    _setPluginParameters() {
        if (!this._enabled) {
            return;
        }
        for (const mat of this._materialsWithRenderPlugin) {
            if (mat.pluginManager) {
                const plugin = mat.pluginManager.getPlugin(IBLShadowsPluginMaterial.Name);
                plugin.iblShadowsTexture = this._getAccumulatedTexture().getInternalTexture();
                plugin.shadowOpacity = this.shadowOpacity;
                plugin.isColored = this._coloredShadows;
            }
        }
    }
    _updateBeforeRender() {
        this._updateDebugPasses();
    }
    _listenForCameraChanges() {
        // We want to listen for camera changes and change settings while the camera is moving.
        this.scene.activeCamera?.onViewMatrixChangedObservable.add(() => {
            this._accumulationPass.isMoving = true;
        });
    }
    /**
     * Checks if the IBL shadow pipeline is ready to render shadows
     * @returns true if the IBL shadow pipeline is ready to render the shadows
     */
    isReady() {
        return (this._noiseTexture.isReady() &&
            this._voxelRenderer.isReady() &&
            this.scene.iblCdfGenerator &&
            this.scene.iblCdfGenerator.isReady() &&
            (!this._voxelTracingPass || this._voxelTracingPass.isReady()) &&
            (!this._spatialBlurPass || this._spatialBlurPass.isReady()) &&
            (!this._accumulationPass || this._accumulationPass.isReady()));
    }
    /**
     * Get the class name
     * @returns "IBLShadowsRenderPipeline"
     */
    getClassName() {
        return "IBLShadowsRenderPipeline";
    }
    /**
     * Disposes the IBL shadow pipeline and associated resources
     */
    dispose() {
        const materials = this._materialsWithRenderPlugin.splice(0);
        for (const mat of materials) {
            this.removeShadowReceivingMaterial(mat);
        }
        this._disposeEffectPasses();
        this._noiseTexture.dispose();
        this._voxelRenderer.dispose();
        this._voxelTracingPass.dispose();
        this._spatialBlurPass.dispose();
        this._accumulationPass.dispose();
        this._dummyTexture2d.dispose();
        this._dummyTexture3d.dispose();
        this.onNewIblReadyObservable.clear();
        this.onShadowTextureReadyObservable.clear();
        this.onVoxelizationCompleteObservable.clear();
        super.dispose();
    }
}

export { IblShadowsRenderPipeline };
//# sourceMappingURL=iblShadowsRenderPipeline-BHPB71IG.esm.js.map