Skip to content

Commit

Permalink
Merge pull request #7422 from AnalyticalGraphicsInc/stencil-tricks
Browse files Browse the repository at this point in the history
Fix classification when terrain depth writes are enabled
  • Loading branch information
bagnell authored Dec 19, 2018
2 parents f9c2e2f + 33db32a commit 3dabb5c
Show file tree
Hide file tree
Showing 29 changed files with 1,646 additions and 833 deletions.
1 change: 0 additions & 1 deletion Apps/Sandcastle/gallery/Classification Types.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
var viewer = new Cesium.Viewer('cesiumContainer', {
terrainProvider: Cesium.createWorldTerrain()
});
viewer.scene.globe.depthTestAgainstTerrain = false;

var tileset = new Cesium.Cesium3DTileset({ url: Cesium.IonResource.fromAssetId(6074) });
viewer.scene.primitives.add(tileset);
Expand Down
6 changes: 6 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
Change Log
==========

### 1.45 - 2019-02-01

##### Fixes :wrench:
* Fixed an issue where classification primitives with the `CESIUM_3D_TILE` classification type would render on terrain. [#6568](https://github.com/AnalyticalGraphicsInc/cesium/issues/6568)
* Fixed an issue where 3D Tiles would show through the globe. [#6867](https://github.com/AnalyticalGraphicsInc/cesium/issues/6867)

### 1.53 - 2019-01-02

##### Fixes :wrench:
Expand Down
9 changes: 4 additions & 5 deletions Source/Renderer/Pass.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,10 @@ define([
CESIUM_3D_TILE : 4,
CESIUM_3D_TILE_CLASSIFICATION : 5,
CESIUM_3D_TILE_CLASSIFICATION_IGNORE_SHOW : 6,
CLASSIFICATION : 7,
OPAQUE : 8,
TRANSLUCENT : 9,
OVERLAY : 10,
NUMBER_OF_PASSES : 11
OPAQUE : 7,
TRANSLUCENT : 8,
OVERLAY : 9,
NUMBER_OF_PASSES : 10
};

return freezeObject(Pass);
Expand Down
92 changes: 62 additions & 30 deletions Source/Scene/Cesium3DTileBatchTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ define([
'./Cesium3DTileColorBlendMode',
'./CullFace',
'./getBinaryAccessor',
'./StencilConstants',
'./StencilFunction',
'./StencilOperation'
], function(
Expand Down Expand Up @@ -66,6 +67,7 @@ define([
Cesium3DTileColorBlendMode,
CullFace,
getBinaryAccessor,
StencilConstants,
StencilFunction,
StencilOperation) {
'use strict';
Expand Down Expand Up @@ -1261,30 +1263,42 @@ define([
derivedCommands.originalCommand = deriveCommand(command);
command.dirty = false;
}
var originalCommand = derivedCommands.originalCommand;

if (styleCommandsNeeded !== StyleCommandsNeeded.ALL_OPAQUE) {
if (styleCommandsNeeded !== StyleCommandsNeeded.ALL_OPAQUE && command.pass !== Pass.TRANSLUCENT) {
if (!defined(derivedCommands.translucent)) {
derivedCommands.translucent = deriveTranslucentCommand(derivedCommands.originalCommand);
derivedCommands.translucent = deriveTranslucentCommand(originalCommand);
}
}

if (bivariateVisibilityTest) {
if (command.pass !== Pass.TRANSLUCENT && !finalResolution) {
if (!defined(derivedCommands.zback)) {
derivedCommands.zback = deriveZBackfaceCommand(frameState.context, derivedCommands.originalCommand);
}
tileset._backfaceCommands.push(derivedCommands.zback);
if (styleCommandsNeeded !== StyleCommandsNeeded.ALL_TRANSLUCENT && command.pass !== Pass.TRANSLUCENT) {
if (!defined(derivedCommands.opaque)) {
derivedCommands.opaque = deriveOpaqueCommand(originalCommand);
}
if (!defined(derivedCommands.stencil) || tile._selectionDepth !== getLastSelectionDepth(derivedCommands.stencil)) {
derivedCommands.stencil = deriveStencilCommand(derivedCommands.originalCommand, tile._selectionDepth);

if (bivariateVisibilityTest) {
if (!finalResolution) {
if (!defined(derivedCommands.zback)) {
derivedCommands.zback = deriveZBackfaceCommand(frameState.context, originalCommand);
}
tileset._backfaceCommands.push(derivedCommands.zback);
}
if (!defined(derivedCommands.stencil) || (tile._selectionDepth !== getLastSelectionDepth(derivedCommands.stencil))) {
if (command.renderState.depthMask) {
derivedCommands.stencil = deriveStencilCommand(originalCommand, tile._selectionDepth);
} else {
// Ignore if tile does not write depth
derivedCommands.stencil = derivedCommands.opaque;
}
}
}
}

var opaqueCommand = bivariateVisibilityTest ? derivedCommands.stencil : derivedCommands.originalCommand;
var opaqueCommand = bivariateVisibilityTest ? derivedCommands.stencil : derivedCommands.opaque;
var translucentCommand = derivedCommands.translucent;

// If the command was originally opaque:
// * If the styling applied to the tile is all opaque, use the original command
// * If the styling applied to the tile is all opaque, use the opaque command
// (with one additional uniform needed for the shader).
// * If the styling is all translucent, use new (cached) derived commands (front
// and back faces) with a translucent render state.
Expand All @@ -1308,7 +1322,7 @@ define([
// as of now, a style can't change an originally translucent feature to
// opaque since the style's alpha is modulated, not a replacement. When
// this changes, we need to derive new opaque commands here.
commandList[i] = opaqueCommand;
commandList[i] = originalCommand;
}
}
};
Expand Down Expand Up @@ -1348,6 +1362,12 @@ define([
return derivedCommand;
}

function deriveOpaqueCommand(command) {
var derivedCommand = DrawCommand.shallowClone(command);
derivedCommand.renderState = getOpaqueRenderState(command.renderState);
return derivedCommand;
}

function getDisableLogDepthFragmentShaderProgram(context, shaderProgram) {
var shader = context.shaderCache.getDerivedShaderProgram(shaderProgram, 'zBackfaceLogDepth');
if (!defined(shader)) {
Expand Down Expand Up @@ -1385,6 +1405,10 @@ define([
factor : 5.0,
units : 5.0
};
// Set the 3D Tiles bit
rs.stencilTest = StencilConstants.setCesium3DTileBit();
rs.stencilMask = StencilConstants.CESIUM_3D_TILE_MASK;

derivedCommand.renderState = RenderState.fromCache(rs);
derivedCommand.castShadows = false;
derivedCommand.receiveShadows = false;
Expand All @@ -1395,27 +1419,27 @@ define([
}

function deriveStencilCommand(command, reference) {
var derivedCommand = command;
if (command.renderState.depthMask) { // ignore if tile does not write depth (ex. translucent)
// Tiles only draw if their selection depth is >= the tile drawn already. They write their
// selection depth to the stencil buffer to prevent ancestor tiles from drawing on top
derivedCommand = DrawCommand.shallowClone(command);
var rs = clone(derivedCommand.renderState, true);
// Stencil test is masked to the most significant 4 bits so the reference is shifted.
// This is to prevent clearing the stencil before classification which needs the least significant
// bits for increment/decrement operations.
rs.stencilTest.enabled = true;
rs.stencilTest.mask = 0xF0;
rs.stencilTest.reference = reference << 4;
rs.stencilTest.frontFunction = StencilFunction.GREATER_OR_EQUAL;
rs.stencilTest.frontOperation.zPass = StencilOperation.REPLACE;
derivedCommand.renderState = RenderState.fromCache(rs);
}
// Tiles only draw if their selection depth is >= the tile drawn already. They write their
// selection depth to the stencil buffer to prevent ancestor tiles from drawing on top
var derivedCommand = DrawCommand.shallowClone(command);
var rs = clone(derivedCommand.renderState, true);
// Stencil test is masked to the most significant 3 bits so the reference is shifted. Writes 0 for the terrain bit
rs.stencilTest.enabled = true;
rs.stencilTest.mask = StencilConstants.SKIP_LOD_MASK;
rs.stencilTest.reference = StencilConstants.CESIUM_3D_TILE_MASK | (reference << StencilConstants.SKIP_LOD_BIT_SHIFT);
rs.stencilTest.frontFunction = StencilFunction.GREATER_OR_EQUAL;
rs.stencilTest.frontOperation.zPass = StencilOperation.REPLACE;
rs.stencilTest.backFunction = StencilFunction.GREATER_OR_EQUAL;
rs.stencilTest.backOperation.zPass = StencilOperation.REPLACE;
rs.stencilMask = StencilConstants.CESIUM_3D_TILE_MASK | StencilConstants.SKIP_LOD_MASK;
derivedCommand.renderState = RenderState.fromCache(rs);
return derivedCommand;
}

function getLastSelectionDepth(stencilCommand) {
return stencilCommand.renderState.stencilTest.reference >>> 4;
// Isolate the selection depth from the stencil reference.
var reference = stencilCommand.renderState.stencilTest.reference;
return (reference & StencilConstants.SKIP_LOD_MASK) >>> StencilConstants.SKIP_LOD_BIT_SHIFT;
}

function getTranslucentRenderState(renderState) {
Expand All @@ -1428,6 +1452,14 @@ define([
return RenderState.fromCache(rs);
}

function getOpaqueRenderState(renderState) {
var rs = clone(renderState, true);
rs.stencilTest = StencilConstants.setCesium3DTileBit();
rs.stencilMask = StencilConstants.CESIUM_3D_TILE_MASK;

return RenderState.fromCache(rs);
}

///////////////////////////////////////////////////////////////////////////

function createTexture(batchTable, context, bytes) {
Expand Down
21 changes: 15 additions & 6 deletions Source/Scene/Cesium3DTileset.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ define([
'../Core/Transforms',
'../Renderer/ClearCommand',
'../Renderer/Pass',
'../Renderer/RenderState',
'../ThirdParty/when',
'./Axis',
'./Cesium3DTile',
Expand All @@ -40,6 +41,7 @@ define([
'./PointCloudShading',
'./SceneMode',
'./ShadowMode',
'./StencilConstants',
'./TileBoundingRegion',
'./TileBoundingSphere',
'./TileOrientedBoundingBox'
Expand Down Expand Up @@ -67,6 +69,7 @@ define([
Transforms,
ClearCommand,
Pass,
RenderState,
when,
Axis,
Cesium3DTile,
Expand All @@ -85,6 +88,7 @@ define([
PointCloudShading,
SceneMode,
ShadowMode,
StencilConstants,
TileBoundingRegion,
TileBoundingSphere,
TileOrientedBoundingBox) {
Expand Down Expand Up @@ -195,6 +199,7 @@ define([

this._hasMixedContent = false;

this._stencilClearCommand = undefined;
this._backfaceCommands = new ManagedArray();

this._maximumScreenSpaceError = defaultValue(options.maximumScreenSpaceError, 16);
Expand Down Expand Up @@ -1703,11 +1708,6 @@ define([
tileset._tileDebugLabels.update(frameState);
}

var stencilClearCommand = new ClearCommand({
stencil : 0,
pass : Pass.CESIUM_3D_TILE
});

function updateTiles(tileset, frameState) {
tileset._styleEngine.applyStyle(tileset, frameState);

Expand All @@ -1729,7 +1729,16 @@ define([
tileset._backfaceCommands.length = 0;

if (bivariateVisibilityTest) {
commandList.push(stencilClearCommand);
if (!defined(tileset._stencilClearCommand)) {
tileset._stencilClearCommand = new ClearCommand({
stencil : 0,
pass : Pass.CESIUM_3D_TILE,
renderState : RenderState.fromCache({
stencilMask : StencilConstants.SKIP_LOD_MASK
})
});
}
commandList.push(tileset._stencilClearCommand);
}

var lengthBeforeUpdate = commandList.length;
Expand Down
8 changes: 2 additions & 6 deletions Source/Scene/Cesium3DTilesetTraversal.js
Original file line number Diff line number Diff line change
Expand Up @@ -526,12 +526,8 @@ define([
* the children's z-depth and the ancestor's z-depth. We cannot rely on Z because we want the child to appear on top
* of ancestor regardless of true depth. The stencil tests used require children to be drawn first.
*
* NOTE: this will no longer work when there is a chain of selected tiles that is longer than the size of the
* stencil buffer (usually 8 bits). In other words, the subset of the tree containing only selected tiles must be
* no deeper than 255. It is very, very unlikely this will cause a problem.
*
* NOTE: when the scene has inverted classification enabled, the stencil buffer will be masked to 4 bits. So, the
* selected tiles must be no deeper than 15. This is still very unlikely.
* NOTE: 3D Tiles uses 3 bits from the stencil buffer meaning this will not work when there is a chain of
* selected tiles that is deeper than 7. This is not very likely.
*/
function traverseAndSelect(tileset, root, frameState) {
var stack = selectionTraversal.stack;
Expand Down
Loading

0 comments on commit 3dabb5c

Please sign in to comment.