UNPKG

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

200 lines 6.56 kB
import { Camera } from "../Cameras/camera.js"; import { Halton2DSequence } from "../Maths/halton2DSequence.js"; import { Vector2 } from "../Maths/math.vector.js"; import { Engine } from "../Engines/engine.js"; import { EffectWrapper } from "../Materials/effectRenderer.js"; /** * Simple implementation of Temporal Anti-Aliasing (TAA). * This can be used to improve image quality for still pictures (screenshots for e.g.). */ export class ThinTAAPostProcess extends EffectWrapper { _gatherImports(useWebGPU, list) { if (useWebGPU) { this._webGPUReady = true; list.push(import("../ShadersWGSL/taa.fragment.js")); } else { list.push(import("../Shaders/taa.fragment.js")); } } /** * Number of accumulated samples (default: 8) */ set samples(samples) { if (this._samples === samples) { return; } this._samples = samples; this._hs.regenerate(samples); } get samples() { return this._samples; } /** * Whether the TAA is disabled */ get disabled() { return this._disabled; } set disabled(value) { if (this._disabled === value) { return; } this._disabled = value; this._reset(); } /** * The width of the texture in which to render */ get textureWidth() { return this._textureWidth; } set textureWidth(width) { if (this._textureWidth === width) { return; } this._textureWidth = width; this._reset(); } /** * The height of the texture in which to render */ get textureHeight() { return this._textureHeight; } set textureHeight(height) { if (this._textureHeight === height) { return; } this._textureHeight = height; this._reset(); } /** * Enables reprojecting the history texture with a per-pixel velocity. * If set the "velocitySampler" has to be provided. */ get reprojectHistory() { return this._reprojectHistory; } set reprojectHistory(reproject) { if (this._reprojectHistory === reproject) { return; } this._reprojectHistory = reproject; this._updateEffect(); } /** * Clamps the history pixel to the min and max of the 3x3 pixels surrounding the target pixel. * This can help further reduce ghosting and artifacts. */ get clampHistory() { return this._clampHistory; } set clampHistory(clamp) { if (this._clampHistory === clamp) { return; } this._clampHistory = clamp; this._updateEffect(); } /** * Constructs a new TAA 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 || Engine.LastCreatedEngine, useShaderStore: true, useAsPostProcess: true, fragmentShader: ThinTAAPostProcess.FragmentUrl, uniforms: ThinTAAPostProcess.Uniforms, samplers: ThinTAAPostProcess.Samplers, }); this._samples = 8; /** * The factor used to blend the history frame with current frame (default: 0.05) */ this.factor = 0.05; this._disabled = false; this._textureWidth = 0; this._textureHeight = 0; /** * Disable TAA on camera move (default: true). * You generally want to keep this enabled, otherwise you will get a ghost effect when the camera moves (but if it's what you want, go for it!) */ this.disableOnCameraMove = true; this._reprojectHistory = false; this._clampHistory = false; this._firstUpdate = true; this._hs = new Halton2DSequence(this.samples); } /** @internal */ _reset() { this._hs.setDimensions(this._textureWidth / 2, this._textureHeight / 2); this._hs.next(); this._firstUpdate = true; } nextJitterOffset(output = new Vector2()) { if (!this.camera || !this.camera.hasMoved) { this._hs.next(); } output.set(this._hs.x, this._hs.y); return output; } updateProjectionMatrix() { if (this.disabled) { return; } if (this.camera && !this.camera.hasMoved) { if (this.camera.mode === Camera.PERSPECTIVE_CAMERA) { const projMat = this.camera.getProjectionMatrix(); projMat.setRowFromFloats(2, this._hs.x, this._hs.y, projMat.m[10], projMat.m[11]); } else { // We must force the update of the projection matrix so that m[12] and m[13] are recomputed, as we modified them the previous frame const projMat = this.camera.getProjectionMatrix(true); projMat.setRowFromFloats(3, this._hs.x + projMat.m[12], this._hs.y + projMat.m[13], projMat.m[14], projMat.m[15]); } } this._hs.next(); } bind(noDefaultBindings = false) { super.bind(noDefaultBindings); if (this.disabled) { return; } const effect = this._drawWrapper.effect; effect.setFloat("factor", (this.camera?.hasMoved && this.disableOnCameraMove) || this._firstUpdate ? 1 : this.factor); this._firstUpdate = false; } _updateEffect() { const defines = []; // There seems to be an issue where `updateEffect` sometimes doesn't include the initial samplers const samplers = ["textureSampler", "historySampler"]; if (this._reprojectHistory) { defines.push("#define TAA_REPROJECT_HISTORY"); samplers.push("velocitySampler"); } if (this._clampHistory) { defines.push("#define TAA_CLAMP_HISTORY"); } this.updateEffect(defines.join("\n"), null, samplers); } } /** * The fragment shader url */ ThinTAAPostProcess.FragmentUrl = "taa"; /** * The list of uniforms used by the effect */ ThinTAAPostProcess.Uniforms = ["factor"]; /** * The list of samplers used by the effect */ ThinTAAPostProcess.Samplers = ["historySampler"]; //# sourceMappingURL=thinTAAPostProcess.js.map