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