You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

588 lines
16 KiB
JavaScript

import BoundingRectangle from "../Core/BoundingRectangle.js";
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 DrawCommand from "../Renderer/DrawCommand.js";
import Framebuffer from "../Renderer/Framebuffer.js";
import Pass from "../Renderer/Pass.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 CompareAndPackTranslucentDepth from "../Shaders/CompareAndPackTranslucentDepth.js";
import CompositeTranslucentClassification from "../Shaders/PostProcessStages/CompositeTranslucentClassification.js";
import BlendingState from "./BlendingState.js";
import StencilConstants from "./StencilConstants.js";
import StencilFunction from "./StencilFunction.js";
var debugShowPackedDepth = false;
/**
* Handles buffers, drawing, and deriving commands needed for classifying translucent 3D Tiles.
* Uses a depth texture, so classification on translucent 3D Tiles is not available in Internet Explorer.
*
* @private
*/
function TranslucentTileClassification(context) {
this._drawClassificationFBO = undefined;
this._accumulationFBO = undefined;
this._packFBO = undefined;
this._opaqueDepthStencilTexture = undefined;
this._colorTexture = undefined;
this._accumulationTexture = undefined;
// Reference to either colorTexture or accumulationTexture
this._textureToComposite = undefined;
this._translucentDepthStencilTexture = undefined;
this._packedTranslucentDepth = undefined;
this._packDepthCommand = undefined;
this._accumulateCommand = undefined;
this._compositeCommand = undefined;
this._copyCommand = undefined;
this._clearColorCommand = new ClearCommand({
color: new Color(0.0, 0.0, 0.0, 0.0),
owner: this,
});
this._clearDepthStencilCommand = new ClearCommand({
depth: 1.0,
stencil: 0,
owner: this,
});
this._supported = context.depthTexture;
this._viewport = new BoundingRectangle();
this._rsDepth = undefined;
this._rsAccumulate = undefined;
this._rsComp = undefined;
this._useScissorTest = undefined;
this._scissorRectangle = undefined;
this._hasTranslucentDepth = false;
this._frustumsDrawn = 0;
}
Object.defineProperties(TranslucentTileClassification.prototype, {
/**
* Gets whether or not translucent depth was rendered.
* @memberof TranslucentTileClassification.prototype
*
* @type {Boolean}
* @readonly
*/
hasTranslucentDepth: {
get: function () {
return this._hasTranslucentDepth;
},
},
});
function destroyTextures(transpClass) {
transpClass._colorTexture =
transpClass._colorTexture &&
!transpClass._colorTexture.isDestroyed() &&
transpClass._colorTexture.destroy();
transpClass._accumulationTexture =
transpClass._accumulationTexture &&
!transpClass._accumulationTexture.isDestroyed() &&
transpClass._accumulationTexture.destroy();
transpClass._textureToComposite = undefined;
transpClass._translucentDepthStencilTexture =
transpClass._translucentDepthStencilTexture &&
!transpClass._translucentDepthStencilTexture.isDestroyed() &&
transpClass._translucentDepthStencilTexture.destroy();
transpClass._packedTranslucentDepth =
transpClass._packedTranslucentDepth &&
!transpClass._packedTranslucentDepth.isDestroyed() &&
transpClass._packedTranslucentDepth.destroy();
}
function destroyFramebuffers(transpClass) {
transpClass._drawClassificationFBO =
transpClass._drawClassificationFBO &&
!transpClass._drawClassificationFBO.isDestroyed() &&
transpClass._drawClassificationFBO.destroy();
transpClass._accumulationFBO =
transpClass._accumulationFBO &&
!transpClass._accumulationFBO.isDestroyed() &&
transpClass._accumulationFBO.destroy();
transpClass._packFBO =
transpClass._packFBO &&
!transpClass._packFBO.isDestroyed() &&
transpClass._packFBO.destroy();
}
function rgbaTexture(context, width, height) {
return new Texture({
context: context,
width: width,
height: height,
pixelFormat: PixelFormat.RGBA,
pixelDatatype: PixelDatatype.UNSIGNED_BYTE,
sampler: Sampler.NEAREST,
});
}
function updateTextures(transpClass, context, width, height) {
destroyTextures(transpClass);
transpClass._colorTexture = rgbaTexture(context, width, height);
transpClass._accumulationTexture = rgbaTexture(context, width, height);
transpClass._translucentDepthStencilTexture = new Texture({
context: context,
width: width,
height: height,
pixelFormat: PixelFormat.DEPTH_STENCIL,
pixelDatatype: PixelDatatype.UNSIGNED_INT_24_8,
sampler: Sampler.NEAREST,
});
transpClass._packedTranslucentDepth = new Texture({
context: context,
width: width,
height: height,
pixelFormat: PixelFormat.RGBA,
pixelDatatype: PixelDatatype.UNSIGNED_BYTE,
sampler: Sampler.NEAREST,
});
}
function updateFramebuffers(transpClass, context) {
destroyFramebuffers(transpClass);
transpClass._drawClassificationFBO = new Framebuffer({
context: context,
colorTextures: [transpClass._colorTexture],
depthStencilTexture: transpClass._translucentDepthStencilTexture,
destroyAttachments: false,
});
transpClass._accumulationFBO = new Framebuffer({
context: context,
colorTextures: [transpClass._accumulationTexture],
depthStencilTexture: transpClass._translucentDepthStencilTexture,
destroyAttachments: false,
});
transpClass._packFBO = new Framebuffer({
context: context,
colorTextures: [transpClass._packedTranslucentDepth],
destroyAttachments: false,
});
}
function updateResources(
transpClass,
context,
passState,
globeDepthFramebuffer
) {
if (!transpClass.isSupported()) {
return;
}
transpClass._opaqueDepthStencilTexture =
globeDepthFramebuffer.depthStencilTexture;
var width = transpClass._opaqueDepthStencilTexture.width;
var height = transpClass._opaqueDepthStencilTexture.height;
var colorTexture = transpClass._colorTexture;
var textureChanged =
!defined(colorTexture) ||
colorTexture.width !== width ||
colorTexture.height !== height;
if (textureChanged) {
updateTextures(transpClass, context, width, height);
}
if (!defined(transpClass._drawClassificationFBO) || textureChanged) {
updateFramebuffers(transpClass, context);
}
var fs;
var uniformMap;
if (!defined(transpClass._packDepthCommand)) {
fs = new ShaderSource({
sources: [CompareAndPackTranslucentDepth],
});
uniformMap = {
u_opaqueDepthTexture: function () {
return transpClass._opaqueDepthStencilTexture;
},
u_translucentDepthTexture: function () {
return transpClass._translucentDepthStencilTexture;
},
};
transpClass._packDepthCommand = context.createViewportQuadCommand(fs, {
uniformMap: uniformMap,
owner: transpClass,
});
}
if (!defined(transpClass._compositeCommand)) {
fs = new ShaderSource({
sources: [CompositeTranslucentClassification],
});
uniformMap = {
colorTexture: function () {
return transpClass._textureToComposite;
},
};
if (debugShowPackedDepth) {
fs.defines = ["DEBUG_SHOW_DEPTH"];
uniformMap.u_packedTranslucentDepth = function () {
return transpClass._packedTranslucentDepth;
};
}
transpClass._compositeCommand = context.createViewportQuadCommand(fs, {
uniformMap: uniformMap,
owner: transpClass,
});
var compositeCommand = transpClass._compositeCommand;
var compositeProgram = compositeCommand.shaderProgram;
var compositePickProgram = context.shaderCache.createDerivedShaderProgram(
compositeProgram,
"pick",
{
vertexShaderSource: compositeProgram.vertexShaderSource,
fragmentShaderSource: new ShaderSource({
sources: fs.sources,
defines: ["PICK"],
}),
attributeLocations: compositeProgram._attributeLocations,
}
);
var compositePickCommand = DrawCommand.shallowClone(compositeCommand);
compositePickCommand.shaderProgram = compositePickProgram;
compositeCommand.derivedCommands.pick = compositePickCommand;
}
if (!defined(transpClass._copyCommand)) {
fs = new ShaderSource({
sources: [CompositeTranslucentClassification],
});
uniformMap = {
colorTexture: function () {
return transpClass._colorTexture;
},
};
transpClass._copyCommand = context.createViewportQuadCommand(fs, {
uniformMap: uniformMap,
owner: transpClass,
});
}
if (!defined(transpClass._accumulateCommand)) {
fs = new ShaderSource({
sources: [CompositeTranslucentClassification],
});
uniformMap = {
colorTexture: function () {
return transpClass._colorTexture;
},
};
transpClass._accumulateCommand = context.createViewportQuadCommand(fs, {
uniformMap: uniformMap,
owner: transpClass,
});
}
transpClass._viewport.width = width;
transpClass._viewport.height = height;
var useScissorTest = !BoundingRectangle.equals(
transpClass._viewport,
passState.viewport
);
var updateScissor = useScissorTest !== transpClass._useScissorTest;
transpClass._useScissorTest = useScissorTest;
if (
!BoundingRectangle.equals(transpClass._scissorRectangle, passState.viewport)
) {
transpClass._scissorRectangle = BoundingRectangle.clone(
passState.viewport,
transpClass._scissorRectangle
);
updateScissor = true;
}
if (
!defined(transpClass._rsDepth) ||
!BoundingRectangle.equals(
transpClass._viewport,
transpClass._rsDepth.viewport
) ||
updateScissor
) {
transpClass._rsDepth = RenderState.fromCache({
viewport: transpClass._viewport,
scissorTest: {
enabled: transpClass._useScissorTest,
rectangle: transpClass._scissorRectangle,
},
});
}
if (defined(transpClass._packDepthCommand)) {
transpClass._packDepthCommand.renderState = transpClass._rsDepth;
}
if (
!defined(transpClass._rsAccumulate) ||
!BoundingRectangle.equals(
transpClass._viewport,
transpClass._rsAccumulate.viewport
) ||
updateScissor
) {
transpClass._rsAccumulate = RenderState.fromCache({
viewport: transpClass._viewport,
scissorTest: {
enabled: transpClass._useScissorTest,
rectangle: transpClass._scissorRectangle,
},
stencilTest: {
enabled: true,
frontFunction: StencilFunction.EQUAL,
reference: StencilConstants.CESIUM_3D_TILE_MASK,
},
});
}
if (defined(transpClass._accumulateCommand)) {
transpClass._accumulateCommand.renderState = transpClass._rsAccumulate;
}
if (
!defined(transpClass._rsComp) ||
!BoundingRectangle.equals(
transpClass._viewport,
transpClass._rsComp.viewport
) ||
updateScissor
) {
transpClass._rsComp = RenderState.fromCache({
viewport: transpClass._viewport,
scissorTest: {
enabled: transpClass._useScissorTest,
rectangle: transpClass._scissorRectangle,
},
blending: BlendingState.ALPHA_BLEND,
});
}
if (defined(transpClass._compositeCommand)) {
transpClass._compositeCommand.renderState = transpClass._rsComp;
transpClass._compositeCommand.derivedCommands.pick.renderState =
transpClass._rsComp;
}
}
TranslucentTileClassification.prototype.executeTranslucentCommands = function (
scene,
executeCommand,
passState,
commands,
globeDepthFramebuffer
) {
// Check for translucent commands that should be classified
var length = commands.length;
var command;
var i;
var useLogDepth = scene.frameState.useLogDepth;
var context = scene.context;
var framebuffer = passState.framebuffer;
for (i = 0; i < length; ++i) {
command = commands[i];
command = useLogDepth ? command.derivedCommands.logDepth.command : command;
if (command.depthForTranslucentClassification) {
this._hasTranslucentDepth = true;
break;
}
}
if (!this._hasTranslucentDepth) {
return;
}
updateResources(this, context, passState, globeDepthFramebuffer);
// Get translucent depth
passState.framebuffer = this._drawClassificationFBO;
// Clear depth for multifrustum
this._clearDepthStencilCommand.execute(context, passState);
for (i = 0; i < length; ++i) {
command = commands[i];
command = useLogDepth ? command.derivedCommands.logDepth.command : command;
if (!command.depthForTranslucentClassification) {
continue;
}
// Depth-only commands are created for all translucent 3D Tiles commands
var depthOnlyCommand = command.derivedCommands.depth.depthOnlyCommand;
executeCommand(depthOnlyCommand, scene, context, passState);
}
this._frustumsDrawn += this._hasTranslucentDepth ? 1 : 0;
// Pack depth if any translucent depth commands were performed
if (this._hasTranslucentDepth) {
passState.framebuffer = this._packFBO;
this._packDepthCommand.execute(context, passState);
}
passState.framebuffer = framebuffer;
};
TranslucentTileClassification.prototype.executeClassificationCommands = function (
scene,
executeCommand,
passState,
frustumCommands
) {
if (!this._hasTranslucentDepth) {
return;
}
var context = scene.context;
var us = context.uniformState;
var framebuffer = passState.framebuffer;
if (this._frustumsDrawn === 2) {
// copy classification from first frustum
passState.framebuffer = this._accumulationFBO;
this._copyCommand.execute(context, passState);
}
passState.framebuffer = this._drawClassificationFBO;
if (this._frustumsDrawn > 1) {
this._clearColorCommand.execute(context, passState);
}
us.updatePass(Pass.CESIUM_3D_TILE_CLASSIFICATION);
var swapGlobeDepth = us.globeDepthTexture;
us.globeDepthTexture = this._packedTranslucentDepth;
var commands = frustumCommands.commands[Pass.CESIUM_3D_TILE_CLASSIFICATION];
var length = frustumCommands.indices[Pass.CESIUM_3D_TILE_CLASSIFICATION];
for (var i = 0; i < length; ++i) {
executeCommand(commands[i], scene, context, passState);
}
us.globeDepthTexture = swapGlobeDepth;
passState.framebuffer = framebuffer;
if (this._frustumsDrawn === 1) {
return;
}
passState.framebuffer = this._accumulationFBO;
this._accumulateCommand.execute(context, passState);
passState.framebuffer = framebuffer;
};
TranslucentTileClassification.prototype.execute = function (scene, passState) {
if (!this._hasTranslucentDepth) {
return;
}
if (this._frustumsDrawn === 1) {
this._textureToComposite = this._colorTexture;
} else {
this._textureToComposite = this._accumulationTexture;
}
var command = scene.frameState.passes.pick
? this._compositeCommand.derivedCommands.pick
: this._compositeCommand;
command.execute(scene.context, passState);
clear(this, scene, passState);
};
function clear(translucentTileClassification, scene, passState) {
if (!translucentTileClassification._hasTranslucentDepth) {
return;
}
var framebuffer = passState.framebuffer;
passState.framebuffer = translucentTileClassification._drawClassificationFBO;
translucentTileClassification._clearColorCommand.execute(
scene._context,
passState
);
passState.framebuffer = framebuffer;
if (translucentTileClassification._frustumsDrawn > 1) {
passState.framebuffer = translucentTileClassification._accumulationFBO;
translucentTileClassification._clearColorCommand.execute(
scene._context,
passState
);
}
translucentTileClassification._hasTranslucentDepth = false;
translucentTileClassification._frustumsDrawn = 0;
}
TranslucentTileClassification.prototype.isSupported = function () {
return this._supported;
};
TranslucentTileClassification.prototype.isDestroyed = function () {
return false;
};
TranslucentTileClassification.prototype.destroy = function () {
destroyTextures(this);
destroyFramebuffers(this);
if (defined(this._compositeCommand)) {
this._compositeCommand.shaderProgram =
this._compositeCommand.shaderProgram &&
this._compositeCommand.shaderProgram.destroy();
}
if (defined(this._packDepthCommand)) {
this._packDepthCommand.shaderProgram =
this._packDepthCommand.shaderProgram &&
this._packDepthCommand.shaderProgram.destroy();
}
return destroyObject(this);
};
export default TranslucentTileClassification;