Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding normalization to realtime irradiance filtering #15963

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -457,10 +457,8 @@ export class ReflectionBlock extends ReflectionTextureBaseBlock {
#ifdef REALTIME_FILTERING
, ${this._vReflectionFilteringInfoName}
#ifdef IBL_CDF_FILTERING
, icdfxSampler // ** not handled **
${isWebGPU ? `, icdfxSamplerSampler` : ""}
, icdfySampler // ** not handled **
${isWebGPU ? `, icdfySamplerSampler` : ""}
, icdfSampler // ** not handled **
${isWebGPU ? `, icdfSamplerSampler` : ""}
#endif
#endif
);
Expand Down
6 changes: 2 additions & 4 deletions packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1489,8 +1489,7 @@ export abstract class PBRBaseMaterial extends PushMaterial {
"morphTargets",
"oitDepthSampler",
"oitFrontColorSampler",
"icdfxSampler",
"icdfySampler",
"icdfSampler",
];

const uniformBuffers = ["Material", "Scene", "Mesh"];
Expand Down Expand Up @@ -2307,8 +2306,7 @@ export abstract class PBRBaseMaterial extends PushMaterial {
//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());
ubo.setTexture("icdfSampler", cdfGenerator.getIcdfTexture());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { Constants } from "../../../Engines/constants";
import { DrawWrapper } from "../../drawWrapper";
import type { RenderTargetWrapper } from "../../../Engines/renderTargetWrapper";
import { ShaderLanguage } from "core/Materials/shaderLanguage";
import type { ThinTexture } from "core/Materials/Textures/thinTexture";

/**
* Options to create a procedural texture
Expand Down Expand Up @@ -93,7 +94,7 @@ export class ProceduralTexture extends Texture {
private _drawWrapper: DrawWrapper;

/** @internal */
public _textures: { [key: string]: Texture } = {};
public _textures: { [key: string]: ThinTexture } = {};

/** @internal */
protected _fallbackTexture: Nullable<Texture>;
Expand Down Expand Up @@ -524,7 +525,7 @@ export class ProceduralTexture extends Texture {
* @param texture Define the texture to bind to this sampler
* @returns the texture itself allowing "fluent" like uniform updates
*/
public setTexture(name: string, texture: Texture): ProceduralTexture {
public setTexture(name: string, texture: ThinTexture): ProceduralTexture {
if (this._samplers.indexOf(name) === -1) {
this._samplers.push(name);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { ShaderLanguage } from "core/Materials/shaderLanguage";
import { GeometryBufferRenderer } from "../../Rendering/geometryBufferRenderer";
import { ProceduralTexture } from "core/Materials/Textures/Procedurals/proceduralTexture";
import type { IProceduralTextureCreationOptions } from "core/Materials/Textures/Procedurals/proceduralTexture";
import type { CubeTexture } from "../../Materials/Textures/cubeTexture";

/**
* Build cdf maps for IBL importance sampling during IBL shadow computation.
Expand Down Expand Up @@ -343,7 +344,11 @@ export class _IblShadowsVoxelTracingPass {

this._frameId++;

let rotation = this._scene.useRightHandedSystem ? -(this._envRotation + 0.5 * Math.PI) : this._envRotation - 0.5 * Math.PI;
let rotation = 0.0;
if (this._scene.environmentTexture) {
rotation = (this._scene.environmentTexture as CubeTexture).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);
Expand All @@ -361,8 +366,7 @@ export class _IblShadowsVoxelTracingPass {
this._outputTexture.setTexture("blueNoiseSampler", this._renderPipeline!._getNoiseTexture());
const cdfGenerator = this._scene.iblCdfGenerator;
if (cdfGenerator) {
this._outputTexture.setTexture("icdfySampler", cdfGenerator.getIcdfyTexture());
this._outputTexture.setTexture("icdfxSampler", cdfGenerator.getIcdfxTexture());
this._outputTexture.setTexture("icdfSampler", cdfGenerator.getIcdfTexture());
}
if (this._debugVoxelMarchEnabled) {
this._outputTexture.defines += "#define VOXEL_MARCH_DIAGNOSTIC_INFO_OPTION 1u\n";
Expand Down Expand Up @@ -399,8 +403,7 @@ export class _IblShadowsVoxelTracingPass {
this._outputTexture.isReady() &&
!(this._debugPassPP && !this._debugPassPP.isReady()) &&
this._scene.iblCdfGenerator &&
this._scene.iblCdfGenerator.getIcdfyTexture().isReady() &&
this._scene.iblCdfGenerator.getIcdfxTexture().isReady() &&
this._scene.iblCdfGenerator.getIcdfTexture().isReady() &&
this._renderPipeline!._getVoxelGridTexture().isReady()
);
}
Expand Down
139 changes: 77 additions & 62 deletions packages/dev/core/src/Rendering/iblCdfGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,21 @@ export class IblCdfGenerator {
private _engine: AbstractEngine;

private _cdfyPT: ProceduralTexture;
private _icdfyPT: ProceduralTexture;
private _cdfxPT: ProceduralTexture;
private _icdfxPT: ProceduralTexture;
private _icdfPT: ProceduralTexture;
private _scaledLuminancePT: ProceduralTexture;
private _iblSource: BaseTexture;
private _dummyTexture: RawTexture;
/**
* Gets the IBL source texture being used by the importance sampling renderer
* Gets the IBL source texture being used by the CDF renderer
*/
public get iblSource(): BaseTexture {
return this._iblSource;
}

/**
* Sets the IBL source texture to be used by the importance sampling renderer.
* This will trigger recreation of the importance sampling assets.
* Sets the IBL source texture to be used by the CDF renderer.
* This will trigger recreation of the CDF assets.
*/
public set iblSource(source: BaseTexture) {
if (this._iblSource === source) {
Expand All @@ -49,20 +49,20 @@ export class IblCdfGenerator {
this._iblSource = source;
if (source.isCube) {
if (source.isReadyOrNotBlocking()) {
this._recreateAssetsFromNewIbl(source);
this._recreateAssetsFromNewIbl();
} else {
(source as CubeTexture).onLoadObservable.addOnce(this._recreateAssetsFromNewIbl.bind(this, source));
}
} else {
if (source.isReadyOrNotBlocking()) {
this._recreateAssetsFromNewIbl(source);
this._recreateAssetsFromNewIbl();
} else {
(source as Texture).onLoadObservable.addOnce(this._recreateAssetsFromNewIbl.bind(this, source));
}
}
}

private _recreateAssetsFromNewIbl(source: BaseTexture) {
private _recreateAssetsFromNewIbl() {
if (this._debugPass) {
this._debugPass.dispose();
}
Expand All @@ -73,27 +73,14 @@ export class IblCdfGenerator {
// Recreate the debug pass because of the new textures
this._createDebugPass();
}

// Once the textures are generated, notify that they are ready to use.
this._icdfxPT.onGeneratedObservable.addOnce(() => {
this.onGeneratedObservable.notifyObservers();
});
}

/**
* Return the cumulative distribution function (CDF) Y texture
* @returns Return the cumulative distribution function (CDF) Y texture
* Return the cumulative distribution function (CDF) texture
* @returns Return the cumulative distribution function (CDF) texture
*/
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(): Texture {
return this._icdfxPT ? this._icdfxPT : this._dummyTexture;
public getIcdfTexture(): Texture {
return this._icdfPT ? this._icdfPT : this._dummyTexture;
}

/** Enable the debug view for this pass */
Expand All @@ -118,7 +105,7 @@ export class IblCdfGenerator {
public get debugPassName(): string {
return this._debugPassName;
}
private _debugPassName: string = "Importance Sample Debug";
private _debugPassName: string = "CDF Debug";

/**
* Gets the debug pass post process
Expand All @@ -139,25 +126,25 @@ export class IblCdfGenerator {
};

/**
* Instanciates the importance sampling renderer
* Instanciates the CDF renderer
* @param scene Scene to attach to
* @returns The importance sampling renderer
* @returns The CDF renderer
*/
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);
const blackPixels = new Uint16Array([0, 0, 0, 255]);
this._dummyTexture = new RawTexture(blackPixels, 1, 1, Engine.TEXTUREFORMAT_RGBA, scene, false, false, undefined, Constants.TEXTURETYPE_HALF_FLOAT);
IblCdfGenerator._SceneComponentInitialization(this._scene);
}

/**
* Observable that triggers when the importance sampling renderer is ready
* Observable that triggers when the CDF renderer is ready
*/
public onGeneratedObservable: Observable<void> = new Observable<void>();

private _createTextures() {
const size: TextureSize = this._iblSource ? this._iblSource.getSize() : { width: 1, height: 1 };
const size: TextureSize = this._iblSource ? { width: this._iblSource.getSize().width, height: this._iblSource.getSize().height } : { width: 1, height: 1 };
if (!this._iblSource) {
this._iblSource = RawTexture.CreateRTexture(
new Uint8Array([255]),
Expand Down Expand Up @@ -188,54 +175,83 @@ export class IblCdfGenerator {
shaderLanguage: isWebGPU ? ShaderLanguage.WGSL : ShaderLanguage.GLSL,
extraInitializationsAsync: async () => {
if (isWebGPU) {
await Promise.all([import("../ShadersWGSL/iblCdfx.fragment"), import("../ShadersWGSL/iblCdfy.fragment")]);
await Promise.all([import("../ShadersWGSL/iblCdfx.fragment"), import("../ShadersWGSL/iblCdfy.fragment"), import("../ShadersWGSL/iblScaledLuminance.fragment")]);
} else {
await Promise.all([import("../Shaders/iblCdfx.fragment"), import("../Shaders/iblCdfy.fragment")]);
await Promise.all([import("../Shaders/iblCdfx.fragment"), import("../Shaders/iblCdfy.fragment"), import("../Shaders/iblScaledLuminance.fragment")]);
}
},
};
const icdfOptions: IProceduralTextureCreationOptions = {
generateDepthBuffer: false,
generateMipMaps: false,
format: Constants.TEXTUREFORMAT_R,
format: Constants.TEXTUREFORMAT_RGBA,
type: Constants.TEXTURETYPE_HALF_FLOAT,
samplingMode: Constants.TEXTURE_NEAREST_SAMPLINGMODE,
shaderLanguage: isWebGPU ? ShaderLanguage.WGSL : ShaderLanguage.GLSL,
extraInitializationsAsync: async () => {
if (isWebGPU) {
await Promise.all([import("../ShadersWGSL/iblIcdfx.fragment"), import("../ShadersWGSL/iblIcdfy.fragment")]);
await Promise.all([import("../ShadersWGSL/iblIcdf.fragment")]);
} else {
await Promise.all([import("../Shaders/iblIcdfx.fragment"), import("../Shaders/iblIcdfy.fragment")]);
await Promise.all([import("../Shaders/iblIcdf.fragment")]);
}
},
};
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.setTexture("iblSource", this._iblSource);
this._cdfyPT.setInt("iblHeight", size.height);
this._cdfyPT.wrapV = Constants.TEXTURE_CLAMP_ADDRESSMODE;
this._cdfyPT.refreshRate = 0;
if (this._iblSource.isCube) {
this._cdfyPT.defines = "#define IBL_USE_CUBE_MAP\n";
}
this._cdfyPT.refreshRate = 0;
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 }, "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 }, "iblIcdfx", this._scene, icdfOptions, false, false);
this._icdfxPT.autoClear = false;
this._icdfxPT.setTexture("cdfx", this._cdfxPT);
this._icdfxPT.refreshRate = 0;
this._cdfxPT.wrapU = Constants.TEXTURE_CLAMP_ADDRESSMODE;

this._scaledLuminancePT = new ProceduralTexture(
"iblScaledLuminance",
{ width: size.width, height: size.height },
"iblScaledLuminance",
this._scene,
{ ...icdfOptions, samplingMode: Constants.TEXTURE_TRILINEAR_SAMPLINGMODE, generateMipMaps: true },
true,
false
);
this._scaledLuminancePT.autoClear = false;
this._scaledLuminancePT.setTexture("iblSource", this._iblSource);
this._scaledLuminancePT.setInt("iblHeight", size.height);
this._scaledLuminancePT.setInt("iblWidth", size.width);
this._scaledLuminancePT.refreshRate = 0;
if (this._iblSource.isCube) {
this._scaledLuminancePT.defines = "#define IBL_USE_CUBE_MAP\n";
}
this._icdfPT = new ProceduralTexture("icdfTexture", { width: size.width, height: size.height }, "iblIcdf", this._scene, icdfOptions, false, false);
this._icdfPT.autoClear = false;
this._icdfPT.setTexture("cdfy", this._cdfyPT);
this._icdfPT.setTexture("cdfx", this._cdfxPT);
this._icdfPT.setTexture("iblSource", this._iblSource);
this._icdfPT.setTexture("scaledLuminanceSampler", this._scaledLuminancePT);
this._icdfPT.refreshRate = 0;
this._icdfPT.wrapV = Constants.TEXTURE_CLAMP_ADDRESSMODE;
this._icdfPT.wrapU = Constants.TEXTURE_CLAMP_ADDRESSMODE;
if (this._iblSource.isCube) {
this._icdfPT.defines = "#define IBL_USE_CUBE_MAP\n";
}
// Once the textures are generated, notify that they are ready to use.
this._icdfPT.onGeneratedObservable.addOnce(() => {
this.onGeneratedObservable.notifyObservers();
});
}

private _disposeTextures() {
this._cdfyPT?.dispose();
this._icdfyPT?.dispose();
this._cdfxPT?.dispose();
this._icdfxPT?.dispose();
this._icdfPT?.dispose();
this._scaledLuminancePT?.dispose();
}

private _createDebugPass() {
Expand All @@ -250,18 +266,18 @@ export class IblCdfGenerator {
engine: this._engine,
textureType: Constants.TEXTURETYPE_UNSIGNED_BYTE,
uniforms: ["sizeParams"],
samplers: ["cdfy", "icdfy", "cdfx", "icdfx", "iblSource"],
samplers: ["cdfy", "icdf", "cdfx", "iblSource"],
defines: this._iblSource?.isCube ? "#define IBL_USE_CUBE_MAP\n" : "",
shaderLanguage: isWebGPU ? ShaderLanguage.WGSL : ShaderLanguage.GLSL,
extraInitializations: (useWebGPU: boolean, list: Promise<any>[]) => {
if (useWebGPU) {
list.push(import("../ShadersWGSL/importanceSamplingDebug.fragment"));
list.push(import("../ShadersWGSL/iblCdfDebug.fragment"));
} else {
list.push(import("../Shaders/importanceSamplingDebug.fragment"));
list.push(import("../Shaders/iblCdfDebug.fragment"));
}
},
};
this._debugPass = new PostProcess(this._debugPassName, "importanceSamplingDebug", debugOptions);
this._debugPass = new PostProcess(this._debugPassName, "iblCdfDebug", debugOptions);
const debugEffect = this._debugPass.getEffect();
if (debugEffect) {
debugEffect.defines = this._iblSource?.isCube ? "#define IBL_USE_CUBE_MAP\n" : "";
Expand All @@ -271,17 +287,16 @@ export class IblCdfGenerator {
}
this._debugPass.onApplyObservable.add((effect) => {
effect.setTexture("cdfy", this._cdfyPT);
effect.setTexture("icdfy", this._icdfyPT);
effect.setTexture("icdf", this._icdfPT);
effect.setTexture("cdfx", this._cdfxPT);
effect.setTexture("icdfx", this._icdfxPT);
effect.setTexture("iblSource", this._iblSource);
effect.setFloat4("sizeParams", this._debugSizeParams.x, this._debugSizeParams.y, this._debugSizeParams.z, this._debugSizeParams.w);
});
}

/**
* Checks if the importance sampling renderer is ready
* @returns true if the importance sampling renderer is ready
* Checks if the CDF renderer is ready
* @returns true if the CDF renderer is ready
*/
public isReady() {
return (
Expand All @@ -290,17 +305,17 @@ export class IblCdfGenerator {
this._iblSource.isReady() &&
this._cdfyPT &&
this._cdfyPT.isReady() &&
this._icdfyPT &&
this._icdfyPT.isReady() &&
this._icdfPT &&
this._icdfPT.isReady() &&
this._cdfxPT &&
this._cdfxPT.isReady() &&
this._icdfxPT &&
this._icdfxPT.isReady()
this._scaledLuminancePT &&
this._scaledLuminancePT.isReady()
);
}

/**
* Disposes the importance sampling renderer and associated resources
* Disposes the CDF renderer and associated resources
*/
public dispose() {
this._disposeTextures();
Expand Down
Loading