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

Invert classification #5836

Merged
merged 21 commits into from
Oct 19, 2017
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
299 changes: 169 additions & 130 deletions Apps/Sandcastle/gallery/Classification.html

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Change Log
* Added function that inserts missing namespace declarations into KML files. [#5860](https://github.com/AnalyticalGraphicsInc/cesium/pull/5860)
* Added support for the layer.json `parentUrl` property in `CesiumTerrainProvider` to allow for compositing of tilesets.
* Fixed a bug that caused KML ground overlays to appear distorted when rotation was applied. [#5914](https://github.com/AnalyticalGraphicsInc/cesium/issues/5914)
* Adds `invertClassification` and `invertClassificationColor` to `Scene`. When `invertClassification` is `true`, any 3D Tiles geometry that is not classified by a `ClassificationPrimitive` or `GroundPrimitive` will have its color multiplied by `invertClassificationColor`. [#5836](https://github.com/AnalyticalGraphicsInc/cesium/pull/5836)

### 1.38 - 2017-10-02

Expand Down
14 changes: 14 additions & 0 deletions Source/Renderer/AutomaticUniforms.js
Original file line number Diff line number Diff line change
Expand Up @@ -1588,6 +1588,20 @@ define([
getValue : function(uniformState) {
return uniformState.minimumDisableDepthTestDistance;
}
}),

/**
* An automatic GLSL uniform that will be the highlight color of unclassified 3D Tiles.
*
* @alias czm_invertClassificationColor
* @glslUniform
*/
czm_invertClassificationColor : new AutomaticUniform({
size : 1,
datatype : WebGLConstants.FLOAT_VEC4,
getValue : function(uniformState) {
return uniformState.invertClassificationColor;
}
})
};

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

return freezeObject(Pass);
Expand Down
16 changes: 16 additions & 0 deletions Source/Renderer/UniformState.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ define([

this._fogDensity = undefined;

this._invertClassificationColor = undefined;

this._imagerySplitPosition = 0.0;
this._pixelSizePerMeter = undefined;
this._geometricToleranceOverMeter = undefined;
Expand Down Expand Up @@ -847,6 +849,18 @@ define([
get : function() {
return this._minimumDisableDepthTestDistance;
}
},

/**
* The highlight color of unclassified 3D Tiles.
*
* @memberof UniformState.prototype
* @type {Color}
*/
invertClassificationColor : {
get : function() {
return this._invertClassificationColor;
}
}
});

Expand Down Expand Up @@ -1012,6 +1026,8 @@ define([

this._fogDensity = frameState.fog.density;

this._invertClassificationColor = frameState.invertClassificationColor;

this._frameState = frameState;
this._temeToPseudoFixed = Transforms.computeTemeToPseudoFixedMatrix(frameState.time, this._temeToPseudoFixed);

Expand Down
6 changes: 5 additions & 1 deletion Source/Scene/Cesium3DTileBatchTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -1342,8 +1342,12 @@ define([
// 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.
Copy link
Contributor

Choose a reason for hiding this comment

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

For my knowledge, remind me what limitation the 4 bits creates, e.g., can't have more than 16 tilesets in the same pixel?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

See this comment when traversing 3D Tiles with the skip LOD optimization: https://github.com/AnalyticalGraphicsInc/cesium/blob/master/Source/Scene/Cesium3DTilesetTraversal.js#L167

Instead of a depth of 255, the depth would be limited to 15.

Copy link
Contributor

Choose a reason for hiding this comment

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

An unlikely, but potentially possible case now, right? But this is limited to just classification?

At the least, please add appropriate comments if you haven't already in case we need to investigate this in the future.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's still very unlikely the selection depth will reach 15. I'll add a comment.

// 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.reference = reference;
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);
Expand Down
2 changes: 1 addition & 1 deletion Source/Scene/Cesium3DTileset.js
Original file line number Diff line number Diff line change
Expand Up @@ -1495,7 +1495,7 @@ define([
var addedCommandsLength = (lengthAfterUpdate - lengthBeforeUpdate);
var backfaceCommandsLength = backfaceCommands.length;

commandList.length += backfaceCommands.length;
commandList.length += backfaceCommandsLength;

// copy commands to the back of the commandList
for (i = addedCommandsLength - 1; i >= 0; --i) {
Expand Down
3 changes: 3 additions & 0 deletions Source/Scene/Cesium3DTilesetTraversal.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,9 @@ define([
* 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.
*/
function traverseAndSelect(tileset, root, frameState) {
var stack = scratchStack;
Expand Down
95 changes: 77 additions & 18 deletions Source/Scene/ClassificationPrimitive.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,13 +164,16 @@ define([
this._uniformMap = options._uniformMap;

this._sp = undefined;
this._spStencil = undefined;
this._spPick = undefined;

this._rsStencilPreloadPass = undefined;
this._rsStencilDepthPass = undefined;
this._rsColorPass = undefined;
this._rsPickPass = undefined;

this._commandsIgnoreShow = [];

this._ready = false;
this._readyPromise = when.defer();

Expand Down Expand Up @@ -344,6 +347,12 @@ define([
return scene.context.stencilBuffer;
};

// The stencil mask only uses the least significant 4 bits.
// This is so 3D Tiles with the skip LOD optimization, which uses the most significant 4 bits,
// can be classified.
var stencilMask = 0x0F;
var stencilReference = 0;

function getStencilPreloadRenderState(enableStencil) {
return {
colorMask : {
Expand All @@ -366,8 +375,8 @@ define([
zFail : StencilOperation.INCREMENT_WRAP,
zPass : StencilOperation.INCREMENT_WRAP
},
reference : 0,
mask : ~0
reference : stencilReference,
mask : stencilMask
},
depthTest : {
enabled : false
Expand Down Expand Up @@ -398,8 +407,8 @@ define([
zFail : StencilOperation.KEEP,
zPass : StencilOperation.DECREMENT_WRAP
},
reference : 0,
mask : ~0
reference : stencilReference,
mask : stencilMask
},
depthTest : {
enabled : true,
Expand All @@ -426,8 +435,8 @@ define([
zFail : StencilOperation.KEEP,
zPass : StencilOperation.DECREMENT_WRAP
},
reference : 0,
mask : ~0
reference : stencilReference,
mask : stencilMask
},
depthTest : {
enabled : false
Expand All @@ -452,8 +461,8 @@ define([
zFail : StencilOperation.KEEP,
zPass : StencilOperation.DECREMENT_WRAP
},
reference : 0,
mask : ~0
reference : stencilReference,
mask : stencilMask
},
depthTest : {
enabled : false
Expand Down Expand Up @@ -510,7 +519,6 @@ define([
var primitive = classificationPrimitive._primitive;
var vs = ShadowVolumeVS;
vs = classificationPrimitive._primitive._batchTable.getVertexShaderCallback()(vs);
vs = Primitive._appendShowToShader(primitive, vs);
vs = Primitive._appendDistanceDisplayConditionToShader(primitive, vs);
vs = Primitive._modifyShaderPosition(classificationPrimitive, vs, frameState.scene3DOnly);
vs = Primitive._updateColorAttribute(primitive, vs);
Expand All @@ -530,9 +538,9 @@ define([
});
var attributeLocations = classificationPrimitive._primitive._attributeLocations;

classificationPrimitive._sp = ShaderProgram.replaceCache({
classificationPrimitive._spStencil = ShaderProgram.replaceCache({
context : context,
shaderProgram : classificationPrimitive._sp,
shaderProgram : classificationPrimitive._spStencil,
vertexShaderSource : vsSource,
fragmentShaderSource : fsSource,
attributeLocations : attributeLocations
Expand Down Expand Up @@ -567,6 +575,20 @@ define([
attributeLocations : attributeLocations
});
}

vs = Primitive._appendShowToShader(primitive, vs);
vsSource = new ShaderSource({
defines : [extrudedDefine],
sources : [vs]
});

classificationPrimitive._sp = ShaderProgram.replaceCache({
context : context,
shaderProgram : classificationPrimitive._sp,
vertexShaderSource : vsSource,
fragmentShaderSource : fsSource,
attributeLocations : attributeLocations
});
}

function createColorCommands(classificationPrimitive, colorCommands) {
Expand Down Expand Up @@ -632,6 +654,24 @@ define([
command = colorCommands[length + i] = DrawCommand.shallowClone(colorCommands[i], colorCommands[length + i]);
command.pass = Pass.CESIUM_3D_TILE_CLASSIFICATION;
}

var commandsIgnoreShow = classificationPrimitive._commandsIgnoreShow;
var spStencil = classificationPrimitive._spStencil;

var commandIndex = 0;
length = commandsIgnoreShow.length = length / 3 * 2;

for (var j = 0; j < length; j += 2) {
var commandIgnoreShow = commandsIgnoreShow[j] = DrawCommand.shallowClone(colorCommands[commandIndex], commandsIgnoreShow[j]);
commandIgnoreShow.shaderProgram = spStencil;
commandIgnoreShow.pass = Pass.CESIUM_3D_TILE_CLASSIFICATION_IGNORE_SHOW;

commandIgnoreShow = commandsIgnoreShow[j + 1] = DrawCommand.shallowClone(colorCommands[commandIndex + 1], commandsIgnoreShow[j + 1]);
commandIgnoreShow.shaderProgram = spStencil;
commandIgnoreShow.pass = Pass.CESIUM_3D_TILE_CLASSIFICATION_IGNORE_SHOW;

commandIndex += 3;
}
}

function createPickCommands(classificationPrimitive, pickCommands) {
Expand Down Expand Up @@ -665,7 +705,7 @@ define([
command.offset = offset;
command.count = count;
command.renderState = classificationPrimitive._rsStencilPreloadPass;
command.shaderProgram = classificationPrimitive._sp;
command.shaderProgram = classificationPrimitive._spStencil;
command.uniformMap = uniformMap;
command.pass = Pass.TERRAIN_CLASSIFICATION;

Expand All @@ -682,7 +722,7 @@ define([
command.offset = offset;
command.count = count;
command.renderState = classificationPrimitive._rsStencilDepthPass;
command.shaderProgram = classificationPrimitive._sp;
command.shaderProgram = classificationPrimitive._spStencil;
command.uniformMap = uniformMap;
command.pass = Pass.TERRAIN_CLASSIFICATION;

Expand Down Expand Up @@ -761,26 +801,45 @@ define([
var commandList = frameState.commandList;
var passes = frameState.passes;

var i;
var indices;
var startIndex;
var endIndex;
var classificationType = classificationPrimitive.classificationType;

if (passes.render) {
var colorCommand;
var colorLength = colorCommands.length;
indices = getCommandIndices(classificationType, colorLength);
startIndex = indices.start;
endIndex = indices.end;

for (var i = startIndex; i < endIndex; ++i) {
var colorCommand = colorCommands[i];
for (i = startIndex; i < endIndex; ++i) {
colorCommand = colorCommands[i];
colorCommand.modelMatrix = modelMatrix;
colorCommand.boundingVolume = boundingVolumes[boundingVolumeIndex(i, colorLength)];
colorCommand.cull = cull;
colorCommand.debugShowBoundingVolume = debugShowBoundingVolume;

commandList.push(colorCommand);
}

if (frameState.invertClassification) {
var ignoreShowCommands = classificationPrimitive._commandsIgnoreShow;
startIndex = 0;
endIndex = ignoreShowCommands.length;

for (i = startIndex; i < endIndex; ++i) {
var bvIndex = Math.floor(i / 2);
colorCommand = ignoreShowCommands[i];
colorCommand.modelMatrix = modelMatrix;
colorCommand.boundingVolume = boundingVolumes[bvIndex];
colorCommand.cull = cull;
colorCommand.debugShowBoundingVolume = debugShowBoundingVolume;

commandList.push(colorCommand);
}
}
}

if (passes.pick) {
Expand All @@ -790,9 +849,9 @@ define([
endIndex = indices.end;

var pickOffsets = primitive._pickOffsets;
for (var j = startIndex; j < endIndex; ++j) {
var pickOffset = pickOffsets[boundingVolumeIndex(j, pickLength)];
var pickCommand = pickCommands[j];
for (i = startIndex; i < endIndex; ++i) {
var pickOffset = pickOffsets[boundingVolumeIndex(i, pickLength)];
var pickCommand = pickCommands[i];
pickCommand.modelMatrix = modelMatrix;
pickCommand.boundingVolume = boundingVolumes[pickOffset.index];
pickCommand.cull = cull;
Expand Down
14 changes: 14 additions & 0 deletions Source/Scene/FrameState.js
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,20 @@ define([
* @type {Number}
*/
this.minimumDisableDepthTestDistance = undefined;

/**
* When <code>false</code>, 3D Tiles will render normally. When <code>true</code>, classified 3D Tile geometry will render normally and
* unclassified 3D Tile geometry will render with the color multiplied with {@link FrameState#invertClassificationColor}.
* @type {Boolean}
* @default false
*/
this.invertClassification = false;

/**
* The highlight color of unclassified 3D Tile geometry when {@link FrameState#invertClassification} is <code>true</code>.
* @type {Color}
*/
this.invertClassificationColor = undefined;
}

/**
Expand Down
24 changes: 22 additions & 2 deletions Source/Scene/GroundPrimitive.js
Original file line number Diff line number Diff line change
Expand Up @@ -614,8 +614,11 @@ define([
startIndex = indices.start;
endIndex = indices.end;

for (var i = startIndex; i < endIndex; ++i) {
var colorCommand = colorCommands[i];
var i;
var colorCommand;

for (i = startIndex; i < endIndex; ++i) {
colorCommand = colorCommands[i];
colorCommand.owner = groundPrimitive;
colorCommand.modelMatrix = modelMatrix;
colorCommand.boundingVolume = boundingVolumes[boundingVolumeIndex(i, colorLength)];
Expand All @@ -624,6 +627,23 @@ define([

commandList.push(colorCommand);
}

if (frameState.invertClassification) {
var ignoreShowCommands = groundPrimitive._primitive._commandsIgnoreShow;
startIndex = 0;
endIndex = ignoreShowCommands.length;

for (i = startIndex; i < endIndex; ++i) {
var bvIndex = Math.floor(i / 2);
colorCommand = ignoreShowCommands[i];
colorCommand.modelMatrix = modelMatrix;
colorCommand.boundingVolume = boundingVolumes[bvIndex];
colorCommand.cull = cull;
colorCommand.debugShowBoundingVolume = debugShowBoundingVolume;

commandList.push(colorCommand);
}
}
}

if (passes.pick) {
Expand Down
Loading