173 lines
4.9 KiB
JavaScript
173 lines
4.9 KiB
JavaScript
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
|
||
* <code>behind: true</code> (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} <code>true</code> 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;
|