diff --git a/packages/dev/core/src/Materials/Node/Blocks/PBR/reflectionBlock.ts b/packages/dev/core/src/Materials/Node/Blocks/PBR/reflectionBlock.ts index fa28bcb5767..87213c76b1e 100644 --- a/packages/dev/core/src/Materials/Node/Blocks/PBR/reflectionBlock.ts +++ b/packages/dev/core/src/Materials/Node/Blocks/PBR/reflectionBlock.ts @@ -456,6 +456,12 @@ export class ReflectionBlock extends ReflectionTextureBaseBlock { #endif #ifdef REALTIME_FILTERING , ${this._vReflectionFilteringInfoName} + #ifdef IBL_CDF_FILTERING + , icdfxSampler // ** not handled ** + ${isWebGPU ? `, icdfxSamplerSampler` : ""} + , icdfySampler // ** not handled ** + ${isWebGPU ? `, icdfySamplerSampler` : ""} + #endif #endif ); #endif\n`; diff --git a/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts b/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts index 77138c03e49..74a60518390 100644 --- a/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts +++ b/packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts @@ -80,6 +80,7 @@ export class PBRMaterialDefines extends MaterialDefines implements IImageProcess public NUM_SAMPLES = "0"; public REALTIME_FILTERING = false; + public IBL_CDF_FILTERING = false; public MAINUV1 = false; public MAINUV2 = false; @@ -1488,6 +1489,8 @@ export abstract class PBRBaseMaterial extends PushMaterial { "morphTargets", "oitDepthSampler", "oitFrontColorSampler", + "icdfxSampler", + "icdfySampler", ]; const uniformBuffers = ["Material", "Scene", "Mesh"]; @@ -1653,6 +1656,9 @@ export abstract class PBRBaseMaterial extends PushMaterial { } defines.REALTIME_FILTERING = true; + if (this.getScene().iblCdfGenerator) { + defines.IBL_CDF_FILTERING = true; + } } else { defines.REALTIME_FILTERING = false; } @@ -2297,6 +2303,13 @@ export abstract class PBRBaseMaterial extends PushMaterial { if (defines.USEIRRADIANCEMAP) { ubo.setTexture("irradianceSampler", reflectionTexture.irradianceTexture); } + + //if realtime filtering and using CDF maps, set them. + const cdfGenerator = this.getScene().iblCdfGenerator; + if (this.realTimeFiltering && cdfGenerator) { + ubo.setTexture("icdfxSampler", cdfGenerator.getIcdfxTexture()); + ubo.setTexture("icdfySampler", cdfGenerator.getIcdfyTexture()); + } } if (defines.ENVIRONMENTBRDF) { diff --git a/packages/dev/core/src/Rendering/IBLShadows/iblShadowsRenderPipeline.ts b/packages/dev/core/src/Rendering/IBLShadows/iblShadowsRenderPipeline.ts index 2a74e080d1f..9807d38c790 100644 --- a/packages/dev/core/src/Rendering/IBLShadows/iblShadowsRenderPipeline.ts +++ b/packages/dev/core/src/Rendering/IBLShadows/iblShadowsRenderPipeline.ts @@ -3,7 +3,6 @@ import { EngineStore } from "../../Engines/engineStore"; import { Matrix, Vector3, Vector4, Quaternion } from "../../Maths/math.vector"; import type { Mesh } from "../../Meshes/mesh"; import type { Scene } from "../../scene"; -import type { BaseTexture } from "../../Materials/Textures/baseTexture"; import { Texture } from "../../Materials/Textures/texture"; import { Logger } from "../../Misc/logger"; import { _IblShadowsVoxelRenderer } from "./iblShadowsVoxelRenderer"; @@ -11,7 +10,6 @@ import { _IblShadowsVoxelTracingPass } from "./iblShadowsVoxelTracingPass"; import { PostProcess } from "../../PostProcesses/postProcess"; import type { PostProcessOptions } from "../../PostProcesses/postProcess"; -import { _IblShadowsImportanceSamplingRenderer } from "./iblShadowsImportanceSamplingRenderer"; import { _IblShadowsSpatialBlurPass } from "./iblShadowsSpatialBlurPass"; import { _IblShadowsAccumulationPass } from "./iblShadowsAccumulationPass"; import { PostProcessRenderPipeline } from "../../PostProcesses/RenderPipeline/postProcessRenderPipeline"; @@ -128,7 +126,6 @@ export class IblShadowsRenderPipeline extends PostProcessRenderPipeline { private _shadowCastingMeshes: Mesh[] = []; private _voxelRenderer: _IblShadowsVoxelRenderer; - private _importanceSamplingRenderer: _IblShadowsImportanceSamplingRenderer; private _voxelTracingPass: _IblShadowsVoxelTracingPass; private _spatialBlurPass: _IblShadowsSpatialBlurPass; private _accumulationPass: _IblShadowsAccumulationPass; @@ -276,16 +273,6 @@ export class IblShadowsRenderPipeline extends PostProcessRenderPipeline { this._updateSSShadowParams(); } - /** - * Set the IBL image to be used for shadowing. It can be either a cubemap - * or a 2D equirectangular texture. - * @param iblSource The texture to use for IBL shadowing - */ - public setIblTexture(iblSource: BaseTexture) { - if (!this._importanceSamplingRenderer) return; - this._importanceSamplingRenderer.iblSource = iblSource; - } - /** * Returns the texture containing the voxel grid data * @returns The texture containing the voxel grid data @@ -299,32 +286,6 @@ export class IblShadowsRenderPipeline extends PostProcessRenderPipeline { return this._dummyTexture3d; } - /** - * Returns the texture containing the importance sampling CDF data for the IBL shadow pipeline - * @returns The texture containing the importance sampling CDF data for the IBL shadow pipeline - * @internal - */ - public _getIcdfyTexture(): Texture { - const tex = this._importanceSamplingRenderer!.getIcdfyTexture(); - if (tex && tex.isReady()) { - return tex; - } - return this._dummyTexture2d; - } - - /** - * Returns the texture containing the importance sampling CDF data for the IBL shadow pipeline - * @returns The texture containing the importance sampling CDF data for the IBL shadow pipeline - * @internal - */ - public _getIcdfxTexture(): Texture { - const tex = this._importanceSamplingRenderer.getIcdfxTexture(); - if (tex && tex.isReady()) { - return tex; - } - return this._dummyTexture2d; - } - /** * Returns the noise texture. * @returns The noise texture. @@ -405,25 +366,25 @@ export class IblShadowsRenderPipeline extends PostProcessRenderPipeline { /** * Turn on or off the debug view of the CDF importance sampling data */ - public get importanceSamplingDebugEnabled(): boolean { - return this._importanceSamplingRenderer?.debugEnabled; + public get cdfDebugEnabled(): boolean { + return this.scene.iblCdfGenerator ? this.scene.iblCdfGenerator.debugEnabled : false; } /** * Turn on or off the debug view of the CDF importance sampling data */ - public set importanceSamplingDebugEnabled(enabled: boolean) { - if (!this._importanceSamplingRenderer) return; + public set cdfDebugEnabled(enabled: boolean) { + 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._importanceSamplingRenderer.debugEnabled) return; - this._importanceSamplingRenderer.debugEnabled = enabled; + if (enabled === this.scene.iblCdfGenerator.debugEnabled) return; + this.scene.iblCdfGenerator.debugEnabled = enabled; if (enabled) { - this._enableEffect(this._importanceSamplingRenderer.debugPassName, this.cameras); + this._enableEffect(this.scene.iblCdfGenerator.debugPassName, this.cameras); } else { - this._disableEffect(this._importanceSamplingRenderer.debugPassName, this.cameras); + this._disableEffect(this.scene.iblCdfGenerator.debugPassName, this.cameras); } } @@ -657,11 +618,11 @@ export class IblShadowsRenderPipeline extends PostProcessRenderPipeline { public set allowDebugPasses(value: boolean) { if (this._allowDebugPasses === value) return; this._allowDebugPasses = value; - if (value) { - if (this._importanceSamplingRenderer.isReady()) { + if (value && this.scene.iblCdfGenerator) { + if (this.scene.iblCdfGenerator.isReady()) { this._createDebugPasses(); } else { - this._importanceSamplingRenderer.onReadyObservable.addOnce(() => { + this.scene.iblCdfGenerator.onGeneratedObservable.addOnce(() => { this._createDebugPasses(); }); } @@ -788,7 +749,7 @@ export class IblShadowsRenderPipeline extends PostProcessRenderPipeline { 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, @@ -796,7 +757,6 @@ export class IblShadowsRenderPipeline extends PostProcessRenderPipeline { options ? options.resolutionExp : 6, options.triPlanarVoxelization !== undefined ? options.triPlanarVoxelization : true ); - this._importanceSamplingRenderer = new _IblShadowsImportanceSamplingRenderer(this.scene); this._voxelTracingPass = new _IblShadowsVoxelTracingPass(this.scene, this); this._spatialBlurPass = new _IblShadowsSpatialBlurPass(this.scene, this); this._accumulationPass = new _IblShadowsAccumulationPass(this.scene, this); @@ -814,9 +774,6 @@ export class IblShadowsRenderPipeline extends PostProcessRenderPipeline { 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); - if (this.scene.environmentTexture) { - this._importanceSamplingRenderer.iblSource = this.scene.environmentTexture; - } scene.postProcessRenderPipelineManager.addPipeline(this); @@ -827,10 +784,12 @@ export class IblShadowsRenderPipeline extends PostProcessRenderPipeline { 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. - this._importanceSamplingRenderer.onReadyObservable.add(() => { - this._setPluginParameters(); - this.onNewIblReadyObservable.notifyObservers(); - }); + if (this.scene.iblCdfGenerator) { + this.scene.iblCdfGenerator.onGeneratedObservable.add(() => { + this._setPluginParameters(); + this.onNewIblReadyObservable.notifyObservers(); + }); + } } private _handleResize() { @@ -887,14 +846,19 @@ export class IblShadowsRenderPipeline extends PostProcessRenderPipeline { } private _createDebugPasses() { - this._debugPasses = [ - { pass: this._importanceSamplingRenderer.getDebugPassPP(), enabled: this.importanceSamplingDebugEnabled }, + 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 }, - ]; + { pass: this._getGBufferDebugPass(), enabled: this.gbufferDebugEnabled } + ); for (let i = 0; i < this._debugPasses.length; i++) { if (!this._debugPasses[i].pass) continue; this.addEffect( @@ -938,7 +902,7 @@ export class IblShadowsRenderPipeline extends PostProcessRenderPipeline { private _updateDebugPasses() { let count = 0; if (this._gbufferDebugEnabled) count++; - if (this.importanceSamplingDebugEnabled) count++; + if (this.cdfDebugEnabled) count++; if (this.voxelDebugEnabled) count++; if (this.voxelTracingDebugEnabled) count++; if (this.spatialBlurPassDebugEnabled) count++; @@ -959,8 +923,8 @@ export class IblShadowsRenderPipeline extends PostProcessRenderPipeline { } } - if (this.importanceSamplingDebugEnabled) { - this._importanceSamplingRenderer.setDebugDisplayParams(x, y, cols, rows); + if (this.cdfDebugEnabled && this.scene.iblCdfGenerator) { + this.scene.iblCdfGenerator.setDebugDisplayParams(x, y, cols, rows); x -= width; if (x <= -1) { x = 0; @@ -1111,7 +1075,8 @@ export class IblShadowsRenderPipeline extends PostProcessRenderPipeline { return ( this._noiseTexture.isReady() && this._voxelRenderer.isReady() && - this._importanceSamplingRenderer.isReady() && + this.scene.iblCdfGenerator && + this.scene.iblCdfGenerator.isReady() && (!this._voxelTracingPass || this._voxelTracingPass.isReady()) && (!this._spatialBlurPass || this._spatialBlurPass.isReady()) && (!this._accumulationPass || this._accumulationPass.isReady()) @@ -1137,7 +1102,6 @@ export class IblShadowsRenderPipeline extends PostProcessRenderPipeline { this._disposeEffectPasses(); this._noiseTexture.dispose(); this._voxelRenderer.dispose(); - this._importanceSamplingRenderer.dispose(); this._voxelTracingPass.dispose(); this._spatialBlurPass.dispose(); this._accumulationPass.dispose(); diff --git a/packages/dev/core/src/Rendering/IBLShadows/iblShadowsVoxelTracingPass.ts b/packages/dev/core/src/Rendering/IBLShadows/iblShadowsVoxelTracingPass.ts index 83b148444ef..f4f16ef33a7 100644 --- a/packages/dev/core/src/Rendering/IBLShadows/iblShadowsVoxelTracingPass.ts +++ b/packages/dev/core/src/Rendering/IBLShadows/iblShadowsVoxelTracingPass.ts @@ -359,8 +359,11 @@ export class _IblShadowsVoxelTracingPass { this._outputTexture.setVector4("shadowOpacity", this._opacityParameters); this._outputTexture.setTexture("voxelGridSampler", voxelGrid); this._outputTexture.setTexture("blueNoiseSampler", this._renderPipeline!._getNoiseTexture()); - this._outputTexture.setTexture("icdfySampler", this._renderPipeline!._getIcdfyTexture()); - this._outputTexture.setTexture("icdfxSampler", this._renderPipeline!._getIcdfxTexture()); + const cdfGenerator = this._scene.iblCdfGenerator; + if (cdfGenerator) { + this._outputTexture.setTexture("icdfySampler", cdfGenerator.getIcdfyTexture()); + this._outputTexture.setTexture("icdfxSampler", cdfGenerator.getIcdfxTexture()); + } if (this._debugVoxelMarchEnabled) { this._outputTexture.defines += "#define VOXEL_MARCH_DIAGNOSTIC_INFO_OPTION 1u\n"; } @@ -395,8 +398,9 @@ export class _IblShadowsVoxelTracingPass { return ( this._outputTexture.isReady() && !(this._debugPassPP && !this._debugPassPP.isReady()) && - this._renderPipeline!._getIcdfyTexture().isReady() && - this._renderPipeline!._getIcdfxTexture().isReady() && + this._scene.iblCdfGenerator && + this._scene.iblCdfGenerator.getIcdfyTexture().isReady() && + this._scene.iblCdfGenerator.getIcdfxTexture().isReady() && this._renderPipeline!._getVoxelGridTexture().isReady() ); } diff --git a/packages/dev/core/src/Rendering/IBLShadows/iblShadowsImportanceSamplingRenderer.ts b/packages/dev/core/src/Rendering/iblCdfGenerator.ts similarity index 73% rename from packages/dev/core/src/Rendering/IBLShadows/iblShadowsImportanceSamplingRenderer.ts rename to packages/dev/core/src/Rendering/iblCdfGenerator.ts index 1aa25372b14..7017412d2b9 100644 --- a/packages/dev/core/src/Rendering/IBLShadows/iblShadowsImportanceSamplingRenderer.ts +++ b/packages/dev/core/src/Rendering/iblCdfGenerator.ts @@ -1,26 +1,26 @@ -import { Constants } from "../../Engines/constants"; -import type { AbstractEngine } from "../../Engines/abstractEngine"; +import { Constants } from "../Engines/constants"; +import type { AbstractEngine } from "../Engines/abstractEngine"; -import type { Scene } from "../../scene"; -import { Texture } from "../../Materials/Textures/texture"; -import type { TextureSize } from "../../Materials/Textures/textureCreationOptions"; -import { ProceduralTexture } from "../../Materials/Textures/Procedurals/proceduralTexture"; -import type { IProceduralTextureCreationOptions } from "../../Materials/Textures/Procedurals/proceduralTexture"; -import { PostProcess } from "../../PostProcesses/postProcess"; -import type { PostProcessOptions } from "../../PostProcesses/postProcess"; -import { Vector4 } from "../../Maths/math.vector"; -import { RawTexture } from "../../Materials/Textures/rawTexture"; -import type { BaseTexture } from "../../Materials/Textures/baseTexture"; -import { Observable } from "../../Misc/observable"; -import type { CubeTexture } from "../../Materials/Textures/cubeTexture"; +import type { Scene } from "../scene"; +import { Texture } from "../Materials/Textures/texture"; +import type { TextureSize } from "../Materials/Textures/textureCreationOptions"; +import { ProceduralTexture } from "../Materials/Textures/Procedurals/proceduralTexture"; +import type { IProceduralTextureCreationOptions } from "../Materials/Textures/Procedurals/proceduralTexture"; +import { PostProcess } from "../PostProcesses/postProcess"; +import type { PostProcessOptions } from "../PostProcesses/postProcess"; +import { Vector4 } from "../Maths/math.vector"; +import { RawTexture } from "../Materials/Textures/rawTexture"; +import type { BaseTexture } from "../Materials/Textures/baseTexture"; +import { Observable } from "../Misc/observable"; +import type { CubeTexture } from "../Materials/Textures/cubeTexture"; import { ShaderLanguage } from "core/Materials/shaderLanguage"; +import { Engine } from "../Engines/engine"; +import { _WarnImport } from "../Misc/devTools"; /** - * Build cdf maps for IBL importance sampling during IBL shadow computation. - * This should not be instanciated directly, as it is part of a scene component - * @internal + * Build cdf maps to be used for IBL importance sampling. */ -export class _IblShadowsImportanceSamplingRenderer { +export class IblCdfGenerator { private _scene: Scene; private _engine: AbstractEngine; @@ -29,7 +29,7 @@ export class _IblShadowsImportanceSamplingRenderer { private _cdfxPT: ProceduralTexture; private _icdfxPT: ProceduralTexture; private _iblSource: BaseTexture; - + private _dummyTexture: RawTexture; /** * Gets the IBL source texture being used by the importance sampling renderer */ @@ -76,7 +76,7 @@ export class _IblShadowsImportanceSamplingRenderer { // Once the textures are generated, notify that they are ready to use. this._icdfxPT.onGeneratedObservable.addOnce(() => { - this.onReadyObservable.notifyObservers(); + this.onGeneratedObservable.notifyObservers(); }); } @@ -84,16 +84,16 @@ export class _IblShadowsImportanceSamplingRenderer { * Return the cumulative distribution function (CDF) Y texture * @returns Return the cumulative distribution function (CDF) Y texture */ - public getIcdfyTexture(): ProceduralTexture { - return this._icdfyPT; + public getIcdfyTexture(): Texture { + return this._icdfyPT ? this._icdfyPT : this._dummyTexture; } /** * Return the cumulative distribution function (CDF) X texture * @returns Return the cumulative distribution function (CDF) X texture */ - public getIcdfxTexture(): ProceduralTexture { - return this._icdfxPT; + public getIcdfxTexture(): Texture { + return this._icdfxPT ? this._icdfxPT : this._dummyTexture; } /** Enable the debug view for this pass */ @@ -131,6 +131,13 @@ export class _IblShadowsImportanceSamplingRenderer { return this._debugPass; } + /** + * @internal + */ + public static _SceneComponentInitialization: (scene: Scene) => void = (_) => { + throw _WarnImport("IblCdfGeneratorSceneComponentSceneComponent"); + }; + /** * Instanciates the importance sampling renderer * @param scene Scene to attach to @@ -139,12 +146,15 @@ export class _IblShadowsImportanceSamplingRenderer { constructor(scene: Scene) { this._scene = scene; this._engine = scene.getEngine(); + const blackPixels = new Uint8Array([0, 0, 0, 255]); + this._dummyTexture = new RawTexture(blackPixels, 1, 1, Engine.TEXTUREFORMAT_RGBA, scene, false); + IblCdfGenerator._SceneComponentInitialization(this._scene); } /** * Observable that triggers when the importance sampling renderer is ready */ - public onReadyObservable: Observable = new Observable(); + public onGeneratedObservable: Observable = new Observable(); private _createTextures() { const size: TextureSize = this._iblSource ? this._iblSource.getSize() : { width: 1, height: 1 }; @@ -178,9 +188,9 @@ export class _IblShadowsImportanceSamplingRenderer { shaderLanguage: isWebGPU ? ShaderLanguage.WGSL : ShaderLanguage.GLSL, extraInitializationsAsync: async () => { if (isWebGPU) { - await Promise.all([import("../../ShadersWGSL/iblShadowsCdfx.fragment"), import("../../ShadersWGSL/iblShadowsCdfy.fragment")]); + await Promise.all([import("../ShadersWGSL/iblCdfx.fragment"), import("../ShadersWGSL/iblCdfy.fragment")]); } else { - await Promise.all([import("../../Shaders/iblShadowsCdfx.fragment"), import("../../Shaders/iblShadowsCdfy.fragment")]); + await Promise.all([import("../Shaders/iblCdfx.fragment"), import("../Shaders/iblCdfy.fragment")]); } }, }; @@ -193,13 +203,13 @@ export class _IblShadowsImportanceSamplingRenderer { shaderLanguage: isWebGPU ? ShaderLanguage.WGSL : ShaderLanguage.GLSL, extraInitializationsAsync: async () => { if (isWebGPU) { - await Promise.all([import("../../ShadersWGSL/iblShadowsIcdfx.fragment"), import("../../ShadersWGSL/iblShadowsIcdfy.fragment")]); + await Promise.all([import("../ShadersWGSL/iblIcdfx.fragment"), import("../ShadersWGSL/iblIcdfy.fragment")]); } else { - await Promise.all([import("../../Shaders/iblShadowsIcdfx.fragment"), import("../../Shaders/iblShadowsIcdfy.fragment")]); + await Promise.all([import("../Shaders/iblIcdfx.fragment"), import("../Shaders/iblIcdfy.fragment")]); } }, }; - this._cdfyPT = new ProceduralTexture("cdfyTexture", { width: size.width, height: size.height + 1 }, "iblShadowsCdfy", this._scene, cdfOptions, false, false); + this._cdfyPT = new ProceduralTexture("cdfyTexture", { width: size.width, height: size.height + 1 }, "iblCdfy", this._scene, cdfOptions, false, false); this._cdfyPT.autoClear = false; this._cdfyPT.setTexture("iblSource", this._iblSource as Texture); this._cdfyPT.setInt("iblHeight", size.height); @@ -207,15 +217,15 @@ export class _IblShadowsImportanceSamplingRenderer { this._cdfyPT.defines = "#define IBL_USE_CUBE_MAP\n"; } this._cdfyPT.refreshRate = 0; - this._icdfyPT = new ProceduralTexture("icdfyTexture", { width: size.width, height: size.height }, "iblShadowsIcdfy", this._scene, icdfOptions, false, false); + this._icdfyPT = new ProceduralTexture("icdfyTexture", { width: size.width, height: size.height }, "iblIcdfy", this._scene, icdfOptions, false, false); this._icdfyPT.autoClear = false; this._icdfyPT.setTexture("cdfy", this._cdfyPT); this._icdfyPT.refreshRate = 0; - this._cdfxPT = new ProceduralTexture("cdfxTexture", { width: size.width + 1, height: 1 }, "iblShadowsCdfx", this._scene, cdfOptions, false, false); + this._cdfxPT = new ProceduralTexture("cdfxTexture", { width: size.width + 1, height: 1 }, "iblCdfx", this._scene, cdfOptions, false, false); this._cdfxPT.autoClear = false; this._cdfxPT.setTexture("cdfy", this._cdfyPT); this._cdfxPT.refreshRate = 0; - this._icdfxPT = new ProceduralTexture("icdfxTexture", { width: size.width, height: 1 }, "iblShadowsIcdfx", this._scene, icdfOptions, false, false); + this._icdfxPT = new ProceduralTexture("icdfxTexture", { width: size.width, height: 1 }, "iblIcdfx", this._scene, icdfOptions, false, false); this._icdfxPT.autoClear = false; this._icdfxPT.setTexture("cdfx", this._cdfxPT); this._icdfxPT.refreshRate = 0; @@ -245,13 +255,13 @@ export class _IblShadowsImportanceSamplingRenderer { shaderLanguage: isWebGPU ? ShaderLanguage.WGSL : ShaderLanguage.GLSL, extraInitializations: (useWebGPU: boolean, list: Promise[]) => { if (useWebGPU) { - list.push(import("../../ShadersWGSL/iblShadowsImportanceSamplingDebug.fragment")); + list.push(import("../ShadersWGSL/importanceSamplingDebug.fragment")); } else { - list.push(import("../../Shaders/iblShadowsImportanceSamplingDebug.fragment")); + list.push(import("../Shaders/importanceSamplingDebug.fragment")); } }, }; - this._debugPass = new PostProcess(this._debugPassName, "iblShadowsImportanceSamplingDebug", debugOptions); + this._debugPass = new PostProcess(this._debugPassName, "importanceSamplingDebug", debugOptions); const debugEffect = this._debugPass.getEffect(); if (debugEffect) { debugEffect.defines = this._iblSource?.isCube ? "#define IBL_USE_CUBE_MAP\n" : ""; @@ -294,9 +304,10 @@ export class _IblShadowsImportanceSamplingRenderer { */ public dispose() { this._disposeTextures(); + this._dummyTexture.dispose(); if (this._debugPass) { this._debugPass.dispose(); } - this.onReadyObservable.clear(); + this.onGeneratedObservable.clear(); } } diff --git a/packages/dev/core/src/Rendering/iblCdfGeneratorSceneComponent.ts b/packages/dev/core/src/Rendering/iblCdfGeneratorSceneComponent.ts new file mode 100644 index 00000000000..6861f98dbd4 --- /dev/null +++ b/packages/dev/core/src/Rendering/iblCdfGeneratorSceneComponent.ts @@ -0,0 +1,130 @@ +import type { Nullable } from "../types"; +import { Scene } from "../scene"; +import type { ISceneComponent } from "../sceneComponent"; +import { SceneComponentConstants } from "../sceneComponent"; +import { IblCdfGenerator } from "./iblCdfGenerator"; +import type { BaseTexture } from "../Materials/Textures/baseTexture"; +import type { Observer } from "../Misc/observable"; + +declare module "../scene" { + export interface Scene { + /** @internal (Backing field) */ + _iblCdfGenerator: Nullable; + + /** + * Gets or Sets the current CDF generator associated to the scene. + * The CDF (cumulative distribution function) generator creates CDF maps + * for a given IBL texture that can then be used for more efficient + * importance sampling. + */ + iblCdfGenerator: Nullable; + + /** + * Enables a IblCdfGenerator and associates it with the scene. + * @returns the IblCdfGenerator + */ + enableIblCdfGenerator(): Nullable; + + /** + * Disables the GeometryBufferRender associated with the scene + */ + disableIblCdfGenerator(): void; + } +} + +Object.defineProperty(Scene.prototype, "iblCdfGenerator", { + get: function (this: Scene) { + return this._iblCdfGenerator; + }, + set: function (this: Scene, value: Nullable) { + if (value) { + this._iblCdfGenerator = value; + } + }, + enumerable: true, + configurable: true, +}); + +Scene.prototype.enableIblCdfGenerator = function (): Nullable { + if (this._iblCdfGenerator) { + return this._iblCdfGenerator; + } + + this._iblCdfGenerator = new IblCdfGenerator(this); + if (this.environmentTexture) { + this._iblCdfGenerator.iblSource = this.environmentTexture; + } + return this._iblCdfGenerator; +}; + +Scene.prototype.disableIblCdfGenerator = function (): void { + if (!this._iblCdfGenerator) { + return; + } + + this._iblCdfGenerator.dispose(); + this._iblCdfGenerator = null; +}; + +/** + * Defines the IBL CDF Generator scene component responsible for generating CDF maps for a given IBL. + */ +export class IblCdfGeneratorSceneComponent implements ISceneComponent { + /** + * The component name helpful to identify the component in the list of scene components. + */ + public readonly name = SceneComponentConstants.NAME_IBLCDFGENERATOR; + + /** + * The scene the component belongs to. + */ + public scene: Scene; + + /** + * Creates a new instance of the component for the given scene + * @param scene Defines the scene to register the component in + */ + constructor(scene: Scene) { + this.scene = scene; + } + + /** + * Registers the component in a given scene + */ + public register(): void { + this._updateIblSource(); + this._newIblObserver = this.scene.onEnvironmentTextureChangedObservable.add(this._updateIblSource.bind(this)); + } + + /** + * Rebuilds the elements related to this component in case of + * context lost for instance. + */ + public rebuild(): void { + // Nothing to do for this component + } + + /** + * Disposes the component and the associated resources + */ + public dispose(): void { + this.scene.onEnvironmentTextureChangedObservable.remove(this._newIblObserver); + } + + private _updateIblSource(): void { + if (this.scene.iblCdfGenerator && this.scene.environmentTexture) { + this.scene.iblCdfGenerator.iblSource = this.scene.environmentTexture; + } + } + + private _newIblObserver: Nullable>> = null; +} + +IblCdfGenerator._SceneComponentInitialization = (scene: Scene) => { + // Register the CDF generator component to the scene. + let component = scene._getComponent(SceneComponentConstants.NAME_IBLCDFGENERATOR) as IblCdfGeneratorSceneComponent; + if (!component) { + component = new IblCdfGeneratorSceneComponent(scene); + scene._addComponent(component); + } +}; diff --git a/packages/dev/core/src/Rendering/index.ts b/packages/dev/core/src/Rendering/index.ts index 5cb915206c1..08614d88e40 100644 --- a/packages/dev/core/src/Rendering/index.ts +++ b/packages/dev/core/src/Rendering/index.ts @@ -7,6 +7,8 @@ export * from "./depthPeelingSceneComponent"; export * from "./edgesRenderer"; export * from "./geometryBufferRenderer"; export * from "./geometryBufferRendererSceneComponent"; +export * from "./iblCdfGenerator"; +export * from "./iblCdfGeneratorSceneComponent"; export * from "./IBLShadows/iblShadowsRenderPipeline"; export * from "./prePassRenderer"; export * from "./prePassRendererSceneComponent"; @@ -69,16 +71,16 @@ export * from "../Shaders/iblGenerateVoxelMip.fragment"; export * from "../ShadersWGSL/iblGenerateVoxelMip.fragment"; export * from "../Shaders/iblShadowGBufferDebug.fragment"; export * from "../ShadersWGSL/iblShadowGBufferDebug.fragment"; -export * from "../ShadersWGSL/iblShadowsCdfx.fragment"; -export * from "../Shaders/iblShadowsCdfx.fragment"; -export * from "../ShadersWGSL/iblShadowsCdfy.fragment"; -export * from "../Shaders/iblShadowsCdfy.fragment"; -export * from "../ShadersWGSL/iblShadowsIcdfx.fragment"; -export * from "../Shaders/iblShadowsIcdfx.fragment"; -export * from "../ShadersWGSL/iblShadowsIcdfy.fragment"; -export * from "../Shaders/iblShadowsIcdfy.fragment"; -export * from "../ShadersWGSL/iblShadowsImportanceSamplingDebug.fragment"; -export * from "../Shaders/iblShadowsImportanceSamplingDebug.fragment"; +export * from "../ShadersWGSL/iblCdfx.fragment"; +export * from "../Shaders/iblCdfx.fragment"; +export * from "../ShadersWGSL/iblCdfy.fragment"; +export * from "../Shaders/iblCdfy.fragment"; +export * from "../ShadersWGSL/iblIcdfx.fragment"; +export * from "../Shaders/iblIcdfx.fragment"; +export * from "../ShadersWGSL/iblIcdfy.fragment"; +export * from "../Shaders/iblIcdfy.fragment"; +export * from "../ShadersWGSL/importanceSamplingDebug.fragment"; +export * from "../Shaders/importanceSamplingDebug.fragment"; export * from "../Shaders/iblVoxelGrid2dArrayDebug.fragment"; export * from "../ShadersWGSL/iblVoxelGrid2dArrayDebug.fragment"; export * from "../Shaders/iblVoxelGrid.fragment"; diff --git a/packages/dev/core/src/Shaders/ShadersInclude/hdrFilteringFunctions.fx b/packages/dev/core/src/Shaders/ShadersInclude/hdrFilteringFunctions.fx index be1a2878964..f232a0d50b8 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/hdrFilteringFunctions.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/hdrFilteringFunctions.fx @@ -49,6 +49,19 @@ return log2(x) / 2.; } + vec3 uv_to_normal(vec2 uv) { + vec3 N; + + vec2 uvRange = uv; + float theta = uvRange.x * 2.0 * PI; + float phi = uvRange.y * PI; + + N.x = cos(theta) * sin(phi); + N.z = sin(theta) * sin(phi); + N.y = cos(phi); + return N; + } + const float NUM_SAMPLES_FLOAT = float(NUM_SAMPLES); const float NUM_SAMPLES_FLOAT_INVERSED = 1. / NUM_SAMPLES_FLOAT; @@ -171,14 +184,21 @@ // #define inline - vec3 irradiance(samplerCube inputTexture, vec3 inputN, vec2 filteringInfo) + vec3 irradiance(samplerCube inputTexture, vec3 inputN, vec2 filteringInfo + #ifdef IBL_CDF_FILTERING + , sampler2D icdfxSampler, sampler2D icdfySampler + #endif + ) { vec3 n = normalize(inputN); vec3 result = vec3(0.0); + + #ifndef IBL_CDF_FILTERING vec3 tangent = abs(n.z) < 0.999 ? vec3(0., 0., 1.) : vec3(1., 0., 0.); tangent = normalize(cross(tangent, n)); vec3 bitangent = cross(n, tangent); mat3 tbn = mat3(tangent, bitangent, n); + #endif float maxLevel = filteringInfo.y; float dim0 = filteringInfo.x; @@ -191,13 +211,20 @@ #endif { vec2 Xi = hammersley(i, NUM_SAMPLES); - vec3 Ls = hemisphereCosSample(Xi); - - Ls = normalize(Ls); - - vec3 Ns = vec3(0., 0., 1.); - float NoL = dot(Ns, Ls); + #ifdef IBL_CDF_FILTERING + vec2 T; + T.x = textureCubeLodEXT(icdfxSampler, vec2(Xi.x, 0.0), 0.0).x; + T.y = textureCubeLodEXT(icdfySampler, vec2(T.x, Xi.y), 0.0).x; + T.x = 1.0 - fract(T.x + 0.25); + vec3 Ls = uv_to_normal(T); + float NoL = dot(n, Ls); + #else + vec3 Ls = hemisphereCosSample(Xi); + Ls = normalize(Ls); + vec3 Ns = vec3(0., 0., 1.); + float NoL = dot(Ns, Ls); + #endif if (NoL > 0.) { float pdf_inversed = PI / NoL; @@ -206,11 +233,20 @@ float l = log4(omegaS) - log4(omegaP) + log4(K); float mipLevel = clamp(l, 0.0, maxLevel); - vec3 c = textureCubeLodEXT(inputTexture, tbn * Ls, mipLevel).rgb; + #ifdef IBL_CDF_FILTERING + vec3 c = textureCubeLodEXT(inputTexture, Ls, mipLevel).rgb; + #else + vec3 c = textureCubeLodEXT(inputTexture, tbn * Ls, mipLevel).rgb; + #endif #ifdef GAMMA_INPUT c = toLinearSpace(c); #endif - result += c; + + #ifdef IBL_CDF_FILTERING + result += c * NoL; + #else + result += c; + #endif } } @@ -267,7 +303,6 @@ float mipLevel = clamp(float(l), 0.0, maxLevel); weight += NoL; - vec3 c = textureCubeLodEXT(inputTexture, tbn * L, mipLevel).rgb; #ifdef GAMMA_INPUT c = toLinearSpace(c); diff --git a/packages/dev/core/src/Shaders/ShadersInclude/pbrBlockReflection.fx b/packages/dev/core/src/Shaders/ShadersInclude/pbrBlockReflection.fx index f7473e96d8d..f97112e21a1 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/pbrBlockReflection.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/pbrBlockReflection.fx @@ -204,6 +204,10 @@ #endif #ifdef REALTIME_FILTERING , in vec2 vReflectionFilteringInfo + #ifdef IBL_CDF_FILTERING + , in sampler2D icdfxSampler + , in sampler2D icdfySampler + #endif #endif ) { @@ -276,7 +280,11 @@ #endif #if defined(REALTIME_FILTERING) - environmentIrradiance = irradiance(reflectionSampler, irradianceVector, vReflectionFilteringInfo); + environmentIrradiance = irradiance(reflectionSampler, irradianceVector, vReflectionFilteringInfo + #ifdef IBL_CDF_FILTERING + , icdfxSampler, icdfySampler + #endif + ); #else environmentIrradiance = computeEnvironmentIrradiance(irradianceVector); #endif diff --git a/packages/dev/core/src/Shaders/ShadersInclude/pbrBlockSubSurface.fx b/packages/dev/core/src/Shaders/ShadersInclude/pbrBlockSubSurface.fx index 406e6668283..e41e053ac17 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/pbrBlockSubSurface.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/pbrBlockSubSurface.fx @@ -180,6 +180,10 @@ struct subSurfaceOutParams #if defined(REALTIME_FILTERING) , in samplerCube reflectionSampler , in vec2 vReflectionFilteringInfo + #ifdef IBL_CDF_FILTERING + , in sampler2D icdfxSampler + , in sampler2D icdfySampler + #endif #endif #endif #ifdef USEIRRADIANCEMAP @@ -490,7 +494,11 @@ struct subSurfaceOutParams #if defined(USESPHERICALFROMREFLECTIONMAP) #if defined(REALTIME_FILTERING) - vec3 refractionIrradiance = irradiance(reflectionSampler, -irradianceVector, vReflectionFilteringInfo); + vec3 refractionIrradiance = irradiance(reflectionSampler, -irradianceVector, vReflectionFilteringInfo + #ifdef IBL_CDF_FILTERING + , icdfxSampler, icdfySampler + #endif + ); #else vec3 refractionIrradiance = computeEnvironmentIrradiance(-irradianceVector); #endif diff --git a/packages/dev/core/src/Shaders/ShadersInclude/pbrFragmentSamplersDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/pbrFragmentSamplersDeclaration.fx index ccb10f78c17..d1f794a7ff6 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/pbrFragmentSamplersDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/pbrFragmentSamplersDeclaration.fx @@ -115,4 +115,9 @@ #include(_DEFINENAME_,SS_REFRACTIONINTENSITY_TEXTURE,_VARYINGNAME_,RefractionIntensity,_SAMPLERNAME_,refractionIntensity) #include(_DEFINENAME_,SS_TRANSLUCENCYINTENSITY_TEXTURE,_VARYINGNAME_,TranslucencyIntensity,_SAMPLERNAME_,translucencyIntensity) #include(_DEFINENAME_,SS_TRANSLUCENCYCOLOR_TEXTURE,_VARYINGNAME_,TranslucencyColor,_SAMPLERNAME_,translucencyColor) +#endif + +#ifdef IBL_CDF_FILTERING + uniform sampler2D icdfxSampler; + uniform sampler2D icdfySampler; #endif \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/iblShadowsCdfx.fragment.fx b/packages/dev/core/src/Shaders/iblCdfx.fragment.fx similarity index 100% rename from packages/dev/core/src/Shaders/iblShadowsCdfx.fragment.fx rename to packages/dev/core/src/Shaders/iblCdfx.fragment.fx diff --git a/packages/dev/core/src/Shaders/iblShadowsCdfy.fragment.fx b/packages/dev/core/src/Shaders/iblCdfy.fragment.fx similarity index 100% rename from packages/dev/core/src/Shaders/iblShadowsCdfy.fragment.fx rename to packages/dev/core/src/Shaders/iblCdfy.fragment.fx diff --git a/packages/dev/core/src/Shaders/iblShadowsIcdfx.fragment.fx b/packages/dev/core/src/Shaders/iblIcdfx.fragment.fx similarity index 100% rename from packages/dev/core/src/Shaders/iblShadowsIcdfx.fragment.fx rename to packages/dev/core/src/Shaders/iblIcdfx.fragment.fx diff --git a/packages/dev/core/src/Shaders/iblShadowsIcdfy.fragment.fx b/packages/dev/core/src/Shaders/iblIcdfy.fragment.fx similarity index 100% rename from packages/dev/core/src/Shaders/iblShadowsIcdfy.fragment.fx rename to packages/dev/core/src/Shaders/iblIcdfy.fragment.fx diff --git a/packages/dev/core/src/Shaders/iblShadowsImportanceSamplingDebug.fragment.fx b/packages/dev/core/src/Shaders/importanceSamplingDebug.fragment.fx similarity index 100% rename from packages/dev/core/src/Shaders/iblShadowsImportanceSamplingDebug.fragment.fx rename to packages/dev/core/src/Shaders/importanceSamplingDebug.fragment.fx diff --git a/packages/dev/core/src/Shaders/pbr.fragment.fx b/packages/dev/core/src/Shaders/pbr.fragment.fx index 713135e029d..231494466e0 100644 --- a/packages/dev/core/src/Shaders/pbr.fragment.fx +++ b/packages/dev/core/src/Shaders/pbr.fragment.fx @@ -298,6 +298,10 @@ void main(void) { #endif #ifdef REALTIME_FILTERING , vReflectionFilteringInfo + #ifdef IBL_CDF_FILTERING + , icdfxSampler + , icdfySampler + #endif #endif ); #else @@ -533,6 +537,10 @@ void main(void) { #if defined(REALTIME_FILTERING) , reflectionSampler , vReflectionFilteringInfo + #ifdef IBL_CDF_FILTERING + , icdfxSampler + , icdfySampler + #endif #endif #endif #ifdef USEIRRADIANCEMAP diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/hdrFilteringFunctions.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/hdrFilteringFunctions.fx index 7e7185f0785..9204e992d9f 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/hdrFilteringFunctions.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/hdrFilteringFunctions.fx @@ -143,14 +143,21 @@ // // - fn irradiance(inputTexture: texture_cube, inputSampler: sampler, inputN: vec3f, filteringInfo: vec2f) -> vec3f + fn irradiance(inputTexture: texture_cube, inputSampler: sampler, inputN: vec3f, filteringInfo: vec2f + #ifdef IBL_CDF_FILTERING + , icdfxSampler: texture_2d, icdfxSamplerSampler: sampler, icdfySampler: texture_2d, icdfySamplerSampler: sampler + #endif + ) -> vec3f { var n: vec3f = normalize(inputN); var result: vec3f = vec3f(0.0); + + #ifndef IBL_CDF_FILTERING var tangent: vec3f = select(vec3f(1., 0., 0.), vec3f(0., 0., 1.), abs(n.z) < 0.999); tangent = normalize(cross(tangent, n)); var bitangent: vec3f = cross(n, tangent); var tbn: mat3x3f = mat3x3f(tangent, bitangent, n); + #endif var maxLevel: f32 = filteringInfo.y; var dim0: f32 = filteringInfo.x; @@ -159,13 +166,20 @@ for(var i: u32 = 0u; i < NUM_SAMPLES; i++) { var Xi: vec2f = hammersley(i, NUM_SAMPLES); - var Ls: vec3f = hemisphereCosSample(Xi); - - Ls = normalize(Ls); - var Ns: vec3f = vec3f(0., 0., 1.); - - var NoL: f32 = dot(Ns, Ls); + #ifdef IBL_CDF_FILTERING + var T: vec2f; + T.x = textureSampleLevel(icdfxSampler, icdfxSamplerSampler, vec2(Xi.x, 0.0), 0.0).x; + T.y = textureSampleLevel(icdfySampler, icdfySamplerSampler, vec2(T.x, Xi.y), 0.0).x; + T.x = 1.0 - fract(T.x + 0.25); + vec3 Ls = uv_to_normal(T); + float NoL = dot(n, Ls); + #else + var Ls: vec3f = hemisphereCosSample(Xi); + Ls = normalize(Ls); + var Ns: vec3f = vec3f(0., 0., 1.); + var NoL: f32 = dot(Ns, Ls); + #endif if (NoL > 0.) { var pdf_inversed: f32 = PI / NoL; @@ -174,11 +188,20 @@ var l: f32 = log4(omegaS) - log4(omegaP) + log4(K); var mipLevel: f32 = clamp(l, 0.0, maxLevel); - var c: vec3f = textureSampleLevel(inputTexture, inputSampler, tbn * Ls, mipLevel).rgb; + #ifdef IBL_CDF_FILTERING + var c: vec3f = textureSampleLevel(inputTexture, inputSampler, Ls, mipLevel).rgb; + #else + var c: vec3f = textureSampleLevel(inputTexture, inputSampler, tbn * Ls, mipLevel).rgb; + #endif #ifdef GAMMA_INPUT c = toLinearSpaceVec3(c); #endif - result += c; + + #ifdef IBL_CDF_FILTERING + result += c * NoL; + #else + result += c; + #endif } } diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrBlockReflection.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrBlockReflection.fx index b4166e40552..bace3f4e20a 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrBlockReflection.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrBlockReflection.fx @@ -230,6 +230,12 @@ #endif #ifdef REALTIME_FILTERING , vReflectionFilteringInfo: vec2f + #ifdef IBL_CDF_FILTERING + , icdfxSampler: texture_2d + , icdfxSamplerSampler: sampler + , icdfySampler: texture_2d + , icdfySamplerSampler: sampler + #endif #endif ) -> reflectionOutParams { @@ -304,7 +310,14 @@ #endif #if defined(REALTIME_FILTERING) - environmentIrradiance = irradiance(reflectionSampler, reflectionSamplerSampler, irradianceVector, vReflectionFilteringInfo); + environmentIrradiance = irradiance(reflectionSampler, reflectionSamplerSampler, irradianceVector, vReflectionFilteringInfo + #ifdef IBL_CDF_FILTERING + , icdfxSampler + , icdfxSamplerSampler + , icdfySampler + , icdfySamplerSampler + #endif + ); #else environmentIrradiance = computeEnvironmentIrradiance(irradianceVector); #endif diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrBlockSubSurface.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrBlockSubSurface.fx index 3371240f346..17381456bcd 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrBlockSubSurface.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrBlockSubSurface.fx @@ -189,6 +189,12 @@ struct subSurfaceOutParams , reflectionSampler: texture_cube , reflectionSamplerSampler: sampler , vReflectionFilteringInfo: vec2f + #ifdef IBL_CDF_FILTERING + , icdfxSampler: texture_2d + , icdfxSamplerSampler: sampler + , icdfySampler: texture_2d + , icdfySamplerSampler: sampler + #endif #endif #endif #ifdef USEIRRADIANCEMAP @@ -513,7 +519,14 @@ struct subSurfaceOutParams #if defined(USESPHERICALFROMREFLECTIONMAP) #if defined(REALTIME_FILTERING) - var refractionIrradiance: vec3f = irradiance(reflectionSampler, reflectionSamplerSampler, -irradianceVector, vReflectionFilteringInfo); + var refractionIrradiance: vec3f = irradiance(reflectionSampler, reflectionSamplerSampler, -irradianceVector, vReflectionFilteringInfo + #ifdef IBL_CDF_FILTERING + , icdfxSampler + , icdfxSamplerSampler + , icdfySampler + , icdfySamplerSampler + #endif + ); #else var refractionIrradiance: vec3f = computeEnvironmentIrradiance(-irradianceVector); #endif diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrFragmentSamplersDeclaration.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrFragmentSamplersDeclaration.fx index edf0f424c88..dc56f6a93f9 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrFragmentSamplersDeclaration.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrFragmentSamplersDeclaration.fx @@ -123,4 +123,11 @@ #include(_DEFINENAME_,SS_REFRACTIONINTENSITY_TEXTURE,_VARYINGNAME_,RefractionIntensity,_SAMPLERNAME_,refractionIntensity) #include(_DEFINENAME_,SS_TRANSLUCENCYINTENSITY_TEXTURE,_VARYINGNAME_,TranslucencyIntensity,_SAMPLERNAME_,translucencyIntensity) #include(_DEFINENAME_,SS_TRANSLUCENCYCOLOR_TEXTURE,_VARYINGNAME_,TranslucencyColor,_SAMPLERNAME_,translucencyColor) +#endif + +#ifdef IBL_CDF_FILTERING + var icdfxSamplerSampler: sampler; + var icdfxSampler: texture_2d; + var icdfySamplerSampler: sampler; + var icdfySampler: texture_2d; #endif \ No newline at end of file diff --git a/packages/dev/core/src/ShadersWGSL/iblShadowsCdfx.fragment.fx b/packages/dev/core/src/ShadersWGSL/iblCdfx.fragment.fx similarity index 100% rename from packages/dev/core/src/ShadersWGSL/iblShadowsCdfx.fragment.fx rename to packages/dev/core/src/ShadersWGSL/iblCdfx.fragment.fx diff --git a/packages/dev/core/src/ShadersWGSL/iblShadowsCdfy.fragment.fx b/packages/dev/core/src/ShadersWGSL/iblCdfy.fragment.fx similarity index 100% rename from packages/dev/core/src/ShadersWGSL/iblShadowsCdfy.fragment.fx rename to packages/dev/core/src/ShadersWGSL/iblCdfy.fragment.fx diff --git a/packages/dev/core/src/ShadersWGSL/iblShadowsIcdfx.fragment.fx b/packages/dev/core/src/ShadersWGSL/iblIcdfx.fragment.fx similarity index 100% rename from packages/dev/core/src/ShadersWGSL/iblShadowsIcdfx.fragment.fx rename to packages/dev/core/src/ShadersWGSL/iblIcdfx.fragment.fx diff --git a/packages/dev/core/src/ShadersWGSL/iblShadowsIcdfy.fragment.fx b/packages/dev/core/src/ShadersWGSL/iblIcdfy.fragment.fx similarity index 100% rename from packages/dev/core/src/ShadersWGSL/iblShadowsIcdfy.fragment.fx rename to packages/dev/core/src/ShadersWGSL/iblIcdfy.fragment.fx diff --git a/packages/dev/core/src/ShadersWGSL/iblShadowsImportanceSamplingDebug.fragment.fx b/packages/dev/core/src/ShadersWGSL/importanceSamplingDebug.fragment.fx similarity index 100% rename from packages/dev/core/src/ShadersWGSL/iblShadowsImportanceSamplingDebug.fragment.fx rename to packages/dev/core/src/ShadersWGSL/importanceSamplingDebug.fragment.fx diff --git a/packages/dev/core/src/ShadersWGSL/pbr.fragment.fx b/packages/dev/core/src/ShadersWGSL/pbr.fragment.fx index 522f44a635d..956fa2a9146 100644 --- a/packages/dev/core/src/ShadersWGSL/pbr.fragment.fx +++ b/packages/dev/core/src/ShadersWGSL/pbr.fragment.fx @@ -289,6 +289,12 @@ fn main(input: FragmentInputs) -> FragmentOutputs { #endif #ifdef REALTIME_FILTERING , uniforms.vReflectionFilteringInfo + #ifdef IBL_CDF_FILTERING + , uniforms.icdfxSampler + , uniforms.icdfxSamplerSampler + , uniforms.icdfySampler + , uniforms.icdfySamplerSampler + #endif #endif ); #else @@ -531,6 +537,12 @@ fn main(input: FragmentInputs) -> FragmentOutputs { , reflectionSampler , reflectionSamplerSampler , vReflectionFilteringInfo + #ifdef IBL_CDF_FILTERING + , uniforms.icdfxSampler + , uniforms.icdfxSamplerSampler + , uniforms.icdfySampler + , uniforms.icdfySamplerSampler + #endif #endif #endif #ifdef USEIRRADIANCEMAP diff --git a/packages/dev/core/src/scene.ts b/packages/dev/core/src/scene.ts index d865a4a9382..abc7c3dc665 100644 --- a/packages/dev/core/src/scene.ts +++ b/packages/dev/core/src/scene.ts @@ -514,6 +514,7 @@ export class Scene implements IAnimatable, IClipPlanesHolder, IAssetContainer { } this._environmentTexture = value; + this.onEnvironmentTextureChangedObservable.notifyObservers(value); this.markAllMaterialsAsDirty(Constants.MATERIAL_TextureDirtyFlag); } @@ -919,6 +920,11 @@ export class Scene implements IAnimatable, IClipPlanesHolder, IAssetContainer { */ public onAnimationFileImportedObservable = new Observable(); + /** + * An event triggered when the environmentTexture is changed. + */ + public onEnvironmentTextureChangedObservable = new Observable>(); + /** * Gets or sets a user defined funtion to select LOD from a mesh and a camera. * By default this function is undefined and Babylon.js will select LOD based on distance to camera @@ -5259,6 +5265,7 @@ export class Scene implements IAnimatable, IClipPlanesHolder, IAssetContainer { this.onActiveCameraChanged.clear(); this.onScenePerformancePriorityChangedObservable.clear(); this.onClearColorChangedObservable.clear(); + this.onEnvironmentTextureChangedObservable.clear(); this._isDisposed = true; } diff --git a/packages/dev/core/src/sceneComponent.ts b/packages/dev/core/src/sceneComponent.ts index 6a4215fbf0e..4754f61d8e3 100644 --- a/packages/dev/core/src/sceneComponent.ts +++ b/packages/dev/core/src/sceneComponent.ts @@ -28,7 +28,6 @@ export class SceneComponentConstants { public static readonly NAME_PREPASSRENDERER = "PrePassRenderer"; public static readonly NAME_DEPTHRENDERER = "DepthRenderer"; public static readonly NAME_DEPTHPEELINGRENDERER = "DepthPeelingRenderer"; - public static readonly NAME_IBLSHADOWSRENDERER = "IblShadowsRenderer"; public static readonly NAME_POSTPROCESSRENDERPIPELINEMANAGER = "PostProcessRenderPipelineManager"; public static readonly NAME_SPRITE = "Sprite"; public static readonly NAME_SUBSURFACE = "SubSurface"; @@ -39,6 +38,7 @@ export class SceneComponentConstants { public static readonly NAME_PHYSICSENGINE = "PhysicsEngine"; public static readonly NAME_AUDIO = "Audio"; public static readonly NAME_FLUIDRENDERER = "FluidRenderer"; + public static readonly NAME_IBLCDFGENERATOR = "iblCDFGenerator"; public static readonly STEP_ISREADYFORMESH_EFFECTLAYER = 0; diff --git a/packages/dev/inspector/src/components/actionTabs/tabs/propertyGrids/postProcesses/iblShadowsRenderPipelinePropertyGridComponent.tsx b/packages/dev/inspector/src/components/actionTabs/tabs/propertyGrids/postProcesses/iblShadowsRenderPipelinePropertyGridComponent.tsx index 6a16401761a..ba2def5cb18 100644 --- a/packages/dev/inspector/src/components/actionTabs/tabs/propertyGrids/postProcesses/iblShadowsRenderPipelinePropertyGridComponent.tsx +++ b/packages/dev/inspector/src/components/actionTabs/tabs/propertyGrids/postProcesses/iblShadowsRenderPipelinePropertyGridComponent.tsx @@ -48,14 +48,6 @@ export class IblShadowsRenderPipelinePropertyGridComponent extends React.Compone this.props.renderPipeline.updateVoxelization(); }} /> - { - if (this.props.renderPipeline.scene.environmentTexture) { - this.props.renderPipeline.setIblTexture(this.props.renderPipeline.scene.environmentTexture); - } - }} - />