UNPKG

@cesium/engine

Version:

CesiumJS is a JavaScript library for creating 3D globes and 2D maps in a web browser without a plugin.

408 lines (367 loc) 12.3 kB
import BoundingRectangle from "../Core/BoundingRectangle.js"; import Color from "../Core/Color.js"; import defined from "../Core/defined.js"; import destroyObject from "../Core/destroyObject.js"; import ClearCommand from "../Renderer/ClearCommand.js"; import FramebufferManager from "../Renderer/FramebufferManager.js"; import PixelDatatype from "../Renderer/PixelDatatype.js"; import RenderState from "../Renderer/RenderState.js"; import PassThrough from "../Shaders/PostProcessStages/PassThrough.js"; import PassThroughDepth from "../Shaders/PostProcessStages/PassThroughDepth.js"; import BlendingState from "./BlendingState.js"; import StencilConstants from "./StencilConstants.js"; import StencilFunction from "./StencilFunction.js"; import StencilOperation from "./StencilOperation.js"; /** * @alias GlobeDepth * @constructor * * @private */ function GlobeDepth() { this._picking = false; this._numSamples = 1; this._tempCopyDepthTexture = undefined; this._pickColorFramebuffer = new FramebufferManager({ depthStencil: true, supportsDepthTexture: true, }); this._outputFramebuffer = new FramebufferManager({ depthStencil: true, supportsDepthTexture: true, }); this._copyDepthFramebuffer = new FramebufferManager(); this._tempCopyDepthFramebuffer = new FramebufferManager(); this._updateDepthFramebuffer = new FramebufferManager({ createColorAttachments: false, createDepthAttachments: false, depthStencil: true, }); this._clearGlobeColorCommand = undefined; this._copyColorCommand = undefined; this._copyDepthCommand = undefined; this._tempCopyDepthCommand = undefined; this._updateDepthCommand = undefined; this._viewport = new BoundingRectangle(); this._rs = undefined; this._rsBlend = undefined; this._rsUpdate = undefined; this._useScissorTest = false; this._scissorRectangle = undefined; this._useHdr = undefined; this._clearGlobeDepth = undefined; } Object.defineProperties(GlobeDepth.prototype, { colorFramebufferManager: { get: function () { return this._picking ? this._pickColorFramebuffer : this._outputFramebuffer; }, }, framebuffer: { get: function () { return this.colorFramebufferManager.framebuffer; }, }, depthStencilTexture: { get: function () { return this.colorFramebufferManager.getDepthStencilTexture(); }, }, picking: { get: function () { return this._picking; }, set: function (value) { this._picking = value; }, }, }); function updateCopyCommands(globeDepth, context, width, height, passState) { const viewport = globeDepth._viewport; viewport.width = width; viewport.height = height; const useScissorTest = !BoundingRectangle.equals( viewport, passState.viewport, ); let updateScissor = useScissorTest !== globeDepth._useScissorTest; globeDepth._useScissorTest = useScissorTest; if ( !BoundingRectangle.equals(globeDepth._scissorRectangle, passState.viewport) ) { globeDepth._scissorRectangle = BoundingRectangle.clone( passState.viewport, globeDepth._scissorRectangle, ); updateScissor = true; } if ( !defined(globeDepth._rs) || !BoundingRectangle.equals(viewport, globeDepth._rs.viewport) || updateScissor ) { globeDepth._rs = RenderState.fromCache({ viewport: viewport, scissorTest: { enabled: globeDepth._useScissorTest, rectangle: globeDepth._scissorRectangle, }, }); globeDepth._rsBlend = RenderState.fromCache({ viewport: viewport, scissorTest: { enabled: globeDepth._useScissorTest, rectangle: globeDepth._scissorRectangle, }, blending: BlendingState.ALPHA_BLEND, }); // Copy packed depth only if the 3D Tiles bit is set globeDepth._rsUpdate = RenderState.fromCache({ viewport: viewport, scissorTest: { enabled: globeDepth._useScissorTest, rectangle: globeDepth._scissorRectangle, }, stencilTest: { enabled: true, frontFunction: StencilFunction.EQUAL, frontOperation: { fail: StencilOperation.KEEP, zFail: StencilOperation.KEEP, zPass: StencilOperation.KEEP, }, backFunction: StencilFunction.NEVER, reference: StencilConstants.CESIUM_3D_TILE_MASK, mask: StencilConstants.CESIUM_3D_TILE_MASK, }, }); } if (!defined(globeDepth._copyDepthCommand)) { globeDepth._copyDepthCommand = context.createViewportQuadCommand( PassThroughDepth, { uniformMap: { u_depthTexture: function () { return globeDepth.colorFramebufferManager.getDepthStencilTexture(); }, }, owner: globeDepth, }, ); } globeDepth._copyDepthCommand.framebuffer = globeDepth._copyDepthFramebuffer.framebuffer; globeDepth._copyDepthCommand.renderState = globeDepth._rs; if (!defined(globeDepth._copyColorCommand)) { globeDepth._copyColorCommand = context.createViewportQuadCommand( PassThrough, { uniformMap: { colorTexture: function () { return globeDepth.colorFramebufferManager.getColorTexture(); }, }, owner: globeDepth, }, ); } globeDepth._copyColorCommand.renderState = globeDepth._rs; if (!defined(globeDepth._tempCopyDepthCommand)) { globeDepth._tempCopyDepthCommand = context.createViewportQuadCommand( PassThroughDepth, { uniformMap: { u_depthTexture: function () { return globeDepth._tempCopyDepthTexture; }, }, owner: globeDepth, }, ); } globeDepth._tempCopyDepthCommand.framebuffer = globeDepth._tempCopyDepthFramebuffer.framebuffer; globeDepth._tempCopyDepthCommand.renderState = globeDepth._rs; if (!defined(globeDepth._updateDepthCommand)) { globeDepth._updateDepthCommand = context.createViewportQuadCommand( PassThrough, { uniformMap: { colorTexture: function () { return globeDepth._tempCopyDepthFramebuffer.getColorTexture(); }, }, owner: globeDepth, }, ); } globeDepth._updateDepthCommand.framebuffer = globeDepth._updateDepthFramebuffer.framebuffer; globeDepth._updateDepthCommand.renderState = globeDepth._rsUpdate; if (!defined(globeDepth._clearGlobeColorCommand)) { globeDepth._clearGlobeColorCommand = new ClearCommand({ color: new Color(0.0, 0.0, 0.0, 0.0), stencil: 0.0, owner: globeDepth, }); } globeDepth._clearGlobeColorCommand.framebuffer = globeDepth.framebuffer; } /** * Update framebuffers and render state. * * @param {Context} context The context used for rendering. * @param {PassState} passState Rendering state for subsequent render passes. * @param {BoundingRectangle} viewport The viewport for the rendering. * @param {number} numSamples The number of samples for multi-sample anti-aliasing (MSAA). * @param {boolean} hdr <code>true</code> if the color output needs to be floating point for HDR rendering. * @param {boolean} clearGlobeDepth <code>true</code> if the depth buffer should be cleared before rendering 3D Tiles and opaque entities. * * @private */ GlobeDepth.prototype.update = function ( context, passState, viewport, numSamples, hdr, clearGlobeDepth, ) { const { width, height } = viewport; const pixelDatatype = hdr ? context.halfFloatingPointTexture ? PixelDatatype.HALF_FLOAT : PixelDatatype.FLOAT : PixelDatatype.UNSIGNED_BYTE; this._numSamples = numSamples; if (this.picking) { this._pickColorFramebuffer.update(context, width, height); } else { this._outputFramebuffer.update( context, width, height, numSamples, pixelDatatype, ); } this._copyDepthFramebuffer.update(context, width, height); updateCopyCommands(this, context, width, height, passState); context.uniformState.globeDepthTexture = undefined; this._clearGlobeDepth = clearGlobeDepth; }; /** * If using MSAA, resolve the stencil. * * @param {Context} context * @param {boolean} blitStencil <code>true</code> if the stencil has been set. * * @private */ GlobeDepth.prototype.prepareColorTextures = function (context, blitStencil) { if (!this.picking && this._numSamples > 1) { this._outputFramebuffer.prepareTextures(context, blitStencil); } }; GlobeDepth.prototype.executeCopyDepth = function (context, passState) { if (defined(this._copyDepthCommand)) { this.prepareColorTextures(context); this._copyDepthCommand.execute(context, passState); context.uniformState.globeDepthTexture = this._copyDepthFramebuffer.getColorTexture(); } }; /** * Update the existing depth texture using a stencil. * * @param {Context} context The context used for rendering. * @param {PassState} passState Render state for subsequent rendering passes. * @param {Texture} [depthTexture] The depth texture to copy. */ GlobeDepth.prototype.executeUpdateDepth = function ( context, passState, depthTexture, ) { const depthTextureToCopy = defined(depthTexture) ? depthTexture : passState.framebuffer.depthStencilTexture; if ( !this._clearGlobeDepth && depthTextureToCopy === this.colorFramebufferManager.getDepthStencilTexture() ) { // Fast path - the depth texture can be copied normally. if (defined(this._copyDepthCommand)) { this._copyDepthCommand.execute(context, passState); } return; } if (!defined(this._updateDepthCommand)) { return; } // First copy the depth to a temporary globe depth texture, then update the // main globe depth texture where the stencil bit for 3D Tiles is set. // This preserves the original globe depth except where 3D Tiles is rendered. // The additional texture and framebuffer resources are created on demand. const updateDepthFramebuffer = this._updateDepthFramebuffer; if ( !defined(updateDepthFramebuffer.framebuffer) || updateDepthFramebuffer.getDepthStencilTexture() !== depthTextureToCopy || updateDepthFramebuffer.getColorTexture() !== this._copyDepthFramebuffer.getColorTexture() ) { const colorTexture = this._copyDepthFramebuffer.getColorTexture(); const { width, height } = colorTexture; this._tempCopyDepthFramebuffer.destroy(); this._tempCopyDepthFramebuffer.update(context, width, height); updateDepthFramebuffer.setColorTexture(colorTexture, 0); updateDepthFramebuffer.setDepthStencilTexture(depthTextureToCopy); updateDepthFramebuffer.update(context, width, height); updateCopyCommands(this, context, width, height, passState); } this._tempCopyDepthTexture = depthTextureToCopy; this._tempCopyDepthCommand.execute(context, passState); this._updateDepthCommand.execute(context, passState); }; GlobeDepth.prototype.executeCopyColor = function (context, passState) { if (defined(this._copyColorCommand)) { this._copyColorCommand.execute(context, passState); } }; GlobeDepth.prototype.clear = function (context, passState, clearColor) { const clear = this._clearGlobeColorCommand; if (defined(clear)) { Color.clone(clearColor, clear.color); this.colorFramebufferManager.clear(context, clear, passState); } }; GlobeDepth.prototype.isDestroyed = function () { return false; }; GlobeDepth.prototype.destroy = function () { this._pickColorFramebuffer.destroy(); this._outputFramebuffer.destroy(); this._copyDepthFramebuffer.destroy(); this._tempCopyDepthFramebuffer.destroy(); this._updateDepthFramebuffer.destroy(); if (defined(this._copyColorCommand)) { this._copyColorCommand.shaderProgram = this._copyColorCommand.shaderProgram.destroy(); } if (defined(this._copyDepthCommand)) { this._copyDepthCommand.shaderProgram = this._copyDepthCommand.shaderProgram.destroy(); } if (defined(this._tempCopyDepthCommand)) { this._tempCopyDepthCommand.shaderProgram = this._tempCopyDepthCommand.shaderProgram.destroy(); } if (defined(this._updateDepthCommand)) { this._updateDepthCommand.shaderProgram = this._updateDepthCommand.shaderProgram.destroy(); } return destroyObject(this); }; export default GlobeDepth;