@cesium/engine
Version:
CesiumJS is a JavaScript library for creating 3D globes and 2D maps in a web browser without a plugin.
382 lines (346 loc) • 11.6 kB
JavaScript
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 FramebufferManager from "../Renderer/FramebufferManager.js";
import PixelDatatype from "../Renderer/PixelDatatype.js";
import Renderbuffer from "../Renderer/Renderbuffer.js";
import RenderbufferFormat from "../Renderer/RenderbufferFormat.js";
import RenderState from "../Renderer/RenderState.js";
import ShaderSource from "../Renderer/ShaderSource.js";
import Texture from "../Renderer/Texture.js";
import PassThrough from "../Shaders/PostProcessStages/PassThrough.js";
import BlendingState from "./BlendingState.js";
import StencilConstants from "./StencilConstants.js";
import StencilFunction from "./StencilFunction.js";
import StencilOperation from "./StencilOperation.js";
/**
* @private
*/
function InvertClassification() {
this._numSamples = 1;
this.previousFramebuffer = undefined;
this._previousFramebuffer = undefined;
this._depthStencilTexture = undefined;
this._depthStencilRenderbuffer = undefined;
this._fbo = new FramebufferManager({
depthStencil: true,
createDepthAttachments: false,
});
this._fboClassified = new FramebufferManager({
depthStencil: true,
createDepthAttachments: false,
});
this._rsUnclassified = undefined;
this._rsClassified = undefined;
this._unclassifiedCommand = undefined;
this._classifiedCommand = undefined;
this._translucentCommand = undefined;
this._clearColorCommand = new ClearCommand({
color: new Color(0.0, 0.0, 0.0, 0.0),
owner: this,
});
this._clearCommand = new ClearCommand({
color: new Color(0.0, 0.0, 0.0, 0.0),
depth: 1.0,
stencil: 0,
});
const that = this;
this._uniformMap = {
colorTexture: function () {
return that._fbo.getColorTexture();
},
depthTexture: function () {
return that._depthStencilTexture;
},
classifiedTexture: function () {
return that._fboClassified.getColorTexture();
},
};
}
Object.defineProperties(InvertClassification.prototype, {
unclassifiedCommand: {
get: function () {
return this._unclassifiedCommand;
},
},
});
InvertClassification.isTranslucencySupported = function (context) {
return context.depthTexture && context.fragmentDepth;
};
const rsUnclassified = {
depthMask: false,
stencilTest: {
enabled: true,
frontFunction: StencilFunction.EQUAL,
frontOperation: {
fail: StencilOperation.KEEP,
zFail: StencilOperation.KEEP,
zPass: StencilOperation.KEEP,
},
backFunction: StencilFunction.NEVER,
reference: 0,
mask: StencilConstants.CLASSIFICATION_MASK,
},
blending: BlendingState.ALPHA_BLEND,
};
const rsClassified = {
depthMask: false,
stencilTest: {
enabled: true,
frontFunction: StencilFunction.NOT_EQUAL,
frontOperation: {
fail: StencilOperation.KEEP,
zFail: StencilOperation.KEEP,
zPass: StencilOperation.KEEP,
},
backFunction: StencilFunction.NEVER,
reference: 0,
mask: StencilConstants.CLASSIFICATION_MASK,
},
blending: BlendingState.ALPHA_BLEND,
};
// Set the 3D Tiles bit when rendering back into the scene's framebuffer. This is only needed if
// invert classification does not use the scene's depth-stencil texture, which is the case if the invert
// classification color is translucent.
const rsDefault = {
depthMask: true,
depthTest: {
enabled: true,
},
stencilTest: StencilConstants.setCesium3DTileBit(),
stencilMask: StencilConstants.CESIUM_3D_TILE_MASK,
blending: BlendingState.ALPHA_BLEND,
};
const translucentFS =
"uniform sampler2D colorTexture;\n" +
"uniform sampler2D depthTexture;\n" +
"uniform sampler2D classifiedTexture;\n" +
"in vec2 v_textureCoordinates;\n" +
"void main()\n" +
"{\n" +
" vec4 color = texture(colorTexture, v_textureCoordinates);\n" +
" if (color.a == 0.0)\n" +
" {\n" +
" discard;\n" +
" }\n" +
" bool isClassified = all(equal(texture(classifiedTexture, v_textureCoordinates), vec4(0.0)));\n" +
"#ifdef UNCLASSIFIED\n" +
" vec4 highlightColor = czm_invertClassificationColor;\n" +
" if (isClassified)\n" +
" {\n" +
" discard;\n" +
" }\n" +
"#else\n" +
" vec4 highlightColor = vec4(1.0);\n" +
" if (!isClassified)\n" +
" {\n" +
" discard;\n" +
" }\n" +
"#endif\n" +
" out_FragColor = color * highlightColor;\n" +
" gl_FragDepth = texture(depthTexture, v_textureCoordinates).r;\n" +
"}\n";
const opaqueFS =
"uniform sampler2D colorTexture;\n" +
"in vec2 v_textureCoordinates;\n" +
"void main()\n" +
"{\n" +
" vec4 color = texture(colorTexture, v_textureCoordinates);\n" +
" if (color.a == 0.0)\n" +
" {\n" +
" discard;\n" +
" }\n" +
"#ifdef UNCLASSIFIED\n" +
" out_FragColor = color * czm_invertClassificationColor;\n" +
"#else\n" +
" out_FragColor = color;\n" +
"#endif\n" +
"}\n";
InvertClassification.prototype.update = function (
context,
numSamples,
globeFramebuffer,
) {
const texture = this._fbo.getColorTexture();
const previousFramebufferChanged =
this.previousFramebuffer !== this._previousFramebuffer;
this._previousFramebuffer = this.previousFramebuffer;
const samplesChanged = this._numSamples !== numSamples;
const width = context.drawingBufferWidth;
const height = context.drawingBufferHeight;
const textureChanged =
!defined(texture) || texture.width !== width || texture.height !== height;
if (textureChanged || previousFramebufferChanged || samplesChanged) {
this._numSamples = numSamples;
this._depthStencilTexture =
this._depthStencilTexture && this._depthStencilTexture.destroy();
this._depthStencilRenderbuffer =
this._depthStencilRenderbuffer &&
this._depthStencilRenderbuffer.destroy();
if (!defined(this._previousFramebuffer)) {
this._depthStencilTexture = new Texture({
context: context,
width: width,
height: height,
pixelFormat: PixelFormat.DEPTH_STENCIL,
pixelDatatype: PixelDatatype.UNSIGNED_INT_24_8,
});
if (numSamples > 1) {
this._depthStencilRenderbuffer = new Renderbuffer({
context: context,
width: width,
height: height,
format: RenderbufferFormat.DEPTH24_STENCIL8,
numSamples: numSamples,
});
}
}
}
if (
!defined(this._fbo.framebuffer) ||
textureChanged ||
previousFramebufferChanged ||
samplesChanged
) {
this._fbo.destroy();
this._fboClassified.destroy();
let depthStencilTexture;
let depthStencilRenderbuffer;
if (defined(this._previousFramebuffer)) {
depthStencilTexture = globeFramebuffer.getDepthStencilTexture();
depthStencilRenderbuffer = globeFramebuffer.getDepthStencilRenderbuffer();
} else {
depthStencilTexture = this._depthStencilTexture;
depthStencilRenderbuffer = this._depthStencilRenderbuffer;
}
this._fbo.setDepthStencilTexture(depthStencilTexture);
if (defined(depthStencilRenderbuffer)) {
this._fbo.setDepthStencilRenderbuffer(depthStencilRenderbuffer);
}
this._fbo.update(context, width, height, numSamples);
if (!defined(this._previousFramebuffer)) {
this._fboClassified.setDepthStencilTexture(depthStencilTexture);
this._fboClassified.update(context, width, height);
}
}
if (!defined(this._rsUnclassified)) {
this._rsUnclassified = RenderState.fromCache(rsUnclassified);
this._rsClassified = RenderState.fromCache(rsClassified);
this._rsDefault = RenderState.fromCache(rsDefault);
}
if (
!defined(this._unclassifiedCommand) ||
previousFramebufferChanged ||
samplesChanged
) {
if (defined(this._unclassifiedCommand)) {
this._unclassifiedCommand.shaderProgram =
this._unclassifiedCommand.shaderProgram &&
this._unclassifiedCommand.shaderProgram.destroy();
this._classifiedCommand.shaderProgram =
this._classifiedCommand.shaderProgram &&
this._classifiedCommand.shaderProgram.destroy();
}
const fs = defined(this._previousFramebuffer) ? opaqueFS : translucentFS;
const unclassifiedFSSource = new ShaderSource({
defines: ["UNCLASSIFIED"],
sources: [fs],
});
const classifiedFSSource = new ShaderSource({
sources: [fs],
});
this._unclassifiedCommand = context.createViewportQuadCommand(
unclassifiedFSSource,
{
renderState: defined(this._previousFramebuffer)
? this._rsUnclassified
: this._rsDefault,
uniformMap: this._uniformMap,
owner: this,
},
);
this._classifiedCommand = context.createViewportQuadCommand(
classifiedFSSource,
{
renderState: defined(this._previousFramebuffer)
? this._rsClassified
: this._rsDefault,
uniformMap: this._uniformMap,
owner: this,
},
);
if (defined(this._translucentCommand)) {
this._translucentCommand.shaderProgram =
this._translucentCommand.shaderProgram &&
this._translucentCommand.shaderProgram.destroy();
}
if (!defined(this._previousFramebuffer)) {
this._translucentCommand = context.createViewportQuadCommand(
PassThrough,
{
renderState: this._rsUnclassified,
uniformMap: this._uniformMap,
owner: this,
},
);
}
}
};
InvertClassification.prototype.prepareTextures = function (
context,
blitStencil,
) {
if (this._fbo._numSamples > 1) {
this._fbo.prepareTextures(context, blitStencil);
}
};
InvertClassification.prototype.clear = function (context, passState) {
if (defined(this._previousFramebuffer)) {
this._fbo.clear(context, this._clearColorCommand, passState);
} else {
this._fbo.clear(context, this._clearCommand, passState);
this._fboClassified.clear(context, this._clearCommand, passState);
}
};
InvertClassification.prototype.executeClassified = function (
context,
passState,
) {
if (!defined(this._previousFramebuffer)) {
const framebuffer = passState.framebuffer;
this.prepareTextures(context, true);
passState.framebuffer = this._fboClassified.framebuffer;
this._translucentCommand.execute(context, passState);
passState.framebuffer = framebuffer;
}
this._classifiedCommand.execute(context, passState);
};
InvertClassification.prototype.executeUnclassified = function (
context,
passState,
) {
this._unclassifiedCommand.execute(context, passState);
};
InvertClassification.prototype.isDestroyed = function () {
return false;
};
InvertClassification.prototype.destroy = function () {
this._fbo.destroy();
this._fboClassified.destroy();
this._depthStencilTexture =
this._depthStencilTexture && this._depthStencilTexture.destroy();
this._depthStencilRenderbuffer =
this._depthStencilRenderbuffer && this._depthStencilRenderbuffer.destroy();
if (defined(this._unclassifiedCommand)) {
this._unclassifiedCommand.shaderProgram =
this._unclassifiedCommand.shaderProgram &&
this._unclassifiedCommand.shaderProgram.destroy();
this._classifiedCommand.shaderProgram =
this._classifiedCommand.shaderProgram &&
this._classifiedCommand.shaderProgram.destroy();
}
return destroyObject(this);
};
export default InvertClassification;