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.

338 lines (337 loc) 18.5 kB
import { FrameGraphTask } from "../../frameGraphTask.js"; import { FrameGraphObjectRendererTask } from "../Rendering/objectRendererTask.js"; import { FrameGraphClearTextureTask } from "../Texture/clearTextureTask.js"; import { FrameGraphBlurTask } from "../PostProcesses/blurTask.js"; import { FrameGraphTextureManager } from "../../frameGraphTextureManager.js"; import { getDimensionsFromTextureSize } from "../../../Materials/Textures/textureCreationOptions.js"; import { FrameGraphPostProcessTask } from "../PostProcesses/postProcessTask.js"; import { Vector2 } from "../../../Maths/math.vector.js"; import { ThinGlowBlurPostProcess } from "../../../Layers/thinEffectLayer.js"; import { FrameGraphExecuteTask } from "../Misc/executeTask.js"; /** @internal */ export var FrameGraphBaseLayerBlurType; (function (FrameGraphBaseLayerBlurType) { FrameGraphBaseLayerBlurType["None"] = "none"; FrameGraphBaseLayerBlurType["Standard"] = "standard"; FrameGraphBaseLayerBlurType["Glow"] = "glow"; })(FrameGraphBaseLayerBlurType || (FrameGraphBaseLayerBlurType = {})); class FrameGraphGlowBlurTask extends FrameGraphPostProcessTask { /** * Constructs a new glow blur task. * @param name The name of the task. * @param frameGraph The frame graph this task is associated with. * @param thinPostProcess The thin post process to use for the glow blur effect. If not provided, a new one will be created. */ constructor(name, frameGraph, thinPostProcess) { super(name, frameGraph, thinPostProcess || new ThinGlowBlurPostProcess(name, frameGraph.engine, new Vector2(1, 0), 1)); } getClassName() { return "FrameGraphGlowBlurTask"; } record(skipCreationOfDisabledPasses = false, additionalExecute, additionalBindings) { const pass = super.record(skipCreationOfDisabledPasses, additionalExecute, additionalBindings); this.postProcess.textureWidth = this._outputWidth; this.postProcess.textureHeight = this._outputHeight; return pass; } } /** * @internal */ export class FrameGraphBaseLayerTask extends FrameGraphTask { /** * The name of the task. */ get name() { return this._name; } set name(name) { this._name = name; if (this._blurX) { for (let i = 0; i < this._blurX.length; i++) { this._blurX[i].name = `${name} Blur X${i}`; this._blurY[i].name = `${name} Blur Y${i}`; } } if (this._clearLayerTextureTask) { this._clearLayerTextureTask.name = name + " Clear Layer"; } if (this._objectRendererForLayerTask) { this._objectRendererForLayerTask.name = name + " Render to Layer"; } } /** * Gets the object renderer used to render the layer. */ get objectRendererForLayer() { return this._objectRendererForLayerTask; } /** * Constructs a new layer task. * @param name Name of the task. * @param frameGraph The frame graph this task is associated with. * @param scene The scene to render the layer in. * @param layer The layer. * @param numBlurPasses The number of blur passes applied by the layer. * @param _blurType The type of blur to use for the layer. * @param _setRenderTargetDepth If true, the task will set the render target depth. * @param _notifyBlurObservable If true, the task will notify before and after blurring occurs. * @param _setObjectList If true, the object list of the object renderer for the layer will be set to the object list of the object renderer task. */ constructor(name, frameGraph, scene, layer, numBlurPasses, _blurType = "standard" /* FrameGraphBaseLayerBlurType.Standard */, _setRenderTargetDepth = false, _notifyBlurObservable = false, _setObjectList = true) { super(name, frameGraph); this._blurType = _blurType; this._setRenderTargetDepth = _setRenderTargetDepth; this._notifyBlurObservable = _notifyBlurObservable; this._setObjectList = _setObjectList; this._blurX = []; this._blurY = []; this._onBeforeBlurTask = null; this._onAfterBlurTask = null; this._onBeforeObservableObserver = null; this._onBeforeObservableObserver2 = null; this._onAfterObservableObserver = null; this._onAfterRenderingGroupObserver = null; this._scene = scene; this._engine = scene.getEngine(); this.layer = layer; if (this._blurType !== "none" /* FrameGraphBaseLayerBlurType.None */) { for (let i = 0; i < numBlurPasses; i++) { if (this._blurType === "glow" /* FrameGraphBaseLayerBlurType.Glow */) { this._blurX.push(new FrameGraphGlowBlurTask(`${name} Blur X${i}`, this._frameGraph, this.layer._postProcesses[1 + i * 2 + 0])); this._blurY.push(new FrameGraphGlowBlurTask(`${name} Blur Y${i}`, this._frameGraph, this.layer._postProcesses[1 + i * 2 + 1])); } else { this._blurX.push(new FrameGraphBlurTask(`${name} Blur X${i}`, this._frameGraph, this.layer._postProcesses[i * 2 + 0])); this._blurY.push(new FrameGraphBlurTask(`${name} Blur Y${i}`, this._frameGraph, this.layer._postProcesses[i * 2 + 1])); } } } this._clearLayerTextureTask = new FrameGraphClearTextureTask(name + " Clear Layer", frameGraph); this._clearLayerTextureTask.clearColor = true; this._clearLayerTextureTask.clearDepth = true; this._objectRendererForLayerTask = new FrameGraphObjectRendererTask(name + " Render to Layer", frameGraph, scene, undefined, this.layer.objectRenderer); if (this._blurType !== "none" /* FrameGraphBaseLayerBlurType.None */ && this._notifyBlurObservable) { this._onBeforeBlurTask = new FrameGraphExecuteTask(name + " On Before Blur", frameGraph); this._onAfterBlurTask = new FrameGraphExecuteTask(name + " On After Blur", frameGraph); this._onBeforeBlurTask.func = () => { if (this.layer.onBeforeBlurObservable.hasObservers()) { this.layer.onBeforeBlurObservable.notifyObservers(this.layer); } }; this._onAfterBlurTask.func = () => { if (this.layer.onAfterBlurObservable.hasObservers()) { this.layer.onAfterBlurObservable.notifyObservers(this.layer); } }; } this.outputTexture = this._frameGraph.textureManager.createDanglingHandle(); } isReady() { return this._objectRendererForLayerTask.isReady() && this.layer.isLayerReady(); } getClassName() { return "FrameGraphBaseLayerTask"; } record(_skipCreationOfDisabledPasses, additionalComposeBindings) { if (this.targetTexture === undefined || this.objectRendererTask === undefined) { throw new Error(`${this.constructor.name} "${this.name}": targetTexture and objectRendererTask are required`); } this._frameGraph.textureManager.resolveDanglingHandle(this.outputTexture, this.targetTexture); // Uses the layerTexture or creates a color texture to render the layer to let textureSize; let textureCreationOptions; let colorLayerOutput; if (this.layerTexture) { colorLayerOutput = this.layerTexture; textureCreationOptions = this._frameGraph.textureManager.getTextureCreationOptions(this.layerTexture); textureSize = getDimensionsFromTextureSize(textureCreationOptions.size); textureCreationOptions.size = textureSize; } else { const targetTextureCreationOptions = this._frameGraph.textureManager.getTextureCreationOptions(this.targetTexture); const fixedTextureSize = this.layer._options.mainTextureFixedSize ? Math.max(2, this.layer._options.mainTextureFixedSize) : 0; textureSize = getDimensionsFromTextureSize(targetTextureCreationOptions.size); textureSize.width = fixedTextureSize || Math.floor(textureSize.width * (this.layer._options.mainTextureRatio || 0.1)) || 1; textureSize.height = fixedTextureSize || Math.floor(textureSize.height * (this.layer._options.mainTextureRatio || 0.1)) || 1; textureCreationOptions = { size: textureSize, options: { createMipMaps: false, types: [this.layer._options.mainTextureType], formats: [this.layer._options.mainTextureFormat], samples: 1, useSRGBBuffers: [false], creationFlags: [0], }, sizeIsPercentage: this.layer._options.mainTextureFixedSize ? false : targetTextureCreationOptions.sizeIsPercentage, }; colorLayerOutput = this._frameGraph.textureManager.createRenderTargetTexture(`${this.name} Color`, textureCreationOptions); } this._layerTextureDimensions = this._frameGraph.textureManager.getTextureAbsoluteDimensions(textureCreationOptions); // Creates a depth texture, used to render objects to the layer // We don't reuse the depth texture of the objectRendererTask, as the size of the layer texture will generally be different (smaller). const textureDepthCreationOptions = { size: textureSize, options: FrameGraphTextureManager.CloneTextureOptions(textureCreationOptions.options), sizeIsPercentage: textureCreationOptions.sizeIsPercentage, }; textureDepthCreationOptions.options.formats[0] = 14; const depthLayerOutput = this._frameGraph.textureManager.createRenderTargetTexture(`${this.name} Depth`, textureDepthCreationOptions); // Clears the textures this._clearLayerTextureTask.targetTexture = colorLayerOutput; this._clearLayerTextureTask.depthTexture = depthLayerOutput; this._clearLayerTextureTask.color = this.layer.neutralColor; this._clearLayerTextureTask.clearDepth = true; const clearTaskPass = this._clearLayerTextureTask.record(true); // Renders the objects to the layer texture this._objectRendererForLayerTask.targetTexture = this._clearLayerTextureTask.outputTexture; this._objectRendererForLayerTask.depthTexture = this._clearLayerTextureTask.outputDepthTexture; this._objectRendererForLayerTask.camera = this.objectRendererTask.camera; if (this._setObjectList) { this._objectRendererForLayerTask.objectList = this.objectRendererTask.objectList; } this._objectRendererForLayerTask.disableShadows = true; const objectRendererForLayerTaskPass = this._objectRendererForLayerTask.record(true); // Blurs the layer color texture let onBeforeBlurPass; let onAfterBlurPass; if (this._blurType !== "none" /* FrameGraphBaseLayerBlurType.None */) { let blurTextureType; if (this._engine.getCaps().textureHalfFloatRender) { blurTextureType = 2; } else { blurTextureType = 0; } textureCreationOptions.options.types[0] = blurTextureType; const blurTextureSizeRatio = this.layer._options.blurTextureSizeRatio !== undefined ? this.layer._options.blurTextureSizeRatio || 0.1 : undefined; if (blurTextureSizeRatio !== undefined) { textureSize.width = Math.floor(textureSize.width * blurTextureSizeRatio) || 1; textureSize.height = Math.floor(textureSize.height * blurTextureSizeRatio) || 1; } onBeforeBlurPass = this._onBeforeBlurTask?.record(); const blurPasses = []; for (let i = 0; i < this._blurX.length; i++) { const blurXTextureHandle = this._frameGraph.textureManager.createRenderTargetTexture(this._blurX[i].name, textureCreationOptions); this._blurX[i].sourceTexture = i === 0 ? this._objectRendererForLayerTask.outputTexture : this._blurY[i - 1].outputTexture; this._blurX[i].sourceSamplingMode = 2; this._blurX[i].targetTexture = blurXTextureHandle; blurPasses.push(this._blurX[i].record(true)); const blurYTextureHandle = this._frameGraph.textureManager.createRenderTargetTexture(this._blurY[i].name, textureCreationOptions); this._blurY[i].sourceTexture = this._blurX[i].outputTexture; this._blurY[i].sourceSamplingMode = 2; this._blurY[i].targetTexture = blurYTextureHandle; blurPasses.push(this._blurY[i].record(true)); textureSize.width = textureSize.width >> 1; textureSize.height = textureSize.height >> 1; } onAfterBlurPass = this._onAfterBlurTask?.record(); this.objectRendererTask.objectRenderer.onBeforeRenderObservable.remove(this._onBeforeObservableObserver2); this._onBeforeObservableObserver2 = this.objectRendererTask.objectRenderer.onBeforeRenderObservable.add(() => { const shouldRender = this.layer.shouldRender(); if (onBeforeBlurPass) { onBeforeBlurPass.disabled = !shouldRender; } for (let i = 0; i < blurPasses.length; i++) { blurPasses[i].disabled = !shouldRender; } if (onAfterBlurPass) { onAfterBlurPass.disabled = !shouldRender; } }); } // Enables stencil (if stencil is needed) when rendering objects to the main texture // We also disable the internal passes if the layer should not render this.objectRendererTask.objectRenderer.onBeforeRenderObservable.remove(this._onBeforeObservableObserver); this._onBeforeObservableObserver = this.objectRendererTask.objectRenderer.onBeforeRenderObservable.add(() => { const shouldRender = this.layer.shouldRender(); clearTaskPass.disabled = !shouldRender; objectRendererForLayerTaskPass.disabled = !shouldRender; if (shouldRender && this.layer.needStencil()) { this._engine.setStencilBuffer(true); this._engine.setStencilFunctionReference(1); } }); this.objectRendererTask.objectRenderer.onAfterRenderObservable.remove(this._onAfterObservableObserver); this._onAfterObservableObserver = this.objectRendererTask.objectRenderer.onAfterRenderObservable.add(() => { if (this.layer.shouldRender() && this.layer.needStencil()) { this._engine.setStencilBuffer(false); } }); // Composes the layer with the target texture this.layer.bindTexturesForCompose = undefined; this._clearAfterRenderingGroupObserver(); const pass = this._frameGraph.addRenderPass(this.name); for (let i = 0; i < this._blurY.length; i++) { pass.addDependencies(this._blurY[i].outputTexture); } pass.setRenderTarget(this.outputTexture); if (this._setRenderTargetDepth) { pass.setRenderTargetDepth(this.objectRendererTask.depthTexture); } pass.setInitializeFunc((context) => { this.layer.bindTexturesForCompose = (effect) => { for (let i = 0; i < this._blurY.length; i++) { context.bindTextureHandle(effect, `textureSampler${i > 0 ? i + 1 : ""}`, this._blurY[i].outputTexture); } additionalComposeBindings?.(context, effect); }; if (this.layer._options.renderingGroupId === -1) { return; } this._onAfterRenderingGroupObserver = this._scene.onAfterRenderingGroupObservable.add((info) => { if (!this.layer.shouldRender() || info.renderingGroupId !== this.layer._options.renderingGroupId || info.renderingManager !== this.objectRendererTask.objectRenderer.renderingManager) { return; } if (this._setObjectList) { this._objectRendererForLayerTask.objectList = this.objectRendererTask.objectList; } context.saveDepthStates(); context.setDepthStates(false, false); context._applyRenderTarget(); this.layer.compose(); context.restoreDepthStates(); }); }); pass.setExecuteFunc((context) => { if (this._blurY.length > 0) { context.setTextureSamplingMode(this._blurY[this._blurY.length - 1].targetTexture, 2); } if (this.layer._options.renderingGroupId === -1 && this.layer.shouldRender()) { if (this._setObjectList) { this._objectRendererForLayerTask.objectList = this.objectRendererTask.objectList; // in case the object list has changed in objectRendererTask } context.setDepthStates(false, false); context._applyRenderTarget(); this.layer.compose(); } }); const passDisabled = this._frameGraph.addRenderPass(this.name + "_disabled", true); passDisabled.setRenderTarget(this.outputTexture); if (this._setRenderTargetDepth) { passDisabled.setRenderTargetDepth(this.objectRendererTask.depthTexture); } passDisabled.setExecuteFunc((_context) => { }); } _clearAfterRenderingGroupObserver() { this._scene.onAfterRenderingGroupObservable.remove(this._onAfterRenderingGroupObserver); this._onAfterRenderingGroupObserver = null; } dispose() { this._clearAfterRenderingGroupObserver(); this._clearLayerTextureTask.dispose(); this._objectRendererForLayerTask.dispose(); this._onBeforeBlurTask?.dispose(); this._onAfterBlurTask?.dispose(); this.layer.dispose(); for (let i = 0; i < this._blurX.length; i++) { this._blurX[i].dispose(); this._blurY[i].dispose(); } super.dispose(); } } //# sourceMappingURL=baseLayerTask.js.map