cesium
Version:
CesiumJS is a JavaScript library for creating 3D globes and 2D maps in a web browser without a plugin.
348 lines (310 loc) • 14 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 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 TextureMagnificationFilter from '../Renderer/TextureMagnificationFilter.js';
import TextureMinificationFilter from '../Renderer/TextureMinificationFilter.js';
import TextureWrap from '../Renderer/TextureWrap.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.previousFramebuffer = undefined;
this._previousFramebuffer = undefined;
this._texture = undefined;
this._classifiedTexture = undefined;
this._depthStencilTexture = undefined;
this._fbo = undefined;
this._fboClassified = undefined;
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
});
var that = this;
this._uniformMap = {
colorTexture : function() {
return that._texture;
},
depthTexture : function() {
return that._depthStencilTexture;
},
classifiedTexture : function() {
return that._classifiedTexture;
}
};
}
Object.defineProperties(InvertClassification.prototype, {
unclassifiedCommand : {
get : function() {
return this._unclassifiedCommand;
}
}
});
InvertClassification.isTranslucencySupported = function(context) {
return context.depthTexture && context.fragmentDepth;
};
var 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
};
var 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.
var rsDefault = {
depthMask : true,
depthTest : {
enabled : true
},
stencilTest : StencilConstants.setCesium3DTileBit(),
stencilMask : StencilConstants.CESIUM_3D_TILE_MASK,
blending : BlendingState.ALPHA_BLEND
};
var translucentFS =
'#extension GL_EXT_frag_depth : enable\n'+
'uniform sampler2D colorTexture;\n' +
'uniform sampler2D depthTexture;\n' +
'uniform sampler2D classifiedTexture;\n' +
'varying vec2 v_textureCoordinates;\n' +
'void main()\n' +
'{\n' +
' vec4 color = texture2D(colorTexture, v_textureCoordinates);\n' +
' if (color.a == 0.0)\n' +
' {\n' +
' discard;\n' +
' }\n' +
' bool isClassified = all(equal(texture2D(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' +
' gl_FragColor = color * highlightColor;\n' +
' gl_FragDepthEXT = texture2D(depthTexture, v_textureCoordinates).r;\n' +
'}\n';
var opaqueFS =
'uniform sampler2D colorTexture;\n' +
'varying vec2 v_textureCoordinates;\n' +
'void main()\n' +
'{\n' +
' vec4 color = texture2D(colorTexture, v_textureCoordinates);\n' +
' if (color.a == 0.0)\n' +
' {\n' +
' discard;\n' +
' }\n' +
'#ifdef UNCLASSIFIED\n' +
' gl_FragColor = color * czm_invertClassificationColor;\n' +
'#else\n' +
' gl_FragColor = color;\n' +
'#endif\n' +
'}\n';
InvertClassification.prototype.update = function(context) {
var texture = this._texture;
var previousFramebufferChanged = !defined(texture) || this.previousFramebuffer !== this._previousFramebuffer;
this._previousFramebuffer = this.previousFramebuffer;
var width = context.drawingBufferWidth;
var height = context.drawingBufferHeight;
var textureChanged = !defined(texture) || texture.width !== width || texture.height !== height;
if (textureChanged || previousFramebufferChanged) {
this._texture = this._texture && this._texture.destroy();
this._classifiedTexture = this._classifiedTexture && this._classifiedTexture.destroy();
this._depthStencilTexture = this._depthStencilTexture && this._depthStencilTexture.destroy();
this._texture = new Texture({
context : context,
width : width,
height : height,
pixelFormat : PixelFormat.RGBA,
pixelDatatype : PixelDatatype.UNSIGNED_BYTE,
sampler : new Sampler({
wrapS : TextureWrap.CLAMP_TO_EDGE,
wrapT : TextureWrap.CLAMP_TO_EDGE,
minificationFilter : TextureMinificationFilter.LINEAR,
magnificationFilter : TextureMagnificationFilter.LINEAR
})
});
if (!defined(this._previousFramebuffer)) {
this._classifiedTexture = new Texture({
context : context,
width : width,
height : height,
pixelFormat : PixelFormat.RGBA,
pixelDatatype : PixelDatatype.UNSIGNED_BYTE,
sampler : new Sampler({
wrapS : TextureWrap.CLAMP_TO_EDGE,
wrapT : TextureWrap.CLAMP_TO_EDGE,
minificationFilter : TextureMinificationFilter.LINEAR,
magnificationFilter : TextureMagnificationFilter.LINEAR
})
});
this._depthStencilTexture = new Texture({
context : context,
width : width,
height : height,
pixelFormat : PixelFormat.DEPTH_STENCIL,
pixelDatatype : PixelDatatype.UNSIGNED_INT_24_8
});
}
}
if (!defined(this._fbo) || textureChanged || previousFramebufferChanged) {
this._fbo = this._fbo && this._fbo.destroy();
this._fboClassified = this._fboClassified && this._fboClassified.destroy();
var depthStencilTexture;
var depthStencilRenderbuffer;
if (defined(this._previousFramebuffer)) {
depthStencilTexture = this._previousFramebuffer.depthStencilTexture;
depthStencilRenderbuffer = this._previousFramebuffer.depthStencilRenderbuffer;
} else {
depthStencilTexture = this._depthStencilTexture;
}
this._fbo = new Framebuffer({
context : context,
colorTextures : [this._texture],
depthStencilTexture : depthStencilTexture,
depthStencilRenderbuffer : depthStencilRenderbuffer,
destroyAttachments : false
});
if (!defined(this._previousFramebuffer)) {
this._fboClassified = new Framebuffer({
context : context,
colorTextures : [this._classifiedTexture],
depthStencilTexture : depthStencilTexture,
destroyAttachments : false
});
}
}
if (!defined(this._rsUnclassified)) {
this._rsUnclassified = RenderState.fromCache(rsUnclassified);
this._rsClassified = RenderState.fromCache(rsClassified);
this._rsDefault = RenderState.fromCache(rsDefault);
}
if (!defined(this._unclassifiedCommand) || previousFramebufferChanged) {
if (defined(this._unclassifiedCommand)) {
this._unclassifiedCommand.shaderProgram = this._unclassifiedCommand.shaderProgram && this._unclassifiedCommand.shaderProgram.destroy();
this._classifiedCommand.shaderProgram = this._classifiedCommand.shaderProgram && this._classifiedCommand.shaderProgram.destroy();
}
var fs = defined(this._previousFramebuffer) ? opaqueFS : translucentFS;
var unclassifiedFSSource = new ShaderSource({
defines : ['UNCLASSIFIED'],
sources : [fs]
});
var 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.clear = function(context, passState) {
var framebuffer = passState.framebuffer;
if (defined(this._previousFramebuffer)) {
passState.framebuffer = this._fbo;
this._clearColorCommand.execute(context, passState);
} else {
passState.framebuffer = this._fbo;
this._clearCommand.execute(context, passState);
passState.framebuffer = this._fboClassified;
this._clearCommand.execute(context, passState);
}
passState.framebuffer = framebuffer;
};
InvertClassification.prototype.executeClassified = function(context, passState) {
if (!defined(this._previousFramebuffer)) {
var framebuffer = passState.framebuffer;
passState.framebuffer = this._fboClassified;
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 = this._fbo && this._fbo.destroy();
this._texture = this._texture && this._texture.destroy();
this._depthStencilTexture = this._depthStencilTexture && this._depthStencilTexture.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;