@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.
297 lines (296 loc) • 13.6 kB
JavaScript
import { EffectRenderer } from "../Materials/effectRenderer.js";
import { CopyTextureToTexture } from "../Misc/copyTextureToTexture.js";
import { FrameGraphContext } from "./frameGraphContext.js";
/**
* Frame graph context used render passes.
* @experimental
*/
export class FrameGraphRenderContext extends FrameGraphContext {
static _IsObjectRenderer(value) {
return value.initRender !== undefined;
}
/** @internal */
constructor(engine, textureManager, scene) {
super(engine, textureManager, scene);
this._debugMessageHasBeenPushed = false;
this._renderTargetIsBound = true;
this._effectRenderer = new EffectRenderer(this._engine);
this._effectRendererBack = new EffectRenderer(this._engine, {
positions: [1, 1, -1, 1, -1, -1, 1, -1],
indices: [0, 2, 1, 0, 3, 2],
});
this._copyTexture = new CopyTextureToTexture(this._engine);
}
/**
* Checks whether a texture handle points to the backbuffer's color or depth texture
* @param handle The handle to check
* @returns True if the handle points to the backbuffer's color or depth texture, otherwise false
*/
isBackbuffer(handle) {
return this._textureManager.isBackbuffer(handle);
}
/**
* Checks whether a texture handle points to the backbuffer's color texture
* @param handle The handle to check
* @returns True if the handle points to the backbuffer's color texture, otherwise false
*/
isBackbufferColor(handle) {
return this._textureManager.isBackbufferColor(handle);
}
/**
* Checks whether a texture handle points to the backbuffer's depth texture
* @param handle The handle to check
* @returns True if the handle points to the backbuffer's depth texture, otherwise false
*/
isBackbufferDepthStencil(handle) {
return this._textureManager.isBackbufferDepthStencil(handle);
}
/**
* Creates a (frame graph) render target wrapper
* Note that renderTargets or renderTargetDepth can be undefined, but not both at the same time!
* @param name Name of the render target wrapper
* @param renderTargets Render target handles (textures) to use
* @param renderTargetDepth Render target depth handle (texture) to use
* @param depthReadOnly If true, the depth buffer will be read-only
* @param stencilReadOnly If true, the stencil buffer will be read-only
* @returns The created render target wrapper
*/
createRenderTarget(name, renderTargets, renderTargetDepth, depthReadOnly, stencilReadOnly) {
return this._textureManager.createRenderTarget(name, renderTargets, renderTargetDepth, depthReadOnly, stencilReadOnly);
}
/**
* Clears the current render buffer or the current render target (if any is set up)
* @param color Defines the color to use
* @param backBuffer Defines if the back buffer must be cleared
* @param depth Defines if the depth buffer must be cleared
* @param stencil Defines if the stencil buffer must be cleared
* @param stencilClearValue Defines the value to use to clear the stencil buffer (default is 0)
*/
clear(color, backBuffer, depth, stencil, stencilClearValue = 0) {
this._applyRenderTarget();
this._engine.clear(color, backBuffer, depth, stencil, stencilClearValue);
}
/**
* Clears the color attachments of the current render target
* @param color Defines the color to use
* @param attachments The attachments to clear
*/
clearColorAttachments(color, attachments) {
this._applyRenderTarget();
this._engine.bindAttachments(attachments);
this._engine.clear(color, true, false, false);
}
/**
* Clears all attachments (color(s) + depth/stencil) of the current render target
* @param color Defines the color to use
* @param attachments The attachments to clear
* @param backBuffer Defines if the back buffer must be cleared
* @param depth Defines if the depth buffer must be cleared
* @param stencil Defines if the stencil buffer must be cleared
* @param stencilClearValue Defines the value to use to clear the stencil buffer (default is 0)
*/
clearAttachments(color, attachments, backBuffer, depth, stencil, stencilClearValue = 0) {
this._applyRenderTarget();
this._engine.bindAttachments(attachments);
this._engine.clear(color, backBuffer, depth, stencil, stencilClearValue);
}
/**
* Binds the attachments to the current render target
* @param attachments The attachments to bind
*/
bindAttachments(attachments) {
this._applyRenderTarget();
this._engine.bindAttachments(attachments);
}
/**
* Generates mipmaps for the current render target
*/
generateMipMaps() {
if (this._currentRenderTarget?.renderTargetWrapper === undefined) {
return;
}
if (this._renderTargetIsBound && this._engine._currentRenderTarget) {
// we can't generate the mipmaps if the render target is bound
this._flushDebugMessages();
this._engine.unBindFramebuffer(this._engine._currentRenderTarget);
this._renderTargetIsBound = false;
}
const textures = this._currentRenderTarget.renderTargetWrapper.textures;
if (textures) {
for (const texture of textures) {
this._engine.generateMipmaps(texture);
}
}
}
/**
* Sets the texture sampling mode for a given texture handle
* @param handle Handle of the texture to set the sampling mode for
* @param samplingMode Sampling mode to set
*/
setTextureSamplingMode(handle, samplingMode) {
const internalTexture = this._textureManager.getTextureFromHandle(handle);
if (internalTexture && internalTexture.samplingMode !== samplingMode) {
this._engine.updateTextureSamplingMode(samplingMode, internalTexture);
}
}
/**
* Binds a texture handle to a given effect (resolves the handle to a texture and binds it to the effect)
* @param effect The effect to bind the texture to
* @param name The name of the texture in the effect
* @param handle The handle of the texture to bind
*/
bindTextureHandle(effect, name, handle) {
let texture;
const historyEntry = this._textureManager._historyTextures.get(handle);
if (historyEntry) {
texture = historyEntry.textures[historyEntry.index]; // texture we write to in this frame
if (this._currentRenderTarget !== undefined &&
this._currentRenderTarget.renderTargetWrapper !== undefined &&
this._currentRenderTarget.renderTargetWrapper.textures.includes(texture)) {
// If the current render target renders to the history write texture, we bind the read texture instead
texture = historyEntry.textures[historyEntry.index ^ 1];
}
}
else {
texture = this._textureManager._textures.get(handle).texture;
}
effect._bindTexture(name, texture);
}
/**
* Applies a full-screen effect to the current render target
* @param drawWrapper The draw wrapper containing the effect to apply
* @param customBindings The custom bindings to use when applying the effect (optional)
* @param stencilState The stencil state to use when applying the effect (optional)
* @param disableColorWrite If true, color write will be disabled when applying the effect (optional)
* @param drawBackFace If true, the fullscreen quad will be drawn as a back face (in CW - optional)
* @param depthTest If true, depth testing will be enabled when applying the effect (default is false)
* @returns True if the effect was applied, otherwise false (effect not ready)
*/
applyFullScreenEffect(drawWrapper, customBindings, stencilState, disableColorWrite, drawBackFace, depthTest) {
if (!drawWrapper.effect?.isReady()) {
return false;
}
this._applyRenderTarget();
const engineDepthMask = this._engine.getDepthWrite(); // for some reasons, depthWrite is not restored by EffectRenderer.restoreStates
const effectRenderer = drawBackFace ? this._effectRendererBack : this._effectRenderer;
effectRenderer.saveStates();
effectRenderer.setViewport();
this._engine.enableEffect(drawWrapper);
this._engine.setState(false, undefined, undefined, undefined, undefined, stencilState);
this._engine.setDepthBuffer(!!depthTest);
if (disableColorWrite) {
this._engine.setColorWrite(false);
}
this._engine.setDepthWrite(false);
effectRenderer.bindBuffers(drawWrapper.effect);
customBindings?.();
effectRenderer.draw();
effectRenderer.restoreStates();
if (disableColorWrite) {
this._engine.setColorWrite(true);
}
this._engine.setDepthWrite(engineDepthMask);
this._engine.setAlphaMode(0);
return true;
}
/**
* Copies a texture to the current render target
* @param sourceTexture The source texture to copy from
* @param forceCopyToBackbuffer If true, the copy will be done to the back buffer regardless of the current render target
*/
copyTexture(sourceTexture, forceCopyToBackbuffer = false) {
if (forceCopyToBackbuffer) {
this.bindRenderTarget();
}
this._applyRenderTarget();
this._copyTexture.copy(this._textureManager.getTextureFromHandle(sourceTexture));
}
/**
* Renders a RenderTargetTexture or a layer
* @param object The RenderTargetTexture/Layer to render
* @param viewportWidth The width of the viewport (optional for Layer, but mandatory for ObjectRenderer)
* @param viewportHeight The height of the viewport (optional for Layer, but mandatory for ObjectRenderer)
*/
render(object, viewportWidth, viewportHeight) {
if (FrameGraphRenderContext._IsObjectRenderer(object)) {
this._scene._intermediateRendering = true;
if (object.shouldRender()) {
this._scene.incrementRenderId();
this._scene.resetCachedMaterial();
this._applyRenderTarget();
object.prepareRenderList();
object.initRender(viewportWidth, viewportHeight);
object.render();
object.finishRender();
}
this._scene._intermediateRendering = false;
}
else {
this._applyRenderTarget();
object.render();
}
}
/**
* Binds a render target texture so that upcoming draw calls will render to it
* Note: it is a lazy operation, so the render target will only be bound when needed. This way, it is possible to call
* this method several times with different render targets without incurring the cost of binding if no draw calls are made
* @param renderTarget The handle of the render target texture to bind (default: undefined, meaning "back buffer"). Pass an array for MRT rendering.
* @param debugMessage Optional debug message to display when the render target is bound (visible in PIX, for example)
*/
bindRenderTarget(renderTarget, debugMessage) {
if ((renderTarget?.renderTargetWrapper === undefined && this._currentRenderTarget === undefined) ||
(renderTarget && this._currentRenderTarget && renderTarget.equals(this._currentRenderTarget))) {
this._flushDebugMessages();
if (debugMessage !== undefined) {
this._engine._debugPushGroup?.(debugMessage, 2);
this._debugMessageWhenTargetBound = undefined;
this._debugMessageHasBeenPushed = true;
}
return;
}
this._currentRenderTarget = renderTarget?.renderTargetWrapper === undefined ? undefined : renderTarget;
this._debugMessageWhenTargetBound = debugMessage;
this._renderTargetIsBound = false;
}
/** @internal */
_flushDebugMessages() {
if (this._debugMessageHasBeenPushed) {
this._engine._debugPopGroup?.(2);
this._debugMessageHasBeenPushed = false;
}
}
/** @internal */
_applyRenderTarget() {
if (this._renderTargetIsBound) {
return;
}
this._flushDebugMessages();
const renderTargetWrapper = this._currentRenderTarget?.renderTargetWrapper;
if (renderTargetWrapper === undefined) {
this._engine.restoreDefaultFramebuffer();
}
else {
if (this._engine._currentRenderTarget) {
this._engine.unBindFramebuffer(this._engine._currentRenderTarget);
}
this._engine.bindFramebuffer(renderTargetWrapper);
}
if (this._debugMessageWhenTargetBound !== undefined) {
this._engine._debugPushGroup?.(this._debugMessageWhenTargetBound, 2);
this._debugMessageWhenTargetBound = undefined;
this._debugMessageHasBeenPushed = true;
}
this._renderTargetIsBound = true;
}
/** @internal */
_isReady() {
return this._copyTexture.isReady();
}
/** @internal */
_dispose() {
this._effectRenderer.dispose();
this._effectRendererBack.dispose();
this._copyTexture.dispose();
}
}
//# sourceMappingURL=frameGraphRenderContext.js.map