Skip to content

Commit

Permalink
Merge pull request #8870 from CesiumGS/two-pass-classification
Browse files Browse the repository at this point in the history
Switch to two-pass shadow volumes for classification
  • Loading branch information
IanLilleyT authored May 20, 2020
2 parents d85033e + 50a719d commit 9eaf6a8
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 289 deletions.
181 changes: 32 additions & 149 deletions Source/Scene/ClassificationPrimitive.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,6 @@ function ClassificationPrimitive(options) {
this._spPick2D = undefined; // only derived if necessary
this._spColor2D = undefined; // only derived if necessary

this._rsStencilPreloadPass = undefined;
this._rsStencilPreloadPass3DTiles = undefined;
this._rsStencilDepthPass = undefined;
this._rsStencilDepthPass3DTiles = undefined;
this._rsColorPass = undefined;
Expand Down Expand Up @@ -357,7 +355,7 @@ ClassificationPrimitive.isSupported = function (scene) {
return scene.context.stencilBuffer;
};

function getStencilPreloadRenderState(enableStencil, mask3DTiles) {
function getStencilDepthRenderState(enableStencil, mask3DTiles) {
var stencilFunction = mask3DTiles
? StencilFunction.EQUAL
: StencilFunction.ALWAYS;
Expand All @@ -374,49 +372,13 @@ function getStencilPreloadRenderState(enableStencil, mask3DTiles) {
frontOperation: {
fail: StencilOperation.KEEP,
zFail: StencilOperation.DECREMENT_WRAP,
zPass: StencilOperation.DECREMENT_WRAP,
zPass: StencilOperation.KEEP,
},
backFunction: stencilFunction,
backOperation: {
fail: StencilOperation.KEEP,
zFail: StencilOperation.INCREMENT_WRAP,
zPass: StencilOperation.INCREMENT_WRAP,
},
reference: StencilConstants.CESIUM_3D_TILE_MASK,
mask: StencilConstants.CESIUM_3D_TILE_MASK,
},
stencilMask: StencilConstants.CLASSIFICATION_MASK,
depthTest: {
enabled: false,
},
depthMask: false,
};
}

function getStencilDepthRenderState(enableStencil, mask3DTiles) {
var stencilFunction = mask3DTiles
? StencilFunction.EQUAL
: StencilFunction.ALWAYS;
return {
colorMask: {
red: false,
green: false,
blue: false,
alpha: false,
},
stencilTest: {
enabled: enableStencil,
frontFunction: stencilFunction,
frontOperation: {
fail: StencilOperation.KEEP,
zFail: StencilOperation.KEEP,
zPass: StencilOperation.INCREMENT_WRAP,
},
backFunction: stencilFunction,
backOperation: {
fail: StencilOperation.KEEP,
zFail: StencilOperation.KEEP,
zPass: StencilOperation.DECREMENT_WRAP,
zPass: StencilOperation.KEEP,
},
reference: StencilConstants.CESIUM_3D_TILE_MASK,
mask: StencilConstants.CESIUM_3D_TILE_MASK,
Expand All @@ -436,15 +398,15 @@ function getColorRenderState(enableStencil) {
enabled: enableStencil,
frontFunction: StencilFunction.NOT_EQUAL,
frontOperation: {
fail: StencilOperation.KEEP,
zFail: StencilOperation.KEEP,
zPass: StencilOperation.DECREMENT_WRAP,
fail: StencilOperation.ZERO,
zFail: StencilOperation.ZERO,
zPass: StencilOperation.ZERO,
},
backFunction: StencilFunction.NOT_EQUAL,
backOperation: {
fail: StencilOperation.KEEP,
zFail: StencilOperation.KEEP,
zPass: StencilOperation.DECREMENT_WRAP,
fail: StencilOperation.ZERO,
zFail: StencilOperation.ZERO,
zPass: StencilOperation.ZERO,
},
reference: 0,
mask: StencilConstants.CLASSIFICATION_MASK,
Expand All @@ -463,15 +425,15 @@ var pickRenderState = {
enabled: true,
frontFunction: StencilFunction.NOT_EQUAL,
frontOperation: {
fail: StencilOperation.KEEP,
zFail: StencilOperation.KEEP,
zPass: StencilOperation.DECREMENT_WRAP,
fail: StencilOperation.ZERO,
zFail: StencilOperation.ZERO,
zPass: StencilOperation.ZERO,
},
backFunction: StencilFunction.NOT_EQUAL,
backOperation: {
fail: StencilOperation.KEEP,
zFail: StencilOperation.KEEP,
zPass: StencilOperation.DECREMENT_WRAP,
fail: StencilOperation.ZERO,
zFail: StencilOperation.ZERO,
zPass: StencilOperation.ZERO,
},
reference: 0,
mask: StencilConstants.CLASSIFICATION_MASK,
Expand All @@ -489,17 +451,11 @@ function createRenderStates(
appearance,
twoPasses
) {
if (defined(classificationPrimitive._rsStencilPreloadPass)) {
if (defined(classificationPrimitive._rsStencilDepthPass)) {
return;
}
var stencilEnabled = !classificationPrimitive.debugShowShadowVolume;

classificationPrimitive._rsStencilPreloadPass = RenderState.fromCache(
getStencilPreloadRenderState(stencilEnabled, false)
);
classificationPrimitive._rsStencilPreloadPass3DTiles = RenderState.fromCache(
getStencilPreloadRenderState(stencilEnabled, true)
);
classificationPrimitive._rsStencilDepthPass = RenderState.fromCache(
getStencilDepthRenderState(stencilEnabled, false)
);
Expand Down Expand Up @@ -722,7 +678,7 @@ function createShaderProgram(classificationPrimitive, frameState) {

function createColorCommands(classificationPrimitive, colorCommands) {
var primitive = classificationPrimitive._primitive;
var length = primitive._va.length * 3; // each geometry (pack of vertex attributes) needs 3 commands: front/back stencils and fill
var length = primitive._va.length * 2; // each geometry (pack of vertex attributes) needs 2 commands: front/back stencils and fill
colorCommands.length = length;

var i;
Expand All @@ -735,10 +691,10 @@ function createColorCommands(classificationPrimitive, colorCommands) {

var needs2DShader = classificationPrimitive._needs2DShader;

for (i = 0; i < length; i += 3) {
for (i = 0; i < length; i += 2) {
var vertexArray = primitive._va[vaIndex++];

// Stencil preload command
// Stencil depth command
command = colorCommands[i];
if (!defined(command)) {
command = colorCommands[i] = new DrawCommand({
Expand All @@ -747,30 +703,6 @@ function createColorCommands(classificationPrimitive, colorCommands) {
});
}

command.vertexArray = vertexArray;
command.renderState = classificationPrimitive._rsStencilPreloadPass;
command.shaderProgram = classificationPrimitive._sp;
command.uniformMap = uniformMap;
command.pass = Pass.TERRAIN_CLASSIFICATION;

derivedCommand = DrawCommand.shallowClone(
command,
command.derivedCommands.tileset
);
derivedCommand.renderState =
classificationPrimitive._rsStencilPreloadPass3DTiles;
derivedCommand.pass = Pass.CESIUM_3D_TILE_CLASSIFICATION;
command.derivedCommands.tileset = derivedCommand;

// Stencil depth command
command = colorCommands[i + 1];
if (!defined(command)) {
command = colorCommands[i + 1] = new DrawCommand({
owner: classificationPrimitive,
primitiveType: primitive._primitiveType,
});
}

command.vertexArray = vertexArray;
command.renderState = classificationPrimitive._rsStencilDepthPass;
command.shaderProgram = classificationPrimitive._sp;
Expand All @@ -787,9 +719,9 @@ function createColorCommands(classificationPrimitive, colorCommands) {
command.derivedCommands.tileset = derivedCommand;

// Color command
command = colorCommands[i + 2];
command = colorCommands[i + 1];
if (!defined(command)) {
command = colorCommands[i + 2] = new DrawCommand({
command = colorCommands[i + 1] = new DrawCommand({
owner: classificationPrimitive,
primitiveType: primitive._primitiveType,
});
Expand Down Expand Up @@ -839,40 +771,33 @@ function createColorCommands(classificationPrimitive, colorCommands) {
var spStencil = classificationPrimitive._spStencil;

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

for (var j = 0; j < length; j += 2) {
for (var j = 0; j < length; ++j) {
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;
commandIndex += 2;
}
}

function createPickCommands(classificationPrimitive, pickCommands) {
var usePickOffsets = classificationPrimitive._usePickOffsets;

var primitive = classificationPrimitive._primitive;
var length = primitive._va.length * 3; // each geometry (pack of vertex attributes) needs 3 commands: front/back stencils and fill
var length = primitive._va.length * 2; // each geometry (pack of vertex attributes) needs 2 commands: front/back stencils and fill

// Fallback for batching same-color geometry instances
var pickOffsets;
var pickIndex = 0;
var pickOffset;
if (usePickOffsets) {
pickOffsets = primitive._pickOffsets;
length = pickOffsets.length * 3;
length = pickOffsets.length * 2;
}

pickCommands.length = length;
Expand All @@ -887,14 +812,14 @@ function createPickCommands(classificationPrimitive, pickCommands) {

var needs2DShader = classificationPrimitive._needs2DShader;

for (j = 0; j < length; j += 3) {
for (j = 0; j < length; j += 2) {
var vertexArray = primitive._va[vaIndex++];
if (usePickOffsets) {
pickOffset = pickOffsets[pickIndex++];
vertexArray = primitive._va[pickOffset.index];
}

// Stencil preload command
// Stencil depth command
command = pickCommands[j];
if (!defined(command)) {
command = pickCommands[j] = new DrawCommand({
Expand All @@ -904,36 +829,6 @@ function createPickCommands(classificationPrimitive, pickCommands) {
});
}

command.vertexArray = vertexArray;
command.renderState = classificationPrimitive._rsStencilPreloadPass;
command.shaderProgram = classificationPrimitive._sp;
command.uniformMap = uniformMap;
command.pass = Pass.TERRAIN_CLASSIFICATION;
if (usePickOffsets) {
command.offset = pickOffset.offset;
command.count = pickOffset.count;
}

// Derive for 3D Tiles classification
derivedCommand = DrawCommand.shallowClone(
command,
command.derivedCommands.tileset
);
derivedCommand.renderState =
classificationPrimitive._rsStencilPreloadPass3DTiles;
derivedCommand.pass = Pass.CESIUM_3D_TILE_CLASSIFICATION;
command.derivedCommands.tileset = derivedCommand;

// Stencil depth command
command = pickCommands[j + 1];
if (!defined(command)) {
command = pickCommands[j + 1] = new DrawCommand({
owner: classificationPrimitive,
primitiveType: primitive._primitiveType,
pickOnly: true,
});
}

command.vertexArray = vertexArray;
command.renderState = classificationPrimitive._rsStencilDepthPass;
command.shaderProgram = classificationPrimitive._sp;
Expand All @@ -955,9 +850,9 @@ function createPickCommands(classificationPrimitive, pickCommands) {
command.derivedCommands.tileset = derivedCommand;

// Pick color command
command = pickCommands[j + 2];
command = pickCommands[j + 1];
if (!defined(command)) {
command = pickCommands[j + 2] = new DrawCommand({
command = pickCommands[j + 1] = new DrawCommand({
owner: classificationPrimitive,
primitiveType: primitive._primitiveType,
pickOnly: true,
Expand Down Expand Up @@ -1016,7 +911,7 @@ function createCommands(
}

function boundingVolumeIndex(commandIndex, length) {
return Math.floor((commandIndex % length) / 3);
return Math.floor((commandIndex % length) / 2);
}

function updateAndQueueRenderCommand(
Expand Down Expand Up @@ -1119,7 +1014,7 @@ function updateAndQueueCommands(
var ignoreShowCommands = classificationPrimitive._commandsIgnoreShow;
var ignoreShowCommandsLength = ignoreShowCommands.length;
for (i = 0; i < ignoreShowCommandsLength; ++i) {
boundingVolume = boundingVolumes[Math.floor(i / 2)];
boundingVolume = boundingVolumes[i];
command = ignoreShowCommands[i];
updateAndQueueRenderCommand(
command,
Expand Down Expand Up @@ -1411,12 +1306,6 @@ ClassificationPrimitive.prototype.update = function (frameState) {
this._ready
) {
this._debugShowShadowVolume = true;
this._rsStencilPreloadPass = RenderState.fromCache(
getStencilPreloadRenderState(false, false)
);
this._rsStencilPreloadPass3DTiles = RenderState.fromCache(
getStencilPreloadRenderState(false, true)
);
this._rsStencilDepthPass = RenderState.fromCache(
getStencilDepthRenderState(false, false)
);
Expand All @@ -1426,12 +1315,6 @@ ClassificationPrimitive.prototype.update = function (frameState) {
this._rsColorPass = RenderState.fromCache(getColorRenderState(false));
} else if (!this.debugShowShadowVolume && this._debugShowShadowVolume) {
this._debugShowShadowVolume = false;
this._rsStencilPreloadPass = RenderState.fromCache(
getStencilPreloadRenderState(true, false)
);
this._rsStencilPreloadPass3DTiles = RenderState.fromCache(
getStencilPreloadRenderState(true, true)
);
this._rsStencilDepthPass = RenderState.fromCache(
getStencilDepthRenderState(true, false)
);
Expand Down
4 changes: 2 additions & 2 deletions Source/Scene/GroundPrimitive.js
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,7 @@ function createBoundingVolume(groundPrimitive, frameState, geometry) {
}

function boundingVolumeIndex(commandIndex, length) {
return Math.floor((commandIndex % length) / 3);
return Math.floor((commandIndex % length) / 2);
}

function updateAndQueueRenderCommand(
Expand Down Expand Up @@ -626,7 +626,7 @@ function updateAndQueueCommands(
var ignoreShowCommands = classificationPrimitive._commandsIgnoreShow;
var ignoreShowCommandsLength = ignoreShowCommands.length;
for (i = 0; i < ignoreShowCommandsLength; ++i) {
boundingVolume = boundingVolumes[Math.floor(i / 2)];
boundingVolume = boundingVolumes[i];
command = ignoreShowCommands[i];
updateAndQueueRenderCommand(
groundPrimitive,
Expand Down
Loading

0 comments on commit 9eaf6a8

Please sign in to comment.