382 lines
11 KiB
JavaScript
382 lines
11 KiB
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;
|