Add existing to tracked
This commit is contained in:
+534
@@ -0,0 +1,534 @@
|
||||
import addAllToArray from "../../Core/addAllToArray.js";
|
||||
import BoundingSphere from "../../Core/BoundingSphere.js";
|
||||
import Check from "../../Core/Check.js";
|
||||
import Frozen from "../../Core/Frozen.js";
|
||||
import Matrix4 from "../../Core/Matrix4.js";
|
||||
import DrawCommand from "../../Renderer/DrawCommand.js";
|
||||
import Pass from "../../Renderer/Pass.js";
|
||||
import RenderState from "../../Renderer/RenderState.js";
|
||||
import BlendingState from "../BlendingState.js";
|
||||
import ClassificationType from "../ClassificationType.js";
|
||||
import DepthFunction from "../DepthFunction.js";
|
||||
import StencilConstants from "../StencilConstants.js";
|
||||
import StencilFunction from "../StencilFunction.js";
|
||||
import StencilOperation from "../StencilOperation.js";
|
||||
|
||||
/**
|
||||
* A wrapper around the draw commands used to render a classification model,
|
||||
* i.e. a {@link Model} that classifies another asset. This manages the
|
||||
* derived commands and returns only the necessary commands depending on the
|
||||
* given frame state.
|
||||
*
|
||||
* @param {object} options An object containing the following options:
|
||||
* @param {DrawCommand} options.command The draw command from which to derive other commands from.
|
||||
* @param {PrimitiveRenderResources} options.primitiveRenderResources The render resources of the primitive associated with the command.
|
||||
*
|
||||
* @alias ClassificationModelDrawCommand
|
||||
* @constructor
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function ClassificationModelDrawCommand(options) {
|
||||
options = options ?? Frozen.EMPTY_OBJECT;
|
||||
|
||||
const command = options.command;
|
||||
const renderResources = options.primitiveRenderResources;
|
||||
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
Check.typeOf.object("options.command", command);
|
||||
Check.typeOf.object("options.primitiveRenderResources", renderResources);
|
||||
//>>includeEnd('debug');
|
||||
|
||||
const model = renderResources.model;
|
||||
|
||||
this._command = command;
|
||||
this._model = model;
|
||||
this._runtimePrimitive = renderResources.runtimePrimitive;
|
||||
|
||||
// Classification models aren't supported in 2D mode, so there's no need to
|
||||
// duplicate the model matrix for each derived command.
|
||||
this._modelMatrix = command.modelMatrix;
|
||||
this._boundingVolume = command.boundingVolume;
|
||||
this._cullFace = command.renderState.cull.face;
|
||||
|
||||
const type = model.classificationType;
|
||||
this._classificationType = type;
|
||||
|
||||
// ClassificationType has three values: terrain only, 3D Tiles only, or both.
|
||||
this._classifiesTerrain = type !== ClassificationType.CESIUM_3D_TILE;
|
||||
this._classifies3DTiles = type !== ClassificationType.TERRAIN;
|
||||
|
||||
this._useDebugWireframe = model._enableDebugWireframe && model.debugWireframe;
|
||||
this._pickId = renderResources.pickId;
|
||||
|
||||
this._commandListTerrain = [];
|
||||
this._commandList3DTiles = [];
|
||||
this._commandListIgnoreShow = []; // Used for inverted classification.
|
||||
this._commandListDebugWireframe = [];
|
||||
|
||||
this._commandListTerrainPicking = [];
|
||||
this._commandList3DTilesPicking = [];
|
||||
|
||||
initialize(this);
|
||||
}
|
||||
|
||||
function getStencilDepthRenderState(stencilFunction) {
|
||||
return {
|
||||
colorMask: {
|
||||
red: false,
|
||||
green: false,
|
||||
blue: false,
|
||||
alpha: false,
|
||||
},
|
||||
stencilTest: {
|
||||
enabled: true,
|
||||
frontFunction: stencilFunction,
|
||||
frontOperation: {
|
||||
fail: StencilOperation.KEEP,
|
||||
zFail: StencilOperation.DECREMENT_WRAP,
|
||||
zPass: StencilOperation.KEEP,
|
||||
},
|
||||
backFunction: stencilFunction,
|
||||
backOperation: {
|
||||
fail: StencilOperation.KEEP,
|
||||
zFail: StencilOperation.INCREMENT_WRAP,
|
||||
zPass: StencilOperation.KEEP,
|
||||
},
|
||||
reference: StencilConstants.CESIUM_3D_TILE_MASK,
|
||||
mask: StencilConstants.CESIUM_3D_TILE_MASK,
|
||||
},
|
||||
stencilMask: StencilConstants.CLASSIFICATION_MASK,
|
||||
depthTest: {
|
||||
enabled: true,
|
||||
func: DepthFunction.LESS_OR_EQUAL,
|
||||
},
|
||||
depthMask: false,
|
||||
};
|
||||
}
|
||||
|
||||
const colorRenderState = {
|
||||
stencilTest: {
|
||||
enabled: true,
|
||||
frontFunction: StencilFunction.NOT_EQUAL,
|
||||
frontOperation: {
|
||||
fail: StencilOperation.ZERO,
|
||||
zFail: StencilOperation.ZERO,
|
||||
zPass: StencilOperation.ZERO,
|
||||
},
|
||||
backFunction: StencilFunction.NOT_EQUAL,
|
||||
backOperation: {
|
||||
fail: StencilOperation.ZERO,
|
||||
zFail: StencilOperation.ZERO,
|
||||
zPass: StencilOperation.ZERO,
|
||||
},
|
||||
reference: 0,
|
||||
mask: StencilConstants.CLASSIFICATION_MASK,
|
||||
},
|
||||
stencilMask: StencilConstants.CLASSIFICATION_MASK,
|
||||
depthTest: {
|
||||
enabled: false,
|
||||
},
|
||||
depthMask: false,
|
||||
blending: BlendingState.PRE_MULTIPLIED_ALPHA_BLEND,
|
||||
};
|
||||
|
||||
const pickRenderState = {
|
||||
stencilTest: {
|
||||
enabled: true,
|
||||
frontFunction: StencilFunction.NOT_EQUAL,
|
||||
frontOperation: {
|
||||
fail: StencilOperation.ZERO,
|
||||
zFail: StencilOperation.ZERO,
|
||||
zPass: StencilOperation.ZERO,
|
||||
},
|
||||
backFunction: StencilFunction.NOT_EQUAL,
|
||||
backOperation: {
|
||||
fail: StencilOperation.ZERO,
|
||||
zFail: StencilOperation.ZERO,
|
||||
zPass: StencilOperation.ZERO,
|
||||
},
|
||||
reference: 0,
|
||||
mask: StencilConstants.CLASSIFICATION_MASK,
|
||||
},
|
||||
stencilMask: StencilConstants.CLASSIFICATION_MASK,
|
||||
depthTest: {
|
||||
enabled: false,
|
||||
},
|
||||
depthMask: false,
|
||||
};
|
||||
|
||||
const scratchDerivedCommands = [];
|
||||
|
||||
function initialize(drawCommand) {
|
||||
const command = drawCommand._command;
|
||||
const derivedCommands = scratchDerivedCommands;
|
||||
|
||||
// If debug wireframe is enabled, don't derive any new commands.
|
||||
// Render normally in the opaque pass.
|
||||
if (drawCommand._useDebugWireframe) {
|
||||
command.pass = Pass.OPAQUE;
|
||||
|
||||
derivedCommands.length = 0;
|
||||
derivedCommands.push(command);
|
||||
|
||||
drawCommand._commandListDebugWireframe = createBatchCommands(
|
||||
drawCommand,
|
||||
derivedCommands,
|
||||
drawCommand._commandListDebugWireframe,
|
||||
);
|
||||
|
||||
const commandList = drawCommand._commandListDebugWireframe;
|
||||
const length = commandList.length;
|
||||
for (let i = 0; i < length; i++) {
|
||||
// The lengths / offsets of the batches have to be adjusted for wireframe.
|
||||
// Only PrimitiveType.TRIANGLES is allowed for classification, so this
|
||||
// just requires doubling the values for the batches.
|
||||
const command = commandList[i];
|
||||
command.count *= 2;
|
||||
command.offset *= 2;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const model = drawCommand.model;
|
||||
const allowPicking = model.allowPicking;
|
||||
|
||||
if (drawCommand._classifiesTerrain) {
|
||||
const pass = Pass.TERRAIN_CLASSIFICATION;
|
||||
const stencilDepthCommand = deriveStencilDepthCommand(command, pass);
|
||||
const colorCommand = deriveColorCommand(command, pass);
|
||||
|
||||
derivedCommands.length = 0;
|
||||
derivedCommands.push(stencilDepthCommand, colorCommand);
|
||||
|
||||
drawCommand._commandListTerrain = createBatchCommands(
|
||||
drawCommand,
|
||||
derivedCommands,
|
||||
drawCommand._commandListTerrain,
|
||||
);
|
||||
|
||||
if (allowPicking) {
|
||||
drawCommand._commandListTerrainPicking = createPickCommands(
|
||||
drawCommand,
|
||||
derivedCommands,
|
||||
drawCommand._commandListTerrainPicking,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (drawCommand._classifies3DTiles) {
|
||||
const pass = Pass.CESIUM_3D_TILE_CLASSIFICATION;
|
||||
const stencilDepthCommand = deriveStencilDepthCommand(command, pass);
|
||||
const colorCommand = deriveColorCommand(command, pass);
|
||||
|
||||
derivedCommands.length = 0;
|
||||
derivedCommands.push(stencilDepthCommand, colorCommand);
|
||||
|
||||
drawCommand._commandList3DTiles = createBatchCommands(
|
||||
drawCommand,
|
||||
derivedCommands,
|
||||
drawCommand._commandList3DTiles,
|
||||
);
|
||||
|
||||
if (allowPicking) {
|
||||
drawCommand._commandList3DTilesPicking = createPickCommands(
|
||||
drawCommand,
|
||||
derivedCommands,
|
||||
drawCommand._commandList3DTilesPicking,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createBatchCommands(drawCommand, derivedCommands, result) {
|
||||
const runtimePrimitive = drawCommand._runtimePrimitive;
|
||||
const batchLengths = runtimePrimitive.batchLengths;
|
||||
const batchOffsets = runtimePrimitive.batchOffsets;
|
||||
|
||||
const numBatches = batchLengths.length;
|
||||
const numDerivedCommands = derivedCommands.length;
|
||||
for (let i = 0; i < numBatches; i++) {
|
||||
const batchLength = batchLengths[i];
|
||||
const batchOffset = batchOffsets[i];
|
||||
// For multiple derived commands (e.g. stencil and color commands),
|
||||
// they must be added in a certain order even within the batches.
|
||||
for (let j = 0; j < numDerivedCommands; j++) {
|
||||
const derivedCommand = derivedCommands[j];
|
||||
const batchCommand = DrawCommand.shallowClone(derivedCommand);
|
||||
batchCommand.count = batchLength;
|
||||
batchCommand.offset = batchOffset;
|
||||
result.push(batchCommand);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function deriveStencilDepthCommand(command, pass) {
|
||||
const stencilDepthCommand = DrawCommand.shallowClone(command);
|
||||
stencilDepthCommand.cull = false;
|
||||
stencilDepthCommand.pass = pass;
|
||||
|
||||
const stencilFunction =
|
||||
pass === Pass.TERRAIN_CLASSIFICATION
|
||||
? StencilFunction.ALWAYS
|
||||
: StencilFunction.EQUAL;
|
||||
const renderState = getStencilDepthRenderState(stencilFunction);
|
||||
stencilDepthCommand.renderState = RenderState.fromCache(renderState);
|
||||
|
||||
return stencilDepthCommand;
|
||||
}
|
||||
|
||||
function deriveColorCommand(command, pass) {
|
||||
const colorCommand = DrawCommand.shallowClone(command);
|
||||
colorCommand.cull = false;
|
||||
colorCommand.pass = pass;
|
||||
|
||||
colorCommand.renderState = RenderState.fromCache(colorRenderState);
|
||||
|
||||
return colorCommand;
|
||||
}
|
||||
|
||||
const scratchPickCommands = [];
|
||||
|
||||
function createPickCommands(drawCommand, derivedCommands, commandList) {
|
||||
const renderState = RenderState.fromCache(pickRenderState);
|
||||
const stencilDepthCommand = derivedCommands[0];
|
||||
const colorCommand = derivedCommands[1];
|
||||
|
||||
const pickStencilDepthCommand = DrawCommand.shallowClone(stencilDepthCommand);
|
||||
pickStencilDepthCommand.cull = true;
|
||||
pickStencilDepthCommand.pickOnly = true;
|
||||
|
||||
const pickColorCommand = DrawCommand.shallowClone(colorCommand);
|
||||
pickColorCommand.cull = true;
|
||||
pickColorCommand.pickOnly = true;
|
||||
pickColorCommand.renderState = renderState;
|
||||
pickColorCommand.pickId = drawCommand._pickId;
|
||||
|
||||
const pickCommands = scratchPickCommands;
|
||||
pickCommands.length = 0;
|
||||
pickCommands.push(pickStencilDepthCommand, pickColorCommand);
|
||||
|
||||
return createBatchCommands(drawCommand, pickCommands, commandList);
|
||||
}
|
||||
|
||||
Object.defineProperties(ClassificationModelDrawCommand.prototype, {
|
||||
/**
|
||||
* The main draw command that the other commands are derived from.
|
||||
*
|
||||
* @memberof ClassificationModelDrawCommand.prototype
|
||||
* @type {DrawCommand}
|
||||
*
|
||||
* @readonly
|
||||
* @private
|
||||
*/
|
||||
command: {
|
||||
get: function () {
|
||||
return this._command;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* The runtime primitive that the draw command belongs to.
|
||||
*
|
||||
* @memberof ClassificationModelDrawCommand.prototype
|
||||
* @type {ModelRuntimePrimitive}
|
||||
*
|
||||
* @readonly
|
||||
* @private
|
||||
*/
|
||||
runtimePrimitive: {
|
||||
get: function () {
|
||||
return this._runtimePrimitive;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* The batch lengths used to generate multiple draw commands.
|
||||
*
|
||||
* @memberof ClassificationModelDrawCommand.prototype
|
||||
* @type {number[]}
|
||||
*
|
||||
* @readonly
|
||||
* @private
|
||||
*/
|
||||
batchLengths: {
|
||||
get: function () {
|
||||
return this._runtimePrimitive.batchLengths;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* The batch offsets used to generate multiple draw commands.
|
||||
*
|
||||
* @memberof ClassificationModelDrawCommand.prototype
|
||||
* @type {number[]}
|
||||
*
|
||||
* @readonly
|
||||
* @private
|
||||
*/
|
||||
batchOffsets: {
|
||||
get: function () {
|
||||
return this._runtimePrimitive.batchOffsets;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* The model that the draw command belongs to.
|
||||
*
|
||||
* @memberof ClassificationModelDrawCommand.prototype
|
||||
* @type {Model}
|
||||
*
|
||||
* @readonly
|
||||
* @private
|
||||
*/
|
||||
model: {
|
||||
get: function () {
|
||||
return this._model;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* The classification type of the model that this draw command belongs to.
|
||||
*
|
||||
* @memberof ClassificationModelDrawCommand.prototype
|
||||
* @type {ClassificationType}
|
||||
*
|
||||
* @readonly
|
||||
* @private
|
||||
*/
|
||||
classificationType: {
|
||||
get: function () {
|
||||
return this._classificationType;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* The current model matrix applied to the draw commands.
|
||||
*
|
||||
* @memberof ClassificationModelDrawCommand.prototype
|
||||
* @type {Matrix4}
|
||||
*
|
||||
* @readonly
|
||||
* @private
|
||||
*/
|
||||
modelMatrix: {
|
||||
get: function () {
|
||||
return this._modelMatrix;
|
||||
},
|
||||
set: function (value) {
|
||||
this._modelMatrix = Matrix4.clone(value, this._modelMatrix);
|
||||
const boundingSphere = this._runtimePrimitive.boundingSphere;
|
||||
this._boundingVolume = BoundingSphere.transform(
|
||||
boundingSphere,
|
||||
this._modelMatrix,
|
||||
this._boundingVolume,
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* The bounding volume of the main draw command. This is equivalent
|
||||
* to the primitive's bounding sphere transformed by the draw
|
||||
* command's model matrix.
|
||||
*
|
||||
* @memberof ClassificationModelDrawCommand.prototype
|
||||
* @type {BoundingSphere}
|
||||
*
|
||||
* @readonly
|
||||
* @private
|
||||
*/
|
||||
boundingVolume: {
|
||||
get: function () {
|
||||
return this._boundingVolume;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Culling is disabled for classification models, so this has no effect on
|
||||
* how the model renders. This only exists to match the interface of
|
||||
* {@link ModelDrawCommand}.
|
||||
*
|
||||
* @memberof ClassificationModelDrawCommand.prototype
|
||||
* @type {CullFace}
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
cullFace: {
|
||||
get: function () {
|
||||
return this._cullFace;
|
||||
},
|
||||
set: function (value) {
|
||||
this._cullFace = value;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Pushes the draw commands necessary to render the primitive.
|
||||
*
|
||||
* @param {FrameState} frameState The frame state.
|
||||
* @param {DrawCommand[]} result The array to push the draw commands to.
|
||||
*
|
||||
* @returns {DrawCommand[]} The modified result parameter.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
ClassificationModelDrawCommand.prototype.pushCommands = function (
|
||||
frameState,
|
||||
result,
|
||||
) {
|
||||
const passes = frameState.passes;
|
||||
if (passes.render) {
|
||||
if (this._useDebugWireframe) {
|
||||
addAllToArray(result, this._commandListDebugWireframe);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._classifiesTerrain) {
|
||||
addAllToArray(result, this._commandListTerrain);
|
||||
}
|
||||
|
||||
if (this._classifies3DTiles) {
|
||||
addAllToArray(result, this._commandList3DTiles);
|
||||
}
|
||||
|
||||
const useIgnoreShowCommands =
|
||||
frameState.invertClassification && this._classifies3DTiles;
|
||||
|
||||
if (useIgnoreShowCommands) {
|
||||
if (this._commandListIgnoreShow.length === 0) {
|
||||
const pass = Pass.CESIUM_3D_TILE_CLASSIFICATION_IGNORE_SHOW;
|
||||
const command = deriveStencilDepthCommand(this._command, pass);
|
||||
|
||||
const derivedCommands = scratchDerivedCommands;
|
||||
derivedCommands.length = 0;
|
||||
derivedCommands.push(command);
|
||||
|
||||
this._commandListIgnoreShow = createBatchCommands(
|
||||
this,
|
||||
derivedCommands,
|
||||
this._commandListIgnoreShow,
|
||||
);
|
||||
}
|
||||
|
||||
addAllToArray(result, this._commandListIgnoreShow);
|
||||
}
|
||||
}
|
||||
|
||||
if (passes.pick) {
|
||||
if (this._classifiesTerrain) {
|
||||
addAllToArray(result, this._commandListTerrainPicking);
|
||||
}
|
||||
|
||||
if (this._classifies3DTiles) {
|
||||
addAllToArray(result, this._commandList3DTilesPicking);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
export default ClassificationModelDrawCommand;
|
||||
Reference in New Issue
Block a user