Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix classification when terrain depth writes are enabled #7422

Merged
merged 16 commits into from
Dec 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of the changes in this function are just cleanup rather than bug fixes.


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