123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533 |
- import BoundingSphere from "../../Core/BoundingSphere.js";
- import Check from "../../Core/Check.js";
- import defaultValue from "../../Core/defaultValue.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 = defaultValue(options, defaultValue.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) {
- result.push.apply(result, this._commandListDebugWireframe);
- return;
- }
- if (this._classifiesTerrain) {
- result.push.apply(result, this._commandListTerrain);
- }
- if (this._classifies3DTiles) {
- result.push.apply(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
- );
- }
- result.push.apply(result, this._commandListIgnoreShow);
- }
- }
- if (passes.pick) {
- if (this._classifiesTerrain) {
- result.push.apply(result, this._commandListTerrainPicking);
- }
- if (this._classifies3DTiles) {
- result.push.apply(result, this._commandList3DTilesPicking);
- }
- }
- return result;
- };
- export default ClassificationModelDrawCommand;
|