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 PixelFormat from "../Core/PixelFormat.js"; import ClearCommand from "../Renderer/ClearCommand.js"; import Framebuffer from "../Renderer/Framebuffer.js"; import PixelDatatype from "../Renderer/PixelDatatype.js"; import RenderState from "../Renderer/RenderState.js"; import Sampler from "../Renderer/Sampler.js"; import ShaderSource from "../Renderer/ShaderSource.js"; import Texture from "../Renderer/Texture.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"; /** * @private */ function GlobeDepth() { this._globeColorTexture = undefined; this._primitiveColorTexture = undefined; this._depthStencilTexture = undefined; this._globeDepthTexture = undefined; this._tempGlobeDepthTexture = undefined; this._tempCopyDepthTexture = undefined; this._globeColorFramebuffer = undefined; this._primitiveColorFramebuffer = undefined; this._copyDepthFramebuffer = undefined; this._tempCopyDepthFramebuffer = undefined; this._updateDepthFramebuffer = undefined; this._clearGlobeColorCommand = undefined; this._clearPrimitiveColorCommand = undefined; this._copyColorCommand = undefined; this._copyDepthCommand = undefined; this._tempCopyDepthCommand = undefined; this._updateDepthCommand = undefined; this._mergeColorCommand = undefined; this._viewport = new BoundingRectangle(); this._rs = undefined; this._rsBlend = undefined; this._rsUpdate = undefined; this._useScissorTest = false; this._scissorRectangle = undefined; this._useLogDepth = undefined; this._useHdr = undefined; this._clearGlobeDepth = undefined; this._debugGlobeDepthViewportCommand = undefined; } Object.defineProperties(GlobeDepth.prototype, { framebuffer: { get: function () { return this._globeColorFramebuffer; }, }, primitiveFramebuffer: { get: function () { return this._primitiveColorFramebuffer; }, }, }); function executeDebugGlobeDepth(globeDepth, context, passState, useLogDepth) { if ( !defined(globeDepth._debugGlobeDepthViewportCommand) || useLogDepth !== globeDepth._useLogDepth ) { var fsSource = "uniform highp sampler2D u_depthTexture;\n" + "varying vec2 v_textureCoordinates;\n" + "void main()\n" + "{\n" + " float z_window = czm_unpackDepth(texture2D(u_depthTexture, v_textureCoordinates));\n" + " z_window = czm_reverseLogDepth(z_window); \n" + " float n_range = czm_depthRange.near;\n" + " float f_range = czm_depthRange.far;\n" + " float z_ndc = (2.0 * z_window - n_range - f_range) / (f_range - n_range);\n" + " float scale = pow(z_ndc * 0.5 + 0.5, 8.0);\n" + " gl_FragColor = vec4(mix(vec3(0.0), vec3(1.0), scale), 1.0);\n" + "}\n"; var fs = new ShaderSource({ defines: [useLogDepth ? "LOG_DEPTH" : ""], sources: [fsSource], }); globeDepth._debugGlobeDepthViewportCommand = context.createViewportQuadCommand( fs, { uniformMap: { u_depthTexture: function () { return globeDepth._globeDepthTexture; }, }, owner: globeDepth, } ); globeDepth._useLogDepth = useLogDepth; } globeDepth._debugGlobeDepthViewportCommand.execute(context, passState); } function destroyTextures(globeDepth) { globeDepth._globeColorTexture = globeDepth._globeColorTexture && !globeDepth._globeColorTexture.isDestroyed() && globeDepth._globeColorTexture.destroy(); globeDepth._depthStencilTexture = globeDepth._depthStencilTexture && !globeDepth._depthStencilTexture.isDestroyed() && globeDepth._depthStencilTexture.destroy(); globeDepth._globeDepthTexture = globeDepth._globeDepthTexture && !globeDepth._globeDepthTexture.isDestroyed() && globeDepth._globeDepthTexture.destroy(); } function destroyFramebuffers(globeDepth) { globeDepth._globeColorFramebuffer = globeDepth._globeColorFramebuffer && !globeDepth._globeColorFramebuffer.isDestroyed() && globeDepth._globeColorFramebuffer.destroy(); globeDepth._copyDepthFramebuffer = globeDepth._copyDepthFramebuffer && !globeDepth._copyDepthFramebuffer.isDestroyed() && globeDepth._copyDepthFramebuffer.destroy(); } function destroyUpdateDepthResources(globeDepth) { globeDepth._tempCopyDepthFramebuffer = globeDepth._tempCopyDepthFramebuffer && !globeDepth._tempCopyDepthFramebuffer.isDestroyed() && globeDepth._tempCopyDepthFramebuffer.destroy(); globeDepth._updateDepthFramebuffer = globeDepth._updateDepthFramebuffer && !globeDepth._updateDepthFramebuffer.isDestroyed() && globeDepth._updateDepthFramebuffer.destroy(); globeDepth._tempGlobeDepthTexture = globeDepth._tempGlobeDepthTexture && !globeDepth._tempGlobeDepthTexture.isDestroyed() && globeDepth._tempGlobeDepthTexture.destroy(); } function createUpdateDepthResources( globeDepth, context, width, height, passState ) { globeDepth._tempGlobeDepthTexture = new Texture({ context: context, width: width, height: height, pixelFormat: PixelFormat.RGBA, pixelDatatype: PixelDatatype.UNSIGNED_BYTE, sampler: Sampler.NEAREST, }); globeDepth._tempCopyDepthFramebuffer = new Framebuffer({ context: context, colorTextures: [globeDepth._tempGlobeDepthTexture], destroyAttachments: false, }); globeDepth._updateDepthFramebuffer = new Framebuffer({ context: context, colorTextures: [globeDepth._globeDepthTexture], depthStencilTexture: passState.framebuffer.depthStencilTexture, destroyAttachments: false, }); } function createTextures(globeDepth, context, width, height, hdr) { var pixelDatatype = hdr ? context.halfFloatingPointTexture ? PixelDatatype.HALF_FLOAT : PixelDatatype.FLOAT : PixelDatatype.UNSIGNED_BYTE; globeDepth._globeColorTexture = new Texture({ context: context, width: width, height: height, pixelFormat: PixelFormat.RGBA, pixelDatatype: pixelDatatype, sampler: Sampler.NEAREST, }); globeDepth._depthStencilTexture = new Texture({ context: context, width: width, height: height, pixelFormat: PixelFormat.DEPTH_STENCIL, pixelDatatype: PixelDatatype.UNSIGNED_INT_24_8, }); globeDepth._globeDepthTexture = new Texture({ context: context, width: width, height: height, pixelFormat: PixelFormat.RGBA, pixelDatatype: PixelDatatype.UNSIGNED_BYTE, sampler: Sampler.NEAREST, }); } function createFramebuffers(globeDepth, context) { globeDepth._globeColorFramebuffer = new Framebuffer({ context: context, colorTextures: [globeDepth._globeColorTexture], depthStencilTexture: globeDepth._depthStencilTexture, destroyAttachments: false, }); globeDepth._copyDepthFramebuffer = new Framebuffer({ context: context, colorTextures: [globeDepth._globeDepthTexture], destroyAttachments: false, }); } function createPrimitiveFramebuffer(globeDepth, context, width, height, hdr) { var pixelDatatype = hdr ? context.halfFloatingPointTexture ? PixelDatatype.HALF_FLOAT : PixelDatatype.FLOAT : PixelDatatype.UNSIGNED_BYTE; globeDepth._primitiveColorTexture = new Texture({ context: context, width: width, height: height, pixelFormat: PixelFormat.RGBA, pixelDatatype: pixelDatatype, sampler: Sampler.NEAREST, }); globeDepth._primitiveColorFramebuffer = new Framebuffer({ context: context, colorTextures: [globeDepth._primitiveColorTexture], depthStencilTexture: globeDepth._depthStencilTexture, destroyAttachments: false, }); } function destroyPrimitiveFramebuffer(globeDepth) { globeDepth._primitiveColorTexture = globeDepth._primitiveColorTexture && !globeDepth._primitiveColorTexture.isDestroyed() && globeDepth._primitiveColorTexture.destroy(); globeDepth._primitiveColorFramebuffer = globeDepth._primitiveColorFramebuffer && !globeDepth._primitiveColorFramebuffer.isDestroyed() && globeDepth._primitiveColorFramebuffer.destroy(); } function updateFramebuffers( globeDepth, context, width, height, hdr, clearGlobeDepth ) { var colorTexture = globeDepth._globeColorTexture; var textureChanged = !defined(colorTexture) || colorTexture.width !== width || colorTexture.height !== height || hdr !== globeDepth._useHdr; if (textureChanged) { destroyTextures(globeDepth); destroyFramebuffers(globeDepth); createTextures(globeDepth, context, width, height, hdr, clearGlobeDepth); createFramebuffers(globeDepth, context, clearGlobeDepth); } if (textureChanged || clearGlobeDepth !== globeDepth._clearGlobeDepth) { destroyPrimitiveFramebuffer(globeDepth); if (clearGlobeDepth) { createPrimitiveFramebuffer(globeDepth, context, width, height, hdr); } } } function updateCopyCommands(globeDepth, context, width, height, passState) { globeDepth._viewport.width = width; globeDepth._viewport.height = height; var useScissorTest = !BoundingRectangle.equals( globeDepth._viewport, passState.viewport ); var 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(globeDepth._viewport, globeDepth._rs.viewport) || updateScissor ) { globeDepth._rs = RenderState.fromCache({ viewport: globeDepth._viewport, scissorTest: { enabled: globeDepth._useScissorTest, rectangle: globeDepth._scissorRectangle, }, }); globeDepth._rsBlend = RenderState.fromCache({ viewport: globeDepth._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: globeDepth._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._depthStencilTexture; }, }, owner: globeDepth, } ); } globeDepth._copyDepthCommand.framebuffer = globeDepth._copyDepthFramebuffer; globeDepth._copyDepthCommand.renderState = globeDepth._rs; if (!defined(globeDepth._copyColorCommand)) { globeDepth._copyColorCommand = context.createViewportQuadCommand( PassThrough, { uniformMap: { colorTexture: function () { return globeDepth._globeColorTexture; }, }, 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; globeDepth._tempCopyDepthCommand.renderState = globeDepth._rs; if (!defined(globeDepth._updateDepthCommand)) { globeDepth._updateDepthCommand = context.createViewportQuadCommand( PassThrough, { uniformMap: { colorTexture: function () { return globeDepth._tempGlobeDepthTexture; }, }, owner: globeDepth, } ); } globeDepth._updateDepthCommand.framebuffer = globeDepth._updateDepthFramebuffer; 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._globeColorFramebuffer; if (!defined(globeDepth._clearPrimitiveColorCommand)) { globeDepth._clearPrimitiveColorCommand = new ClearCommand({ color: new Color(0.0, 0.0, 0.0, 0.0), stencil: 0.0, owner: globeDepth, }); } globeDepth._clearPrimitiveColorCommand.framebuffer = globeDepth._primitiveColorFramebuffer; if (!defined(globeDepth._mergeColorCommand)) { globeDepth._mergeColorCommand = context.createViewportQuadCommand( PassThrough, { uniformMap: { colorTexture: function () { return globeDepth._primitiveColorTexture; }, }, owner: globeDepth, } ); } globeDepth._mergeColorCommand.framebuffer = globeDepth._globeColorFramebuffer; globeDepth._mergeColorCommand.renderState = globeDepth._rsBlend; } GlobeDepth.prototype.executeDebugGlobeDepth = function ( context, passState, useLogDepth ) { executeDebugGlobeDepth(this, context, passState, useLogDepth); }; GlobeDepth.prototype.update = function ( context, passState, viewport, hdr, clearGlobeDepth ) { var width = viewport.width; var height = viewport.height; updateFramebuffers(this, context, width, height, hdr, clearGlobeDepth); updateCopyCommands(this, context, width, height, passState); context.uniformState.globeDepthTexture = undefined; this._useHdr = hdr; this._clearGlobeDepth = clearGlobeDepth; }; GlobeDepth.prototype.executeCopyDepth = function (context, passState) { if (defined(this._copyDepthCommand)) { this._copyDepthCommand.execute(context, passState); context.uniformState.globeDepthTexture = this._globeDepthTexture; } }; GlobeDepth.prototype.executeUpdateDepth = function ( context, passState, clearGlobeDepth ) { var depthTextureToCopy = passState.framebuffer.depthStencilTexture; if (clearGlobeDepth || depthTextureToCopy !== this._depthStencilTexture) { // 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. if (defined(this._updateDepthCommand)) { if ( !defined(this._updateDepthFramebuffer) || this._updateDepthFramebuffer.depthStencilTexture !== depthTextureToCopy || this._updateDepthFramebuffer.getColorTexture(0) !== this._globeDepthTexture ) { var width = this._globeDepthTexture.width; var height = this._globeDepthTexture.height; destroyUpdateDepthResources(this); createUpdateDepthResources(this, context, width, height, passState); updateCopyCommands(this, context, width, height, passState); } this._tempCopyDepthTexture = depthTextureToCopy; this._tempCopyDepthCommand.execute(context, passState); this._updateDepthCommand.execute(context, passState); } return; } // Fast path - the depth texture can be copied normally. if (defined(this._copyDepthCommand)) { this._copyDepthCommand.execute(context, passState); } }; GlobeDepth.prototype.executeCopyColor = function (context, passState) { if (defined(this._copyColorCommand)) { this._copyColorCommand.execute(context, passState); } }; GlobeDepth.prototype.executeMergeColor = function (context, passState) { if (defined(this._mergeColorCommand)) { this._mergeColorCommand.execute(context, passState); } }; GlobeDepth.prototype.clear = function (context, passState, clearColor) { var clear = this._clearGlobeColorCommand; if (defined(clear)) { Color.clone(clearColor, clear.color); clear.execute(context, passState); } clear = this._clearPrimitiveColorCommand; if (defined(clear) && defined(this._primitiveColorFramebuffer)) { clear.execute(context, passState); } }; GlobeDepth.prototype.isDestroyed = function () { return false; }; GlobeDepth.prototype.destroy = function () { destroyTextures(this); destroyFramebuffers(this); destroyPrimitiveFramebuffer(this); destroyUpdateDepthResources(this); 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(); } if (defined(this._mergeColorCommand)) { this._mergeColorCommand.shaderProgram = this._mergeColorCommand.shaderProgram.destroy(); } if (defined(this._debugGlobeDepthViewportCommand)) { this._debugGlobeDepthViewportCommand.shaderProgram = this._debugGlobeDepthViewportCommand.shaderProgram.destroy(); } return destroyObject(this); }; export default GlobeDepth;