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.

1,309 lines (1,304 loc) 74.4 kB
import { c5 as EffectWrapper, a as EngineStore, ac as ImageProcessingConfiguration, C as Constants, l as __runInitializers, aP as PostProcess, q as __esDecorate, s as serialize, be as MultiRenderTarget, aZ as SceneComponentConstants, ao as Scene, y as Logger, b1 as Color4, F as Material, ba as _WarnImport } from './index-MZPybX0H.esm.js'; import { R as RegisterGeometryBufferRendererSceneComponent, G as GeometryBufferRenderer } from './geometryBufferRenderer.pure-BFEtStOF.esm.js'; /** * Post process used to apply image processing to a scene */ class ThinImageProcessingPostProcess extends EffectWrapper { _gatherImports(useWebGPU, list) { if (useWebGPU) { this._webGPUReady = true; list.push(import('./imageProcessing.fragment-BSK1p2l3.esm.js')); } else { list.push(import('./imageProcessing.fragment-dvbSDXQv.esm.js')); } } /** * Gets the image processing configuration used either in this material. */ get imageProcessingConfiguration() { return this._imageProcessingConfiguration; } /** * Sets the Default image processing configuration used either in the this material. * * If sets to null, the scene one is in use. */ set imageProcessingConfiguration(value) { // We are almost sure it is applied by post process as // We are in the post process :-) value.applyByPostProcess = true; this._attachImageProcessingConfiguration(value); } /** * Attaches a new image processing configuration to the PBR Material. * @param configuration * @param doNotBuild */ _attachImageProcessingConfiguration(configuration, doNotBuild = false) { if (configuration === this._imageProcessingConfiguration) { return; } // Detaches observer. if (this._imageProcessingConfiguration && this._imageProcessingObserver) { this._imageProcessingConfiguration.onUpdateParameters.remove(this._imageProcessingObserver); } // Pick the scene configuration if needed. if (!configuration) { let scene = this.options.scene; if (!scene) { const engine = this.options.engine; if (engine && engine.scenes) { const scenes = engine.scenes; scene = scenes[scenes.length - 1]; } else { scene = EngineStore.LastCreatedScene; } } if (scene) { this._imageProcessingConfiguration = scene.imageProcessingConfiguration; } else { this._imageProcessingConfiguration = new ImageProcessingConfiguration(); } } else { this._imageProcessingConfiguration = configuration; } // Attaches observer. if (this._imageProcessingConfiguration) { this._imageProcessingObserver = this._imageProcessingConfiguration.onUpdateParameters.add(() => { this._updateParameters(); }); } // Ensure the effect will be rebuilt. if (!doNotBuild) { this._updateParameters(); } } /** * Gets Color curves setup used in the effect if colorCurvesEnabled is set to true . */ get colorCurves() { return this.imageProcessingConfiguration.colorCurves; } /** * Sets Color curves setup used in the effect if colorCurvesEnabled is set to true . */ set colorCurves(value) { this.imageProcessingConfiguration.colorCurves = value; } /** * Gets whether the color curves effect is enabled. */ get colorCurvesEnabled() { return this.imageProcessingConfiguration.colorCurvesEnabled; } /** * Sets whether the color curves effect is enabled. */ set colorCurvesEnabled(value) { this.imageProcessingConfiguration.colorCurvesEnabled = value; } /** * Gets Color grading LUT texture used in the effect if colorGradingEnabled is set to true. */ get colorGradingTexture() { return this.imageProcessingConfiguration.colorGradingTexture; } /** * Sets Color grading LUT texture used in the effect if colorGradingEnabled is set to true. */ set colorGradingTexture(value) { this.imageProcessingConfiguration.colorGradingTexture = value; } /** * Gets whether the color grading effect is enabled. */ get colorGradingEnabled() { return this.imageProcessingConfiguration.colorGradingEnabled; } /** * Gets whether the color grading effect is enabled. */ set colorGradingEnabled(value) { this.imageProcessingConfiguration.colorGradingEnabled = value; } /** * Gets exposure used in the effect. */ get exposure() { return this.imageProcessingConfiguration.exposure; } /** * Sets exposure used in the effect. */ set exposure(value) { this.imageProcessingConfiguration.exposure = value; } /** * Gets whether tonemapping is enabled or not. */ get toneMappingEnabled() { return this._imageProcessingConfiguration.toneMappingEnabled; } /** * Sets whether tonemapping is enabled or not */ set toneMappingEnabled(value) { this._imageProcessingConfiguration.toneMappingEnabled = value; } /** * Gets the type of tone mapping effect. */ get toneMappingType() { return this._imageProcessingConfiguration.toneMappingType; } /** * Sets the type of tone mapping effect. */ set toneMappingType(value) { this._imageProcessingConfiguration.toneMappingType = value; } /** * Gets contrast used in the effect. */ get contrast() { return this.imageProcessingConfiguration.contrast; } /** * Sets contrast used in the effect. */ set contrast(value) { this.imageProcessingConfiguration.contrast = value; } /** * Gets Vignette stretch size. */ get vignetteStretch() { return this.imageProcessingConfiguration.vignetteStretch; } /** * Sets Vignette stretch size. */ set vignetteStretch(value) { this.imageProcessingConfiguration.vignetteStretch = value; } /** * Gets Vignette center X Offset. * @deprecated use vignetteCenterX instead */ get vignetteCentreX() { return this.imageProcessingConfiguration.vignetteCenterX; } /** * Sets Vignette center X Offset. * @deprecated use vignetteCenterX instead */ set vignetteCentreX(value) { this.imageProcessingConfiguration.vignetteCenterX = value; } /** * Gets Vignette center Y Offset. * @deprecated use vignetteCenterY instead */ get vignetteCentreY() { return this.imageProcessingConfiguration.vignetteCenterY; } /** * Sets Vignette center Y Offset. * @deprecated use vignetteCenterY instead */ set vignetteCentreY(value) { this.imageProcessingConfiguration.vignetteCenterY = value; } /** * Vignette center Y Offset. */ get vignetteCenterY() { return this.imageProcessingConfiguration.vignetteCenterY; } set vignetteCenterY(value) { this.imageProcessingConfiguration.vignetteCenterY = value; } /** * Vignette center X Offset. */ get vignetteCenterX() { return this.imageProcessingConfiguration.vignetteCenterX; } set vignetteCenterX(value) { this.imageProcessingConfiguration.vignetteCenterX = value; } /** * Gets Vignette weight or intensity of the vignette effect. */ get vignetteWeight() { return this.imageProcessingConfiguration.vignetteWeight; } /** * Sets Vignette weight or intensity of the vignette effect. */ set vignetteWeight(value) { this.imageProcessingConfiguration.vignetteWeight = value; } /** * Gets Color of the vignette applied on the screen through the chosen blend mode (vignetteBlendMode) * if vignetteEnabled is set to true. */ get vignetteColor() { return this.imageProcessingConfiguration.vignetteColor; } /** * Sets Color of the vignette applied on the screen through the chosen blend mode (vignetteBlendMode) * if vignetteEnabled is set to true. */ set vignetteColor(value) { this.imageProcessingConfiguration.vignetteColor = value; } /** * Gets Camera field of view used by the Vignette effect. */ get vignetteCameraFov() { return this.imageProcessingConfiguration.vignetteCameraFov; } /** * Sets Camera field of view used by the Vignette effect. */ set vignetteCameraFov(value) { this.imageProcessingConfiguration.vignetteCameraFov = value; } /** * Gets the vignette blend mode allowing different kind of effect. */ get vignetteBlendMode() { return this.imageProcessingConfiguration.vignetteBlendMode; } /** * Sets the vignette blend mode allowing different kind of effect. */ set vignetteBlendMode(value) { this.imageProcessingConfiguration.vignetteBlendMode = value; } /** * Gets whether the vignette effect is enabled. */ get vignetteEnabled() { return this.imageProcessingConfiguration.vignetteEnabled; } /** * Sets whether the vignette effect is enabled. */ set vignetteEnabled(value) { this.imageProcessingConfiguration.vignetteEnabled = value; } /** * Gets intensity of the dithering effect. */ get ditheringIntensity() { return this.imageProcessingConfiguration.ditheringIntensity; } /** * Sets intensity of the dithering effect. */ set ditheringIntensity(value) { this.imageProcessingConfiguration.ditheringIntensity = value; } /** * Gets whether the dithering effect is enabled. */ get ditheringEnabled() { return this.imageProcessingConfiguration.ditheringEnabled; } /** * Sets whether the dithering effect is enabled. */ set ditheringEnabled(value) { this.imageProcessingConfiguration.ditheringEnabled = value; } /** * Gets whether the input of the processing is in Gamma or Linear Space. */ get fromLinearSpace() { return this._fromLinearSpace; } /** * Sets whether the input of the processing is in Gamma or Linear Space. */ set fromLinearSpace(value) { if (this._fromLinearSpace === value) { return; } this._fromLinearSpace = value; this._updateParameters(); } /** * * Gets the width of the output texture used to store the result of the post process. */ get outputTextureWidth() { return this.imageProcessingConfiguration.outputTextureWidth; } /** * * Sets the width of the output texture used to store the result of the post process. */ set outputTextureWidth(value) { this.imageProcessingConfiguration.outputTextureWidth = value; } /** * * Gets the height of the output texture used to store the result of the post process. */ get outputTextureHeight() { return this.imageProcessingConfiguration.outputTextureHeight; } /** * * Sets the height of the output texture used to store the result of the post process. */ set outputTextureHeight(value) { this.imageProcessingConfiguration.outputTextureHeight = value; } /** * Constructs a new image processing post process * @param name Name of the effect * @param engine Engine to use to render the effect. If not provided, the last created engine will be used * @param options Options to configure the effect */ constructor(name, engine = null, options) { super({ ...options, name, engine: engine || EngineStore.LastCreatedEngine, useShaderStore: true, useAsPostProcess: true, fragmentShader: ThinImageProcessingPostProcess.FragmentUrl, }); this._fromLinearSpace = true; /** * Defines cache preventing GC. */ this._defines = { IMAGEPROCESSING: false, VIGNETTE: false, VIGNETTEBLENDMODEMULTIPLY: false, VIGNETTEBLENDMODEOPAQUE: false, TONEMAPPING: 0, CONTRAST: false, COLORCURVES: false, COLORGRADING: false, COLORGRADING3D: false, FROMLINEARSPACE: false, SAMPLER3DGREENDEPTH: false, SAMPLER3DBGRMAP: false, DITHER: false, IMAGEPROCESSINGPOSTPROCESS: false, EXPOSURE: false, SKIPFINALCOLORCLAMP: false, }; const imageProcessingConfiguration = options?.imageProcessingConfiguration; // Setup the configuration as forced by the constructor. This would then not force the // scene materials output in linear space and let untouched the default forward pass. if (imageProcessingConfiguration) { imageProcessingConfiguration.applyByPostProcess = true; this._attachImageProcessingConfiguration(imageProcessingConfiguration, true); // This will cause the shader to be compiled this._updateParameters(); } // Setup the default processing configuration to the scene. else { this._attachImageProcessingConfiguration(null, true); this.imageProcessingConfiguration.applyByPostProcess = true; } } /** * @internal */ _updateParameters() { this._defines.FROMLINEARSPACE = this._fromLinearSpace; this.imageProcessingConfiguration.prepareDefines(this._defines, true); let defines = ""; for (const prop in this._defines) { const value = this._defines[prop]; const type = typeof value; switch (type) { case "number": case "string": defines += `#define ${prop} ${value};\n`; break; default: if (value) { defines += `#define ${prop};\n`; } break; } } const samplers = ["textureSampler"]; const uniforms = ["scale"]; if (ImageProcessingConfiguration) { ImageProcessingConfiguration.PrepareSamplers(samplers, this._defines); ImageProcessingConfiguration.PrepareUniforms(uniforms, this._defines); } this.updateEffect(defines, uniforms, samplers); } bind(noDefaultBindings = false) { super.bind(noDefaultBindings); this.imageProcessingConfiguration.bind(this.effect, this.overrideAspectRatio); } dispose() { super.dispose(); if (this._imageProcessingConfiguration && this._imageProcessingObserver) { this._imageProcessingConfiguration.onUpdateParameters.remove(this._imageProcessingObserver); } if (this._imageProcessingConfiguration) { this.imageProcessingConfiguration.applyByPostProcess = false; } } } /** * The fragment shader url */ ThinImageProcessingPostProcess.FragmentUrl = "imageProcessing"; /** * ImageProcessingPostProcess * @see https://doc.babylonjs.com/features/featuresDeepDive/postProcesses/usePostProcesses#imageprocessing */ let ImageProcessingPostProcess = (() => { var _a; let _classSuper = PostProcess; let _instanceExtraInitializers = []; let _get_fromLinearSpace_decorators; return _a = class ImageProcessingPostProcess extends _classSuper { get _imageProcessingConfiguration() { return this._effectWrapper.imageProcessingConfiguration; } /** * Gets the image processing configuration used either in this material. */ get imageProcessingConfiguration() { return this._effectWrapper.imageProcessingConfiguration; } /** * Sets the Default image processing configuration used either in the this material. * * If sets to null, the scene one is in use. */ set imageProcessingConfiguration(value) { this._effectWrapper.imageProcessingConfiguration = value; } /** * If the post process is supported. */ get isSupported() { const effect = this.getEffect(); return !effect || effect.isSupported; } /** * Gets Color curves setup used in the effect if colorCurvesEnabled is set to true . */ get colorCurves() { return this.imageProcessingConfiguration.colorCurves; } /** * Sets Color curves setup used in the effect if colorCurvesEnabled is set to true . */ set colorCurves(value) { this.imageProcessingConfiguration.colorCurves = value; } /** * Gets whether the color curves effect is enabled. */ get colorCurvesEnabled() { return this.imageProcessingConfiguration.colorCurvesEnabled; } /** * Sets whether the color curves effect is enabled. */ set colorCurvesEnabled(value) { this.imageProcessingConfiguration.colorCurvesEnabled = value; } /** * Gets Color grading LUT texture used in the effect if colorGradingEnabled is set to true. */ get colorGradingTexture() { return this.imageProcessingConfiguration.colorGradingTexture; } /** * Sets Color grading LUT texture used in the effect if colorGradingEnabled is set to true. */ set colorGradingTexture(value) { this.imageProcessingConfiguration.colorGradingTexture = value; } /** * Gets whether the color grading effect is enabled. */ get colorGradingEnabled() { return this.imageProcessingConfiguration.colorGradingEnabled; } /** * Gets whether the color grading effect is enabled. */ set colorGradingEnabled(value) { this.imageProcessingConfiguration.colorGradingEnabled = value; } /** * Gets exposure used in the effect. */ get exposure() { return this.imageProcessingConfiguration.exposure; } /** * Sets exposure used in the effect. */ set exposure(value) { this.imageProcessingConfiguration.exposure = value; } /** * Gets whether tonemapping is enabled or not. */ get toneMappingEnabled() { return this._imageProcessingConfiguration.toneMappingEnabled; } /** * Sets whether tonemapping is enabled or not */ set toneMappingEnabled(value) { this._imageProcessingConfiguration.toneMappingEnabled = value; } /** * Gets the type of tone mapping effect. */ get toneMappingType() { return this._imageProcessingConfiguration.toneMappingType; } /** * Sets the type of tone mapping effect. */ set toneMappingType(value) { this._imageProcessingConfiguration.toneMappingType = value; } /** * Gets contrast used in the effect. */ get contrast() { return this.imageProcessingConfiguration.contrast; } /** * Sets contrast used in the effect. */ set contrast(value) { this.imageProcessingConfiguration.contrast = value; } /** * Gets Vignette stretch size. */ get vignetteStretch() { return this.imageProcessingConfiguration.vignetteStretch; } /** * Sets Vignette stretch size. */ set vignetteStretch(value) { this.imageProcessingConfiguration.vignetteStretch = value; } /** * Gets Vignette center X Offset. * @deprecated use vignetteCenterX instead */ get vignetteCentreX() { return this.imageProcessingConfiguration.vignetteCenterX; } /** * Sets Vignette center X Offset. * @deprecated use vignetteCenterX instead */ set vignetteCentreX(value) { this.imageProcessingConfiguration.vignetteCenterX = value; } /** * Gets Vignette center Y Offset. * @deprecated use vignetteCenterY instead */ get vignetteCentreY() { return this.imageProcessingConfiguration.vignetteCenterY; } /** * Sets Vignette center Y Offset. * @deprecated use vignetteCenterY instead */ set vignetteCentreY(value) { this.imageProcessingConfiguration.vignetteCenterY = value; } /** * Vignette center Y Offset. */ get vignetteCenterY() { return this.imageProcessingConfiguration.vignetteCenterY; } set vignetteCenterY(value) { this.imageProcessingConfiguration.vignetteCenterY = value; } /** * Vignette center X Offset. */ get vignetteCenterX() { return this.imageProcessingConfiguration.vignetteCenterX; } set vignetteCenterX(value) { this.imageProcessingConfiguration.vignetteCenterX = value; } /** * Gets Vignette weight or intensity of the vignette effect. */ get vignetteWeight() { return this.imageProcessingConfiguration.vignetteWeight; } /** * Sets Vignette weight or intensity of the vignette effect. */ set vignetteWeight(value) { this.imageProcessingConfiguration.vignetteWeight = value; } /** * Gets Color of the vignette applied on the screen through the chosen blend mode (vignetteBlendMode) * if vignetteEnabled is set to true. */ get vignetteColor() { return this.imageProcessingConfiguration.vignetteColor; } /** * Sets Color of the vignette applied on the screen through the chosen blend mode (vignetteBlendMode) * if vignetteEnabled is set to true. */ set vignetteColor(value) { this.imageProcessingConfiguration.vignetteColor = value; } /** * Gets Camera field of view used by the Vignette effect. */ get vignetteCameraFov() { return this.imageProcessingConfiguration.vignetteCameraFov; } /** * Sets Camera field of view used by the Vignette effect. */ set vignetteCameraFov(value) { this.imageProcessingConfiguration.vignetteCameraFov = value; } /** * Gets the vignette blend mode allowing different kind of effect. */ get vignetteBlendMode() { return this.imageProcessingConfiguration.vignetteBlendMode; } /** * Sets the vignette blend mode allowing different kind of effect. */ set vignetteBlendMode(value) { this.imageProcessingConfiguration.vignetteBlendMode = value; } /** * Gets whether the vignette effect is enabled. */ get vignetteEnabled() { return this.imageProcessingConfiguration.vignetteEnabled; } /** * Sets whether the vignette effect is enabled. */ set vignetteEnabled(value) { this.imageProcessingConfiguration.vignetteEnabled = value; } /** * Gets intensity of the dithering effect. */ get ditheringIntensity() { return this.imageProcessingConfiguration.ditheringIntensity; } /** * Sets intensity of the dithering effect. */ set ditheringIntensity(value) { this.imageProcessingConfiguration.ditheringIntensity = value; } /** * Gets whether the dithering effect is enabled. */ get ditheringEnabled() { return this.imageProcessingConfiguration.ditheringEnabled; } /** * Sets whether the dithering effect is enabled. */ set ditheringEnabled(value) { this.imageProcessingConfiguration.ditheringEnabled = value; } /** * Gets whether the input of the processing is in Gamma or Linear Space. */ get fromLinearSpace() { return this._effectWrapper.fromLinearSpace; } /** * Sets whether the input of the processing is in Gamma or Linear Space. */ set fromLinearSpace(value) { this._effectWrapper.fromLinearSpace = value; } constructor(name, options, camera = null, samplingMode, engine, reusable, textureType = Constants.TEXTURETYPE_UNSIGNED_BYTE, imageProcessingConfiguration) { const localOptions = { size: typeof options === "number" ? options : undefined, camera, samplingMode, engine, reusable, textureType, imageProcessingConfiguration, scene: camera?.getScene(), ...options, blockCompilation: true, }; super(name, ThinImageProcessingPostProcess.FragmentUrl, { effectWrapper: typeof options === "number" || !options.effectWrapper ? new ThinImageProcessingPostProcess(name, engine, localOptions) : undefined, ...localOptions, }); __runInitializers(this, _instanceExtraInitializers); this.onApply = () => { this._effectWrapper.overrideAspectRatio = this.aspectRatio; }; } /** * "ImageProcessingPostProcess" * @returns "ImageProcessingPostProcess" */ getClassName() { return "ImageProcessingPostProcess"; } /** * @internal */ _updateParameters() { this._effectWrapper._updateParameters(); } dispose(camera) { super.dispose(camera); if (this._imageProcessingConfiguration) { this.imageProcessingConfiguration.applyByPostProcess = false; } } }, (() => { const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0; _get_fromLinearSpace_decorators = [serialize()]; __esDecorate(_a, null, _get_fromLinearSpace_decorators, { kind: "getter", name: "fromLinearSpace", static: false, private: false, access: { has: obj => "fromLinearSpace" in obj, get: obj => obj.fromLinearSpace }, metadata: _metadata }, null, _instanceExtraInitializers); if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); })(), _a; })(); /** * A multi render target designed to render the prepass. * Prepass is a scene component used to render information in multiple textures * alongside with the scene materials rendering. * Note : This is an internal class, and you should NOT need to instanciate this. * Only the `PrePassRenderer` should instanciate this class. * It is more likely that you need a regular `MultiRenderTarget` * @internal */ class PrePassRenderTarget extends MultiRenderTarget { constructor(name, renderTargetTexture, size, count, scene, options) { super(name, size, count, scene, options); /** * @internal */ this._beforeCompositionPostProcesses = []; /** * @internal */ this._internalTextureDirty = false; /** * Is this render target enabled for prepass rendering */ this.enabled = false; /** * Render target associated with this prePassRenderTarget * If this is `null`, it means this prePassRenderTarget is associated with the scene */ this.renderTargetTexture = null; this.renderTargetTexture = renderTargetTexture; } /** * Creates a composition effect for this RT * @internal */ _createCompositionEffect() { this.imageProcessingPostProcess = new ImageProcessingPostProcess("prePassComposition", 1, null, undefined, this._engine); this.imageProcessingPostProcess._updateParameters(); } /** * Checks that the size of this RT is still adapted to the desired render size. * @internal */ _checkSize() { const requiredWidth = this._engine.getRenderWidth(true); const requiredHeight = this._engine.getRenderHeight(true); const width = this.getRenderWidth(); const height = this.getRenderHeight(); if (width !== requiredWidth || height !== requiredHeight) { this.resize({ width: requiredWidth, height: requiredHeight }); this._internalTextureDirty = true; } } /** * 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) { super.updateCount(count, options, textureNames); this._internalTextureDirty = true; } /** * Resets the post processes chains applied to this RT. * @internal */ _resetPostProcessChain() { this._beforeCompositionPostProcesses.length = 0; } /** * Diposes this render target */ dispose() { const scene = this._scene; super.dispose(); if (scene && scene.prePassRenderer) { const index = scene.prePassRenderer.renderTargets.indexOf(this); if (index !== -1) { scene.prePassRenderer.renderTargets.splice(index, 1); } } if (this.imageProcessingPostProcess) { this.imageProcessingPostProcess.dispose(); } if (this.renderTargetTexture) { this.renderTargetTexture._prePassRenderTarget = null; } if (this._outputPostProcess) { this._outputPostProcess.autoClear = true; this._outputPostProcess.restoreDefaultInputTexture(); } } } /** This file must only contain pure code and pure imports */ /** * Defines the Geometry Buffer scene component responsible to manage a G-Buffer useful * in several rendering techniques. */ class PrePassRendererSceneComponent { /** * 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_PREPASSRENDERER; this.scene = scene; } /** * Registers the component in a given scene */ register() { this.scene._beforeCameraDrawStage.registerStep(SceneComponentConstants.STEP_BEFORECAMERADRAW_PREPASS, this, this._beforeCameraDraw); this.scene._afterCameraDrawStage.registerStep(SceneComponentConstants.STEP_AFTERCAMERADRAW_PREPASS, this, this._afterCameraDraw); this.scene._beforeRenderTargetDrawStage.registerStep(SceneComponentConstants.STEP_BEFORERENDERTARGETDRAW_PREPASS, this, this._beforeRenderTargetDraw); this.scene._afterRenderTargetDrawStage.registerStep(SceneComponentConstants.STEP_AFTERCAMERADRAW_PREPASS, this, this._afterRenderTargetDraw); this.scene._beforeClearStage.registerStep(SceneComponentConstants.STEP_BEFORECLEAR_PREPASS, this, this._beforeClearStage); this.scene._beforeRenderTargetClearStage.registerStep(SceneComponentConstants.STEP_BEFORERENDERTARGETCLEAR_PREPASS, this, this._beforeRenderTargetClearStage); this.scene._beforeRenderingMeshStage.registerStep(SceneComponentConstants.STEP_BEFORERENDERINGMESH_PREPASS, this, this._beforeRenderingMeshStage); this.scene._afterRenderingMeshStage.registerStep(SceneComponentConstants.STEP_AFTERRENDERINGMESH_PREPASS, this, this._afterRenderingMeshStage); } _beforeRenderTargetDraw(renderTarget, faceIndex, layer) { if (this.scene.prePassRenderer && !renderTarget.noPrePassRenderer) { this.scene.prePassRenderer._setRenderTarget(renderTarget._prePassRenderTarget); this.scene.prePassRenderer._beforeDraw(undefined, faceIndex, layer); } } _afterRenderTargetDraw(renderTarget, faceIndex, layer) { if (this.scene.prePassRenderer && !renderTarget.noPrePassRenderer) { this.scene.prePassRenderer._afterDraw(faceIndex, layer); } } _beforeRenderTargetClearStage(renderTarget) { if (this.scene.prePassRenderer && !renderTarget.noPrePassRenderer) { if (!renderTarget._prePassRenderTarget) { renderTarget._prePassRenderTarget = this.scene.prePassRenderer._createRenderTarget(renderTarget.name + "_prePassRTT", renderTarget); } this.scene.prePassRenderer._setRenderTarget(renderTarget._prePassRenderTarget); this.scene.prePassRenderer._clear(); } } _beforeCameraDraw(camera) { if (this.scene.prePassRenderer) { this.scene.prePassRenderer._setRenderTarget(null); this.scene.prePassRenderer._beforeDraw(camera); } } _afterCameraDraw() { if (this.scene.prePassRenderer) { this.scene.prePassRenderer._afterDraw(); } } _beforeClearStage() { if (this.scene.prePassRenderer) { this.scene.prePassRenderer._setRenderTarget(null); this.scene.prePassRenderer._clear(); } } _beforeRenderingMeshStage(mesh, subMesh, batch, effect) { if (!effect) { return; } // Render to MRT const scene = mesh.getScene(); if (scene.prePassRenderer) { scene.prePassRenderer.bindAttachmentsForEffect(effect, subMesh); } } _afterRenderingMeshStage(mesh) { const scene = mesh.getScene(); if (scene.prePassRenderer) { scene.prePassRenderer.restoreAttachments(); } } /** * 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() { this.scene.disablePrePassRenderer(); } } let _Registered = false; /** * Register side effects for prePassRendererSceneComponent. * Safe to call multiple times; only the first call has an effect. * @param prePassRendererClass The PrePassRenderer class to register the component for */ function RegisterPrePassRendererSceneComponent(prePassRendererClass) { if (_Registered) { return; } _Registered = true; Object.defineProperty(Scene.prototype, "prePassRenderer", { get: function () { return this._prePassRenderer; }, set: function (value) { if (value && value.isSupported) { this._prePassRenderer = value; } }, enumerable: true, configurable: true, }); Scene.prototype.enablePrePassRenderer = function () { if (this._prePassRenderer) { return this._prePassRenderer; } this._prePassRenderer = new prePassRendererClass(this); if (!this._prePassRenderer.isSupported) { this._prePassRenderer = null; Logger.Error("PrePassRenderer needs WebGL 2 support.\n" + "Maybe you tried to use the following features that need the PrePassRenderer :\n" + " + Subsurface Scattering"); } return this._prePassRenderer; }; Scene.prototype.disablePrePassRenderer = function () { if (!this._prePassRenderer) { return; } this._prePassRenderer.dispose(); this._prePassRenderer = null; }; prePassRendererClass._SceneComponentInitialization = (scene) => { // Register the G Buffer component to the scene. let component = scene._getComponent(SceneComponentConstants.NAME_PREPASSRENDERER); if (!component) { component = new PrePassRendererSceneComponent(scene); scene._addComponent(component); } }; } /** This file must only contain pure code and pure imports */ /** * Renders a pre pass of the scene * This means every mesh in the scene will be rendered to a render target texture * And then this texture will be composited to the rendering canvas with post processes * It is necessary for effects like subsurface scattering or deferred shading */ class PrePassRenderer { /** * Indicates if the prepass renderer is generating normals in world space or camera space (default: camera space) */ get generateNormalsInWorldSpace() { return this._generateNormalsInWorldSpace; } set generateNormalsInWorldSpace(value) { if (this._generateNormalsInWorldSpace === value) { return; } this._generateNormalsInWorldSpace = value; this._markAllMaterialsAsPrePassDirty(); } /** * Returns the index of a texture in the multi render target texture array. * @param type Texture type * @returns The index */ getIndex(type) { return this._textureIndices[type]; } /** * How many samples are used for MSAA of the scene render target */ get samples() { return this.defaultRT.samples; } set samples(n) { this.defaultRT.samples = n; } /** * 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. */ get useSpecificClearForDepthTexture() { return this._useSpecificClearForDepthTexture; } set useSpecificClearForDepthTexture(value) { if (this._useSpecificClearForDepthTexture === value) { return; } this._useSpecificClearForDepthTexture = value; this._isDirty = true; } /** * @returns the prepass render target for the rendering pass. * If we are currently rendering a render target, it returns the PrePassRenderTarget * associated with that render target. Otherwise, it returns the scene default PrePassRenderTarget */ getRenderTarget() { return this._currentTarget; } /** * @internal * Managed by the scene component * @param prePassRenderTarget */ _setRenderTarget(prePassRenderTarget) { if (prePassRenderTarget) { this._currentTarget = prePassRenderTarget; } else { this._currentTarget = this.defaultRT; this._engine.currentRenderPassId = this._scene.activeCamera?.renderPassId ?? this._currentTarget.renderPassId; } } /** * Returns true if the currently rendered prePassRenderTarget is the one * associated with the scene. */ get currentRTisSceneRT() { return this._currentTarget === this.defaultRT; } _refreshGeometryBufferRendererLink() { if (!this.doNotUseGeometryRendererFallback) { this._geometryBuffer = this._scene.enableGeometryBufferRenderer(); if (!this._geometryBuffer) { // Not supported this.doNotUseGeometryRendererFallback = true; return; } this._geometryBuffer._linkPrePassRenderer(this); } else { if (this._geometryBuffer) { this._geometryBuffer._unlinkPrePassRenderer(); } this._geometryBuffer = null; this._scene.disableGeometryBufferRenderer(); } } /** * Indicates if the prepass is enabled */ get enabled() { return this._enabled; } /** * Instantiates a prepass renderer * @param scene The scene */ constructor(scene) { /** * To save performance, we can excluded skinned meshes from the prepass */ this.excludedSkinnedMesh = []; /** * Force material to be excluded from the prepass * Can be useful when `useGeometryBufferFallback` is set to `true` * and you don't want a material to show in the effect. */ this.excludedMaterials = []; /** * Number of textures in the multi render target texture where the scene is directly rendered */ this.mrtCount = 0; this._mrtTypes = []; this._mrtFormats = []; this._mrtLayout = []; this._mrtNames = []; this._textureIndices = []; this._generateNormalsInWorldSpace = false; this._useSpecificClearForDepthTexture = false; this._isDirty = true; /** * Configuration for prepass effects */ this._effectConfigurations = []; /** * Prevents the PrePassRenderer from using the GeometryBufferRenderer as a fallback */ this.doNotUseGeometryRendererFallback = true; /** * All the render targets generated by prepass */ this.renderTargets = []; 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._enabled = false; this._geometryBufferRenderList = []; this._needsCompositionForThisPass = false; this._postProcessesSourceForThisPass = []; this._postProcessChainForThisPass = []; this._postProcessesForUpdate = []; /** * Set to true to disable gamma transform in PrePass. * Can be useful in case you already proceed to gamma transform on a material level * and your post processes don't need to be in linear color space. */ this.disableGammaTransform = false; this._scene = scene; this._engine = scene.getEngine(); let type = Constants.TEXTURETYPE_UNSIGNED_BYTE; if (this._engine._caps.textureFloat && this._engine._caps.textureFloatLinearFiltering) { type = Constants.TEXTURETYPE_FLOAT; } else if (this._engine._caps.textureHalfFloat && this._engine._caps.textureHalfFloatLinearFiltering) { type = Constants.TEXTURETYPE_HALF_FLOAT; } for (let i = 0; i < PrePassRenderer.TextureFormats.length; ++i) { const format = PrePassRenderer.TextureFormats[i].format; if (PrePassRenderer.TextureFormats[i].type === Constants.TEXTURETYPE_FLOAT) { PrePassRenderer.TextureFormats[i].type = type; if (type === Constants.TEXTURETYPE_FLOAT && (format === Constants.TEXTUREFORMAT_R || format === Constants.TEXTUREFORMAT_RG || format === Constants.TEXTUREFORMAT_RGBA) && !this._engine._caps.supportFloatTexturesResolve) { // We don't know in advance if the texture will be used as a resolve target, so we revert to half_float if the extension to resolve full float textures is not supported PrePassRenderer.TextureFormats[i].type = Constants.TEXTURETYPE_HALF_FLOAT; } } } RegisterPrePassRendererSceneComponent(PrePassRenderer); RegisterGeometryBufferRendererSceneComponent(GeometryBufferRenderer); PrePassRenderer._SceneComponentInitialization(this._scene); this.defaultRT = this._createRenderTarget("sceneprePassRT", null); this._currentTarget = this.defaultRT; } /** * Creates a new PrePassRenderTarget * This should be the only way to instantiate a `PrePassRenderTarget` * @param name Name of the `PrePassRenderTarget` * @param renderTargetTexture RenderTarget the `PrePassRenderTarget` will be attached to. * Can be `null` if the created `PrePassRenderTarget` is attached to the scene (default framebuffer). * @internal */ _createRenderTarget(name, renderTargetTexture) { const rt = new PrePassRenderTarget(name, renderTargetTexture, { width: this._engine.getRenderWidth(), height: this._engine.getRenderHeight() }, 0, this._scene, { generateMipMaps: false, generateStencilBuffer: this._engine.isStencilEnable, defaultType: Constants.TEXTURETYPE_UNSIGNED_BYTE, types: [], drawOnlyOnFirstAttachmentByDefault: true, }); this.renderTargets.push(rt); if (this._enabled) { // The pre-pass renderer is already enabled, so make sure we create the render target with the correct number of textures this._update(); } return rt; } /** * Indicates if rendering a prepass is supported */ get isSupported() { return this._scene.getEngine().getCaps().drawBuffersExtension; } /** * Sets the proper output textures to draw in the engine. * @param effect The effect that is drawn. It can be or not be compatible with drawing to several output textures. * @param subMesh Submesh on which the effect is applied */ bindAttachmentsForEffect(effect, subMesh) { const material = subMesh.getMaterial(); const isPrePassCapable = material && material.isPrePassCapable; const excluded = material && this.excludedMaterials.indexOf(material) !== -1; if (this.enabled && this._currentTarget.enabled) { if (effect._multiTarget && isPrePassCapable && !excluded) { this._engine.bindAttachments(this._multiRenderAttachments); } else { if (this._engine._currentRenderTarget) { this._engine.bindAttachments(this._defaultAttachments); } else { this._engine.restoreSingleAttachment(); } if (this._geometryBuffer && this.currentRTisSceneRT && !excluded) { this._geometryBuffer.renderList.push(subMesh.getRenderingMesh()); } } } } _reinitializeAttachments() { const multiRenderLayout = []; const clearLayout = [false]; const clearDepthLayout = [false]; const defaultLayout = [true]; for (let i = 0; i < this.mrtCount; i++) { multiRenderLayout.push(true); if (i > 0) { if (this._useSpecificClearForDepthTexture && this._mrtLayout[i] === Constants.PREPASS_DEPTH_TEXTURE_TYPE) { clearLayout.push(false); clearDepthLayout.push(true); } else { clearLayout.push(true); clearDepthLayout.push(false); } defaultLayout.push(false); } } this._multiRenderAttachments = this._engine.buildTextureLayout(multiRenderLayout); this._clearAttachments = this._engine.buildTextureLayout(clearLayout); this._clearDepthAttachments = this._engine.buildTextureLayout(clearDepthLayout); this._defaultAttachments = this._engine.buildTextureLayout(defaultLayout); } _resetLayout() { for (let i = 0; i < PrePassRenderer.TextureFormats.length; i++) { this._textureIndices[PrePassRenderer.TextureForm