Skip to content

Commit

Permalink
Merge pull request #5298 from AnalyticalGraphicsInc/command-cleanup
Browse files Browse the repository at this point in the history
Clean up 3D Tiles derived commands
  • Loading branch information
pjcozzi authored May 10, 2017
2 parents c4e6591 + 29829b4 commit d4a9f70
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 79 deletions.
12 changes: 7 additions & 5 deletions Source/Scene/Batched3DModel3DTileContent.js
Original file line number Diff line number Diff line change
Expand Up @@ -395,10 +395,7 @@ define([
* Part of the {@link Cesium3DTileContent} interface.
*/
Batched3DModel3DTileContent.prototype.update = function(tileset, frameState) {
var oldAddCommand = frameState.addCommand;
if (frameState.passes.render) {
frameState.addCommand = this.batchTable.getAddCommand();
}
var commandStart = frameState.commandList.length;

// In the PROCESSING state we may be calling update() to move forward
// the content's resource loading. In the READY state, it will
Expand All @@ -408,7 +405,12 @@ define([
this._model.shadows = this._tileset.shadows;
this._model.debugWireframe = this._tileset.debugWireframe;
this._model.update(frameState);
frameState.addCommand = oldAddCommand;

// If any commands were pushed, add derived commands
var commandEnd = frameState.commandList.length;
if ((commandStart < commandEnd) && frameState.passes.render) {
this.batchTable.addDerivedCommands(frameState, commandStart);
}
};

/**
Expand Down
102 changes: 46 additions & 56 deletions Source/Scene/Cesium3DTileBatchTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -894,8 +894,6 @@ define([
' vec4 featureProperties = texture2D(tile_batchTexture, st); \n' +
' float show = ceil(featureProperties.a); \n' + // 0 - false, non-zeo - true
' gl_Position *= show; \n'; // Per-feature show/hide
// TODO: Translucent should still write depth for picking? For example, we want to grab highlighted building that became translucent
// TODO: Same TODOs below in getFragmentShaderCallback
if (handleTranslucent) {
newMain +=
' bool isStyleTranslucent = (featureProperties.a != 1.0); \n' +
Expand Down Expand Up @@ -1231,56 +1229,48 @@ define([
OPAQUE_AND_TRANSLUCENT : 2
};

function updateDerivedCommands(derivedCommands, command) {
for (var name in derivedCommands) {
if (derivedCommands.hasOwnProperty(name)) {
var derivedCommand = derivedCommands[name];
derivedCommand.castShadows = command.castShadows;
derivedCommand.receiveShadows = command.receiveShadows;
derivedCommand.primitiveType = command.primitiveType;
}
}
}

Cesium3DTileBatchTable.prototype.getAddCommand = function() {
var styleCommandsNeeded = getStyleCommandsNeeded(this);
Cesium3DTileBatchTable.prototype.addDerivedCommands = function(frameState, commandStart) {
var commandList = frameState.commandList;
var commandEnd = commandList.length;
var tile = this._content._tile;
var tileset = tile._tileset;
var bivariateVisibilityTest = tileset.skipLODs && tileset._hasMixedContent && frameState.context.stencilBuffer;
var styleCommandsNeeded = getStyleCommandsNeeded(this);

// TODO: This function most likely will not get optimized. Do something like this later in the render loop.
return function(command) {
var commandList = this.commandList;

for (var i = commandStart; i < commandEnd; ++i) {
var command = commandList[i];
var derivedCommands = command.derivedCommands.tileset;
if (!defined(derivedCommands)) {
derivedCommands = {};
command.derivedCommands.tileset = derivedCommands;

derivedCommands.originalCommand = deriveCommand(command);
derivedCommands.back = deriveTranslucentCommand(command, CullFace.FRONT);
derivedCommands.front = deriveTranslucentCommand(command, CullFace.BACK);
}

var bivariateVisibilityTest = tileset.skipLODs && tileset._hasMixedContent && this.context.stencilBuffer;
updateDerivedCommand(derivedCommands.originalCommand, command);

if (bivariateVisibilityTest) {
if (!defined(derivedCommands.zback)) {
derivedCommands.zback = deriveZBackfaceCommand(command);
if (styleCommandsNeeded !== StyleCommandsNeeded.ALL_OPAQUE) {
if (!defined(derivedCommands.translucent)) {
derivedCommands.translucent = deriveTranslucentCommand(derivedCommands.originalCommand);
}
updateDerivedCommand(derivedCommands.translucent, command);
}

if (bivariateVisibilityTest) {
if (command.pass !== Pass.TRANSLUCENT) {
if (!defined(derivedCommands.zback)) {
derivedCommands.zback = deriveZBackfaceCommand(derivedCommands.originalCommand);
}
tileset._backfaceCommands.push(derivedCommands.zback);
}

if (!defined(derivedCommands.stencil) || tile._selectionDepth !== tile._lastSelectionDepth) {
derivedCommands.stencil = deriveStencilCommand(derivedCommands.originalCommand, tile._selectionDepth);
tile._lastSelectionDepth = tile._selectionDepth;
}
updateDerivedCommand(derivedCommands.stencil, command);
}

updateDerivedCommands(derivedCommands, command);

// replace original commands with stenciled commands
var opaqueCommand = bivariateVisibilityTest ? derivedCommands.stencil : derivedCommands.originalCommand;
var translucentCommand = derivedCommands.translucent;

// If the command was originally opaque:
// * If the styling applied to the tile is all opaque, use the original command
Expand All @@ -1289,36 +1279,35 @@ define([
// and back faces) with a translucent render state.
// * If the styling causes both opaque and translucent features in this tile,
// then use both sets of commands.
// TODO: if the tile has multiple commands, we do not know what features are in what
// commands so the third-case may be overkill. Change this to a PERFORMANCE_IDEA?
if (command.pass !== Pass.TRANSLUCENT) {
if (styleCommandsNeeded === StyleCommandsNeeded.ALL_OPAQUE) {
commandList.push(opaqueCommand);
commandList[i] = opaqueCommand;
}

if (styleCommandsNeeded === StyleCommandsNeeded.ALL_TRANSLUCENT) {
// TODO: vector tiles, for example, will not always want two passes for translucency. Some primitives,
// for example, those created from Cesium geometries, will also already return commands for two
// passes if the command is originally translucent. Same TODO below.
commandList.push(derivedCommands.back);
commandList.push(derivedCommands.front);
commandList[i] = translucentCommand;
}

if (styleCommandsNeeded === StyleCommandsNeeded.OPAQUE_AND_TRANSLUCENT) {
commandList.push(opaqueCommand);
commandList.push(derivedCommands.back);
commandList.push(derivedCommands.front);
// PERFORMANCE_IDEA: if the tile has multiple commands, we do not know what features are in what
// commands so this case may be overkill.
commandList[i] = opaqueCommand;
commandList.push(translucentCommand);
}
} else {
// Command was originally translucent so no need to derive new commands;
// 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.push(opaqueCommand);
commandList[i] = opaqueCommand;
}
};
}
};

function updateDerivedCommand(derivedCommand, command) {
derivedCommand.castShadows = command.castShadows;
derivedCommand.receiveShadows = command.receiveShadows;
derivedCommand.primitiveType = command.primitiveType;
}

function getStyleCommandsNeeded(batchTable) {
var translucentFeaturesLength = batchTable._translucentFeaturesLength;

Expand All @@ -1331,13 +1320,6 @@ define([
return StyleCommandsNeeded.OPAQUE_AND_TRANSLUCENT;
}

function deriveTranslucentCommand(command, cullFace) {
var derivedCommand = deriveCommand(command);
derivedCommand.pass = Pass.TRANSLUCENT;
derivedCommand.renderState = getTranslucentRenderState(command.renderState, cullFace);
return derivedCommand;
}

function deriveCommand(command) {
var derivedCommand = DrawCommand.shallowClone(command);

Expand All @@ -1358,13 +1340,22 @@ define([
return derivedCommand;
}

// write just backface depth of unresolved tiles so resolved stenciled tiles do not appear in front
function deriveTranslucentCommand(command) {
var derivedCommand = DrawCommand.shallowClone(command);
derivedCommand.pass = Pass.TRANSLUCENT;
derivedCommand.renderState = getTranslucentRenderState(command.renderState);
return derivedCommand;
}

function deriveZBackfaceCommand(command) {
// Write just backface depth of unresolved tiles so resolved stenciled tiles do not appear in front
var derivedCommand = DrawCommand.shallowClone(command);
var rs = clone(derivedCommand.renderState, true);
rs.cull.enabled = true;
rs.cull.face = CullFace.FRONT;
derivedCommand.renderState = RenderState.fromCache(rs);
derivedCommand.castShadows = false;
derivedCommand.receiveShadows = false;
return derivedCommand;
}

Expand All @@ -1384,10 +1375,9 @@ define([
return derivedCommand;
}

function getTranslucentRenderState(renderState, cullFace) {
function getTranslucentRenderState(renderState) {
var rs = clone(renderState, true);
rs.cull.enabled = true;
rs.cull.face = cullFace;
rs.cull.enabled = false;
rs.depthTest.enabled = true;
rs.depthMask = false;
rs.blending = BlendingState.ALPHA_BLEND;
Expand Down
4 changes: 0 additions & 4 deletions Source/Scene/FrameState.js
Original file line number Diff line number Diff line change
Expand Up @@ -287,10 +287,6 @@ define([
this.minimumDisableDepthTestDistance = undefined;
}

FrameState.prototype.addCommand = function(command) {
this.commandList.push(command);
};

/**
* A function that will be called at the end of the frame.
*
Expand Down
11 changes: 6 additions & 5 deletions Source/Scene/Instanced3DModel3DTileContent.js
Original file line number Diff line number Diff line change
Expand Up @@ -480,10 +480,7 @@ define([
* Part of the {@link Cesium3DTileContent} interface.
*/
Instanced3DModel3DTileContent.prototype.update = function(tileset, frameState) {
var oldAddCommand = frameState.addCommand;
if (frameState.passes.render) {
frameState.addCommand = this.batchTable.getAddCommand();
}
var commandStart = frameState.commandList.length;

// In the PROCESSING state we may be calling update() to move forward
// the content's resource loading. In the READY state, it will
Expand All @@ -494,7 +491,11 @@ define([
this._modelInstanceCollection.debugWireframe = this._tileset.debugWireframe;
this._modelInstanceCollection.update(frameState);

frameState.addCommand = oldAddCommand;
// If any commands were pushed, add derived commands
var commandEnd = frameState.commandList.length;
if ((commandStart < commandEnd) && frameState.passes.render) {
this.batchTable.addDerivedCommands(frameState, commandStart);
}
};

/**
Expand Down
13 changes: 7 additions & 6 deletions Source/Scene/Model.js
Original file line number Diff line number Diff line change
Expand Up @@ -4662,6 +4662,7 @@ define([
// and then have them visible immediately when show is set to true.
if (show && !this._ignoreCommands) {
// PERFORMANCE_IDEA: This is terrible
var commandList = frameState.commandList;
var passes = frameState.passes;
var nodeCommands = this._nodeCommands;
var length = nodeCommands.length;
Expand All @@ -4677,13 +4678,13 @@ define([
if (nc.show) {
var command = translucent ? nc.translucentCommand : nc.command;
command = silhouette ? nc.silhouetteModelCommand : command;
frameState.addCommand(command);
commandList.push(command);
boundingVolume = nc.command.boundingVolume;
if (frameState.mode === SceneMode.SCENE2D &&
(boundingVolume.center.y + boundingVolume.radius > idl2D || boundingVolume.center.y - boundingVolume.radius < idl2D)) {
var command2D = translucent ? nc.translucentCommand2D : nc.command2D;
command2D = silhouette ? nc.silhouetteModelCommand2D : command2D;
frameState.addCommand(command2D);
commandList.push(command2D);
}
}
}
Expand All @@ -4693,11 +4694,11 @@ define([
for (i = 0; i < length; ++i) {
nc = nodeCommands[i];
if (nc.show) {
frameState.addCommand(nc.silhouetteColorCommand);
commandList.push(nc.silhouetteColorCommand);
boundingVolume = nc.command.boundingVolume;
if (frameState.mode === SceneMode.SCENE2D &&
(boundingVolume.center.y + boundingVolume.radius > idl2D || boundingVolume.center.y - boundingVolume.radius < idl2D)) {
frameState.addCommand(nc.silhouetteColorCommand2D);
commandList.push(nc.silhouetteColorCommand2D);
}
}
}
Expand All @@ -4709,12 +4710,12 @@ define([
nc = nodeCommands[i];
if (nc.show) {
var pickCommand = nc.pickCommand;
frameState.addCommand(pickCommand);
commandList.push(pickCommand);

boundingVolume = pickCommand.boundingVolume;
if (frameState.mode === SceneMode.SCENE2D &&
(boundingVolume.center.y + boundingVolume.radius > idl2D || boundingVolume.center.y - boundingVolume.radius < idl2D)) {
frameState.addCommand(nc.pickCommand2D);
commandList.push(nc.pickCommand2D);
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion Source/Scene/ModelInstanceCollection.js
Original file line number Diff line number Diff line change
Expand Up @@ -975,11 +975,12 @@ define([
updateShowBoundingVolume(this);

var passes = frameState.passes;
var commandList = frameState.commandList;
var commands = passes.render ? this._drawCommands : this._pickCommands;
var commandsLength = commands.length;

for (var i = 0; i < commandsLength; ++i) {
frameState.addCommand(commands[i]);
commandList.push(commands[i]);
}
};

Expand Down
6 changes: 4 additions & 2 deletions Source/Scene/PointCloud3DTileContent.js
Original file line number Diff line number Diff line change
Expand Up @@ -1217,12 +1217,14 @@ define([
this.batchTable.update(tileset, frameState);
}

var commandList = frameState.commandList;

var passes = frameState.passes;
if (passes.render) {
frameState.addCommand(this._drawCommand);
commandList.push(this._drawCommand);
}
if (passes.pick) {
frameState.addCommand(this._pickCommand);
commandList.push(this._pickCommand);
}
};

Expand Down

0 comments on commit d4a9f70

Please sign in to comment.