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.

518 lines (517 loc) 20.1 kB
import { HasStencilAspect } from "../Materials/Textures/textureHelper.functions.js"; /** * Wrapper around a render target (either single or multi textures) */ export class RenderTargetWrapper { /** * Gets the depth/stencil texture */ get depthStencilTexture() { return this._depthStencilTexture; } /** * Sets the depth/stencil texture * @param texture The depth/stencil texture to set * @param disposeExisting True to dispose the existing depth/stencil texture (if any) before replacing it (default: true) */ setDepthStencilTexture(texture, disposeExisting = true) { if (disposeExisting && this._depthStencilTexture) { this._depthStencilTexture.dispose(); } this._depthStencilTexture = texture; this._generateDepthBuffer = this._generateStencilBuffer = this._depthStencilTextureWithStencil = false; if (texture) { this._generateDepthBuffer = true; this._generateStencilBuffer = this._depthStencilTextureWithStencil = HasStencilAspect(texture.format); } } /** * Indicates if the depth/stencil texture has a stencil aspect */ get depthStencilTextureWithStencil() { return this._depthStencilTextureWithStencil; } /** * Defines if the render target wrapper is for a cube texture or if false a 2d texture */ get isCube() { return this._isCube; } /** * Defines if the render target wrapper is for a single or multi target render wrapper */ get isMulti() { return this._isMulti; } /** * Defines if the render target wrapper is for a single or an array of textures */ get is2DArray() { return this.layers > 0; } /** * Defines if the render target wrapper is for a 3D texture */ get is3D() { return this.depth > 0; } /** * Gets the size of the render target wrapper (used for cubes, as width=height in this case) */ get size() { return this.width; } /** * Gets the width of the render target wrapper */ get width() { return this._size.width ?? this._size; } /** * Gets the height of the render target wrapper */ get height() { return this._size.height ?? this._size; } /** * Gets the number of layers of the render target wrapper (only used if is2DArray is true and wrapper is not a multi render target) */ get layers() { return this._size.layers || 0; } /** * Gets the depth of the render target wrapper (only used if is3D is true and wrapper is not a multi render target) */ get depth() { return this._size.depth || 0; } /** * Gets the render texture. If this is a multi render target, gets the first texture */ get texture() { return this._textures?.[0] ?? null; } /** * Gets the list of render textures. If we are not in a multi render target, the list will be null (use the texture getter instead) */ get textures() { return this._textures; } /** * Gets the face indices that correspond to the list of render textures. If we are not in a multi render target, the list will be null */ get faceIndices() { return this._faceIndices; } /** * Gets the layer indices that correspond to the list of render textures. If we are not in a multi render target, the list will be null */ get layerIndices() { return this._layerIndices; } /** * Gets the base array layer of a texture in the textures array * This is an number that is calculated based on the layer and face indices set for this texture at that index * @param index The index of the texture in the textures array to get the base array layer for * @returns the base array layer of the texture at the given index */ getBaseArrayLayer(index) { if (!this._textures) { return -1; } const texture = this._textures[index]; const layerIndex = this._layerIndices?.[index] ?? 0; const faceIndex = this._faceIndices?.[index] ?? 0; return texture.isCube ? layerIndex * 6 + faceIndex : texture.is3D ? 0 : layerIndex; } /** * Gets the sample count of the render target */ get samples() { return this._samples; } /** * Sets the sample count of the render target * @param value sample count * @param initializeBuffers If set to true, the engine will make an initializing call to drawBuffers (only used when isMulti=true). * @param force true to force calling the update sample count engine function even if the current sample count is equal to value * @returns the sample count that has been set */ setSamples(value, initializeBuffers = true, force = false) { if (this.samples === value && !force) { return value; } const result = this._isMulti ? this._engine.updateMultipleRenderTargetTextureSampleCount(this, value, initializeBuffers) : this._engine.updateRenderTargetTextureSampleCount(this, value); this._samples = value; return result; } /** * Resolves the MSAA textures into their non-MSAA version. * Note that if samples equals 1 (no MSAA), no resolve is performed. */ resolveMSAATextures() { if (this.isMulti) { this._engine.resolveMultiFramebuffer(this); } else { this._engine.resolveFramebuffer(this); } } /** * Generates mipmaps for each texture of the render target */ generateMipMaps() { if (this._engine._currentRenderTarget === this) { this._engine.unBindFramebuffer(this, true); } if (this.isMulti) { this._engine.generateMipMapsMultiFramebuffer(this); } else { this._engine.generateMipMapsFramebuffer(this); } } /** * Initializes the render target wrapper * @param isMulti true if the wrapper is a multi render target * @param isCube true if the wrapper should render to a cube texture * @param size size of the render target (width/height/layers) * @param engine engine used to create the render target * @param label defines the label to use for the wrapper (for debugging purpose only) */ constructor(isMulti, isCube, size, engine, label) { this._textures = null; this._faceIndices = null; this._layerIndices = null; /** @internal */ this._samples = 1; /** @internal */ this._attachments = null; /** @internal */ this._generateStencilBuffer = false; /** @internal */ this._generateDepthBuffer = false; /** @internal */ this._depthStencilTextureWithStencil = false; /** * Sets this property to true to disable the automatic MSAA resolve that happens when the render target wrapper is unbound (default is false) */ this.disableAutomaticMSAAResolve = false; /** * Indicates if MSAA color texture(s) should be resolved when a resolve occur (either automatically by the engine or manually by the user) (default is true) * Note that you can trigger a MSAA resolve at any time by calling resolveMSAATextures() */ this.resolveMSAAColors = true; /** * Indicates if MSAA depth texture should be resolved when a resolve occur (either automatically by the engine or manually by the user) (default is false) */ this.resolveMSAADepth = false; /** * Indicates if MSAA stencil texture should be resolved when a resolve occur (either automatically by the engine or manually by the user) (default is false) */ this.resolveMSAAStencil = false; this._isMulti = isMulti; this._isCube = isCube; this._size = size; this._engine = engine; this._depthStencilTexture = null; this.label = label; } /** * Sets the render target texture(s) * @param textures texture(s) to set */ setTextures(textures) { if (Array.isArray(textures)) { this._textures = textures; } else if (textures) { this._textures = [textures]; } else { this._textures = null; } } /** * Set a texture in the textures array * @param texture The texture to set * @param index The index in the textures array to set * @param disposePrevious If this function should dispose the previous texture */ setTexture(texture, index = 0, disposePrevious = true) { if (!this._textures) { this._textures = []; } if (this._textures[index] === texture) { return; } if (this._textures[index] && disposePrevious) { this._textures[index].dispose(); } this._textures[index] = texture; } /** * Sets the layer and face indices of every render target texture bound to each color attachment * @param layers The layers of each texture to be set * @param faces The faces of each texture to be set */ setLayerAndFaceIndices(layers, faces) { this._layerIndices = layers; this._faceIndices = faces; } /** * Sets the layer and face indices of a texture in the textures array that should be bound to each color attachment * @param index The index of the texture in the textures array to modify * @param layer The layer of the texture to be set * @param face The face of the texture to be set */ setLayerAndFaceIndex(index = 0, layer, face) { if (!this._layerIndices) { this._layerIndices = []; } if (!this._faceIndices) { this._faceIndices = []; } if (layer !== undefined && layer >= 0) { this._layerIndices[index] = layer; } if (face !== undefined && face >= 0) { this._faceIndices[index] = face; } } /** * Creates the depth/stencil texture * @param comparisonFunction Comparison function to use for the texture * @param bilinearFiltering true if bilinear filtering should be used when sampling the texture * @param generateStencil Not used anymore. "format" will be used to determine if stencil should be created * @param samples sample count to use when creating the texture (default: 1) * @param format format of the depth texture (default: 14) * @param label defines the label to use for the texture (for debugging purpose only) * @returns the depth/stencil created texture */ createDepthStencilTexture(comparisonFunction = 0, bilinearFiltering = true, generateStencil = false, samples = 1, format = 14, label) { this._depthStencilTexture?.dispose(); this._depthStencilTextureWithStencil = generateStencil; this._depthStencilTextureLabel = label; this._depthStencilTexture = this._engine.createDepthStencilTexture(this._size, { bilinearFiltering, comparisonFunction, generateStencil, isCube: this._isCube, samples, depthTextureFormat: format, label, }, this); return this._depthStencilTexture; } /** * @deprecated Use shareDepth instead * @param renderTarget Destination renderTarget */ _shareDepth(renderTarget) { this.shareDepth(renderTarget); } /** * Shares the depth buffer of this render target with another render target. * @param renderTarget Destination renderTarget */ shareDepth(renderTarget) { if (this._depthStencilTexture) { if (renderTarget._depthStencilTexture) { renderTarget._depthStencilTexture.dispose(); } renderTarget._depthStencilTexture = this._depthStencilTexture; renderTarget._depthStencilTextureWithStencil = this._depthStencilTextureWithStencil; this._depthStencilTexture.incrementReferences(); } } /** * @internal */ _swapAndDie(target) { if (this.texture) { this.texture._swapAndDie(target); } this._textures = null; this.dispose(true); } _cloneRenderTargetWrapper() { let rtw = null; if (this._isMulti) { const textureArray = this.textures; if (textureArray && textureArray.length > 0) { let generateDepthTexture = false; let textureCount = textureArray.length; let depthTextureFormat = -1; const lastTextureSource = textureArray[textureArray.length - 1]._source; if (lastTextureSource === 14 /* InternalTextureSource.Depth */ || lastTextureSource === 12 /* InternalTextureSource.DepthStencil */) { generateDepthTexture = true; depthTextureFormat = textureArray[textureArray.length - 1].format; textureCount--; } const samplingModes = []; const types = []; const formats = []; const targetTypes = []; const faceIndex = []; const layerIndex = []; const layerCounts = []; const internalTexture2Index = {}; for (let i = 0; i < textureCount; ++i) { const texture = textureArray[i]; samplingModes.push(texture.samplingMode); types.push(texture.type); formats.push(texture.format); const index = internalTexture2Index[texture.uniqueId]; if (index !== undefined) { targetTypes.push(-1); layerCounts.push(0); } else { internalTexture2Index[texture.uniqueId] = i; if (texture.is2DArray) { targetTypes.push(35866); layerCounts.push(texture.depth); } else if (texture.isCube) { targetTypes.push(34067); layerCounts.push(0); } /*else if (texture.isCubeArray) { targetTypes.push(3735928559); layerCounts.push(texture.depth); }*/ else if (texture.is3D) { targetTypes.push(32879); layerCounts.push(texture.depth); } else { targetTypes.push(3553); layerCounts.push(0); } } if (this._faceIndices) { faceIndex.push(this._faceIndices[i] ?? 0); } if (this._layerIndices) { layerIndex.push(this._layerIndices[i] ?? 0); } } const optionsMRT = { samplingModes, generateMipMaps: textureArray[0].generateMipMaps, generateDepthBuffer: this._generateDepthBuffer, generateStencilBuffer: this._generateStencilBuffer, generateDepthTexture, depthTextureFormat, types, formats, textureCount, targetTypes, faceIndex, layerIndex, layerCounts, label: this.label, }; const size = { width: this.width, height: this.height, depth: this.depth, }; rtw = this._engine.createMultipleRenderTarget(size, optionsMRT); for (let i = 0; i < textureCount; ++i) { if (targetTypes[i] !== -1) { continue; } const index = internalTexture2Index[textureArray[i].uniqueId]; rtw.setTexture(rtw.textures[index], i); } } } else { const options = {}; options.generateDepthBuffer = this._generateDepthBuffer; options.generateMipMaps = this.texture?.generateMipMaps ?? false; options.generateStencilBuffer = this._generateStencilBuffer; options.samplingMode = this.texture?.samplingMode; options.type = this.texture?.type; options.format = this.texture?.format; options.noColorAttachment = !this._textures; options.label = this.label; if (this.isCube) { rtw = this._engine.createRenderTargetCubeTexture(this.width, options); } else { const size = { width: this.width, height: this.height, layers: this.is2DArray || this.is3D ? this.texture?.depth : undefined, }; rtw = this._engine.createRenderTargetTexture(size, options); } if (rtw.texture) { rtw.texture.isReady = true; } } return rtw; } _swapRenderTargetWrapper(target) { if (this._textures && target._textures) { for (let i = 0; i < this._textures.length; ++i) { this._textures[i]._swapAndDie(target._textures[i], false); target._textures[i].isReady = true; } } if (this._depthStencilTexture && target._depthStencilTexture) { this._depthStencilTexture._swapAndDie(target._depthStencilTexture); target._depthStencilTexture.isReady = true; } this._textures = null; this._depthStencilTexture = null; } /** @internal */ _rebuild() { const rtw = this._cloneRenderTargetWrapper(); if (!rtw) { return; } if (this._depthStencilTexture) { const samplingMode = this._depthStencilTexture.samplingMode; const format = this._depthStencilTexture.format; const bilinear = samplingMode === 2 || samplingMode === 3 || samplingMode === 11; rtw.createDepthStencilTexture(this._depthStencilTexture._comparisonFunction, bilinear, this._depthStencilTextureWithStencil, this._depthStencilTexture.samples, format, this._depthStencilTextureLabel); } if (this.samples > 1) { rtw.setSamples(this.samples); } rtw._swapRenderTargetWrapper(this); rtw.dispose(); } /** * Releases the internal render textures */ releaseTextures() { if (this._textures) { for (let i = 0; i < this._textures.length; ++i) { this._textures[i].dispose(); } } this._textures = null; } /** * Disposes the whole render target wrapper * @param disposeOnlyFramebuffers true if only the frame buffers should be released (used for the WebGL engine). If false, all the textures will also be released */ dispose(disposeOnlyFramebuffers = false) { if (!disposeOnlyFramebuffers) { this._depthStencilTexture?.dispose(); this._depthStencilTexture = null; this.releaseTextures(); } this._engine._releaseRenderTargetWrapper(this); } } //# sourceMappingURL=renderTargetWrapper.js.map