@babylonjs/core
Version:
Getting started? Play directly with the Babylon.js API using our [playground](https://playground.babylonjs.com/). It also contains a lot of samples to learn how to use it.
136 lines (135 loc) • 7.61 kB
JavaScript
import { Vector4 } from "../../../../Maths/math.vector.pure.js";
import { ThinCustomPostProcess } from "../../../../PostProcesses/thinCustomPostProcess.js";
import { FrameGraphTask } from "../../../frameGraphTask.js";
/**
* Task used to temporally accumulate IBL shadows.
* @internal
*/
export class FrameGraphIblShadowsAccumulationTask extends FrameGraphTask {
get remanence() {
return this._remanence;
}
set remanence(value) {
this._remanence = Math.max(0, Math.min(value, 1));
}
constructor(name, frameGraph) {
super(name, frameGraph);
this._remanence = 0.75;
this.reset = true;
this.isMoving = false;
this.voxelGridSize = 1;
this._accumulationParams = new Vector4(0, 0, 0, 0);
this.postProcess = new ThinCustomPostProcess(name, frameGraph.engine, {
fragmentShader: "iblShadowAccumulation",
uniforms: ["accumulationParameters"],
samplers: ["spatialBlurSampler", "oldAccumulationSampler", "prevPositionSampler", "motionSampler", "positionSampler"],
shaderLanguage: frameGraph.engine.isWebGPU ? 1 /* ShaderLanguage.WGSL */ : 0 /* ShaderLanguage.GLSL */,
});
this._postProcessDrawWrapper = this.postProcess.drawWrapper;
this.outputTexture = this._frameGraph.textureManager.createDanglingHandle();
}
getClassName() {
return "FrameGraphIblShadowsAccumulationTask";
}
// eslint-disable-next-line @typescript-eslint/promise-function-async, no-restricted-syntax
initAsync() {
if (this._frameGraph.engine.isWebGPU) {
return import("../../../../ShadersWGSL/iblShadowAccumulation.fragment.js");
}
return import("../../../../Shaders/iblShadowAccumulation.fragment.js");
}
isReady() {
return this.postProcess.isReady();
}
record() {
if (this.sourceTexture === undefined || this.velocityTexture === undefined || this.positionTexture === undefined) {
throw new Error(`FrameGraphIblShadowsAccumulationTask ${this.name}: sourceTexture, velocityTexture and positionTexture are required`);
}
const textureManager = this._frameGraph.textureManager;
const outputSize = textureManager.getTextureAbsoluteDimensions(this.sourceTexture);
const positionSize = textureManager.getTextureAbsoluteDimensions(this.positionTexture);
const sharedTextureOptions = {
createMipMaps: false,
samples: 1,
formats: [5],
useSRGBBuffers: [false],
creationFlags: [0],
};
const outputCreationOptions = {
size: outputSize,
sizeIsPercentage: false,
isHistoryTexture: false,
options: { ...sharedTextureOptions, types: [2], labels: [`${this.name} Output`] },
};
const previousAccumulationCreationOptions = {
size: outputSize,
sizeIsPercentage: false,
isHistoryTexture: false,
options: { ...sharedTextureOptions, types: [2], labels: [`${this.name} Previous Accumulation`] },
};
const previousPositionCreationOptions = {
size: positionSize,
sizeIsPercentage: false,
isHistoryTexture: false,
options: { ...sharedTextureOptions, types: [2], labels: [`${this.name} Previous Position`] },
};
textureManager.resolveDanglingHandle(this.outputTexture, undefined, `${this.name} Output`, outputCreationOptions);
this._previousAccumulationTexture = textureManager.createRenderTargetTexture(`${this.name} Previous Accumulation`, previousAccumulationCreationOptions, this._previousAccumulationTexture);
this._previousPositionTexture = textureManager.createRenderTargetTexture(`${this.name} Previous Position`, previousPositionCreationOptions, this._previousPositionTexture);
// Pass 1: Accumulate into outputTexture, sampling last frame's accumulation and position.
const pass = this._frameGraph.addRenderPass(this.name);
pass.addDependencies(this.sourceTexture);
pass.addDependencies(this.velocityTexture);
pass.addDependencies(this.positionTexture);
pass.addDependencies(this._previousAccumulationTexture);
pass.addDependencies(this._previousPositionTexture);
pass.setRenderTarget(this.outputTexture);
pass.setExecuteFunc((context) => {
context.setTextureSamplingMode(this.sourceTexture, 1);
context.setTextureSamplingMode(this.velocityTexture, 1);
context.setTextureSamplingMode(this.positionTexture, 1);
const remanence = this.isMoving ? this.remanence : 0.99;
this._accumulationParams.set(remanence, this.reset ? 1.0 : 0.0, this.voxelizationTask?.voxelGridSize ?? this.voxelGridSize, 0.0);
context.applyFullScreenEffect(this._postProcessDrawWrapper, () => {
const effect = this._postProcessDrawWrapper.effect;
context.bindTextureHandle(effect, "spatialBlurSampler", this.sourceTexture);
context.bindTextureHandle(effect, "oldAccumulationSampler", this._previousAccumulationTexture);
context.bindTextureHandle(effect, "prevPositionSampler", this._previousPositionTexture);
context.bindTextureHandle(effect, "motionSampler", this.velocityTexture);
context.bindTextureHandle(effect, "positionSampler", this.positionTexture);
effect.setVector4("accumulationParameters", this._accumulationParams);
this.postProcess.bind();
}, undefined, false, false, true);
this.reset = false;
this.isMoving = false;
});
// Pass 2: Copy the current frame's world-position into previousPositionTexture so the
// next frame's accumulation pass can use it as "previous frame positions".
const copyPositionToPreviousPass = this._frameGraph.addRenderPass(`${this.name} CopyPositionToPrevious`);
copyPositionToPreviousPass.addDependencies(this.positionTexture);
copyPositionToPreviousPass.setRenderTarget(this._previousPositionTexture);
copyPositionToPreviousPass.setExecuteFunc((context) => {
context.copyTexture(this.positionTexture);
});
// Pass 3: Copy the current frame's accumulation result into previousAccumulationTexture
// so the next frame's accumulation pass can use it as oldAccumulationSampler.
const copyAccumulationToPreviousPass = this._frameGraph.addRenderPass(`${this.name} CopyAccumulationToPrevious`);
copyAccumulationToPreviousPass.addDependencies(this.outputTexture);
copyAccumulationToPreviousPass.setRenderTarget(this._previousAccumulationTexture);
copyAccumulationToPreviousPass.setExecuteFunc((context) => {
context.copyTexture(this.outputTexture);
});
// Pass 4 (marker): empty execute, render target = outputTexture.
// Ensures _checkTask sees outputTexture as the task's last enabled-pass output,
// matching the disabled path. No render pass encoder is opened because the
// execute function never calls _applyRenderTarget.
const outputMarkerPass = this._frameGraph.addRenderPass(`${this.name} Output`);
outputMarkerPass.setRenderTarget(this.outputTexture);
outputMarkerPass.setExecuteFunc((_context) => { });
}
dispose() {
this.postProcess.dispose();
super.dispose();
}
}
//# sourceMappingURL=iblShadowsAccumulationTask.js.map