import defined from "../Core/defined.js"; import destroyObject from "../Core/destroyObject.js"; import PixelFormat from "../Core/PixelFormat.js"; import Color from "../Core/Color.js"; import PixelDatatype from "../Renderer/PixelDatatype.js"; import FramebufferManager from "../Renderer/FramebufferManager.js"; import ClearCommand from "../Renderer/ClearCommand.js"; /** * Creates and manages a framebuffer for the planar fill feature-ID pre-pass. * * During this pass, non-behind planar fill geometry writes its per-fragment * feature ID into a screen-sized texture. Later, primitives with * behind: true (BENTLEY_materials_planar_fill) sample this * texture to check whether the pixel they are about to overwrite belongs to * the same logical object (same feature ID). Only then do they apply an * additional depth offset, pushing the fill behind its own object's edges * and non-behind fills — but NOT behind other objects. * * Layout: * Color attachment 0 – R32F (single RED channel): encoded feature ID. * Depth-stencil attachment – shared with the main scene for correct depth testing. * * @alias PlanarFillIdFramebuffer * @constructor * @private */ function PlanarFillIdFramebuffer() { this._framebufferManager = new FramebufferManager({ colorAttachmentsLength: 1, createColorAttachments: true, depthStencil: true, supportsDepthTexture: true, color: true, }); this._framebuffer = undefined; this._idTexture = undefined; this._depthStencilTexture = undefined; this._clearCommand = new ClearCommand({ color: new Color(0.0, 0.0, 0.0, 0.0), depth: 1.0, stencil: 0, owner: this, }); } Object.defineProperties(PlanarFillIdFramebuffer.prototype, { /** * Gets the underlying framebuffer. * @memberof PlanarFillIdFramebuffer.prototype * @type {Framebuffer} * @readonly */ framebuffer: { get: function () { return this._framebuffer; }, }, /** * Gets the feature-ID texture (color attachment 0). * @memberof PlanarFillIdFramebuffer.prototype * @type {Texture} * @readonly */ idTexture: { get: function () { return this._idTexture; }, }, /** * Gets the depth-stencil texture. * @memberof PlanarFillIdFramebuffer.prototype * @type {Texture} * @readonly */ depthStencilTexture: { get: function () { return this._depthStencilTexture; }, }, }); /** * Updates (creates / resizes) the framebuffer to match the viewport. * * @param {Context} context * @param {BoundingRectangle} viewport * @param {boolean} hdr * @returns {boolean} true if the framebuffer was recreated. */ PlanarFillIdFramebuffer.prototype.update = function (context, viewport, hdr) { const width = viewport.width; const height = viewport.height; // Feature IDs are integers, so a 32-bit float channel provides plenty of range // for feature IDs. A single RED channel (R32F) is used since only one value is // stored per pixel. Rendering to R32F requires EXT_color_buffer_float, which is // available in WebGL2 on all browsers CesiumJS supports; the UNSIGNED_BYTE fallback // below only exists for stubbed WebGL contexts possibly used in tests. const pixelDatatype = context.colorBufferFloat ? PixelDatatype.FLOAT : PixelDatatype.UNSIGNED_BYTE; const changed = this._framebufferManager.update( context, width, height, 1, // no MSAA pixelDatatype, PixelFormat.RED, ); if (this._framebufferManager.framebuffer) { this._framebuffer = this._framebufferManager.framebuffer; this._idTexture = this._framebufferManager.getColorTexture(0); this._depthStencilTexture = this._framebufferManager.getDepthStencilTexture(); } return changed; }; /** * Returns a ClearCommand that targets this framebuffer. * * @param {Color} [clearColor] Override the clear color (default: transparent black). * @returns {ClearCommand} */ PlanarFillIdFramebuffer.prototype.getClearCommand = function (clearColor) { this._clearCommand.framebuffer = this._framebuffer; if (defined(clearColor)) { Color.clone(clearColor, this._clearCommand.color); } return this._clearCommand; }; /** * Releases GPU resources without destroying this object; a later call to * {@link PlanarFillIdFramebuffer#update} recreates them. */ PlanarFillIdFramebuffer.prototype.releaseResources = function () { if (!defined(this._framebuffer)) { return; } this._framebufferManager.destroy(); this._framebuffer = undefined; this._idTexture = undefined; this._depthStencilTexture = undefined; }; /** * @returns {boolean} */ PlanarFillIdFramebuffer.prototype.isDestroyed = function () { return false; }; /** * Destroys WebGL resources. */ PlanarFillIdFramebuffer.prototype.destroy = function () { this._framebufferManager = this._framebufferManager && this._framebufferManager.destroy(); this._clearCommand = undefined; return destroyObject(this); }; export default PlanarFillIdFramebuffer;