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;
|