Add existing to tracked
This commit is contained in:
+381
@@ -0,0 +1,381 @@
|
||||
import Check from "../../Core/Check.js";
|
||||
import Frozen from "../../Core/Frozen.js";
|
||||
import defined from "../../Core/defined.js";
|
||||
import PrimitiveType from "../../Core/PrimitiveType.js";
|
||||
import SceneMode from "../SceneMode.js";
|
||||
import AlphaPipelineStage from "./AlphaPipelineStage.js";
|
||||
import BatchTexturePipelineStage from "./BatchTexturePipelineStage.js";
|
||||
import ClassificationPipelineStage from "./ClassificationPipelineStage.js";
|
||||
import CPUStylingPipelineStage from "./CPUStylingPipelineStage.js";
|
||||
import CustomShaderMode from "./CustomShaderMode.js";
|
||||
import CustomShaderPipelineStage from "./CustomShaderPipelineStage.js";
|
||||
import DequantizationPipelineStage from "./DequantizationPipelineStage.js";
|
||||
import EdgeDetectionPipelineStage from "./EdgeDetectionPipelineStage.js";
|
||||
import EdgeVisibilityPipelineStage from "./EdgeVisibilityPipelineStage.js";
|
||||
import FeatureIdPipelineStage from "./FeatureIdPipelineStage.js";
|
||||
import GeometryPipelineStage from "./GeometryPipelineStage.js";
|
||||
import ImageryPipelineStage from "./ImageryPipelineStage.js";
|
||||
import LightingPipelineStage from "./LightingPipelineStage.js";
|
||||
import MaterialPipelineStage from "./MaterialPipelineStage.js";
|
||||
import MetadataPickingPipelineStage from "./MetadataPickingPipelineStage.js";
|
||||
import MetadataPipelineStage from "./MetadataPipelineStage.js";
|
||||
import ModelUtility from "./ModelUtility.js";
|
||||
import MorphTargetsPipelineStage from "./MorphTargetsPipelineStage.js";
|
||||
import PickingPipelineStage from "./PickingPipelineStage.js";
|
||||
import PointCloudStylingPipelineStage from "./PointCloudStylingPipelineStage.js";
|
||||
import PrimitiveOutlinePipelineStage from "./PrimitiveOutlinePipelineStage.js";
|
||||
import PrimitiveStatisticsPipelineStage from "./PrimitiveStatisticsPipelineStage.js";
|
||||
import SceneMode2DPipelineStage from "./SceneMode2DPipelineStage.js";
|
||||
import SelectedFeatureIdPipelineStage from "./SelectedFeatureIdPipelineStage.js";
|
||||
import SkinningPipelineStage from "./SkinningPipelineStage.js";
|
||||
import VerticalExaggerationPipelineStage from "./VerticalExaggerationPipelineStage.js";
|
||||
import WireframePipelineStage from "./WireframePipelineStage.js";
|
||||
import oneTimeWarning from "../../Core/oneTimeWarning.js";
|
||||
|
||||
/**
|
||||
* In memory representation of a single primitive, that is, a primitive
|
||||
* and its corresponding mesh.
|
||||
*
|
||||
* @param {object} options An object containing the following options:
|
||||
* @param {ModelComponents.Primitive} options.primitive The primitive component.
|
||||
* @param {ModelComponents.Node} options.node The node that this primitive belongs to.
|
||||
* @param {Model} options.model The {@link Model} this primitive belongs to.
|
||||
*
|
||||
* @alias ModelRuntimePrimitive
|
||||
* @constructor
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function ModelRuntimePrimitive(options) {
|
||||
options = options ?? Frozen.EMPTY_OBJECT;
|
||||
|
||||
const primitive = options.primitive;
|
||||
const node = options.node;
|
||||
const model = options.model;
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
Check.typeOf.object("options.primitive", primitive);
|
||||
Check.typeOf.object("options.node", node);
|
||||
Check.typeOf.object("options.model", model);
|
||||
//>>includeEnd('debug');
|
||||
|
||||
/**
|
||||
* The primitive component associated with this primitive.
|
||||
*
|
||||
* @type {ModelComponents.Primitive}
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
this.primitive = primitive;
|
||||
|
||||
/**
|
||||
* A reference to the node this primitive belongs to.
|
||||
*
|
||||
* @type {ModelComponents.Node}
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
this.node = node;
|
||||
|
||||
/**
|
||||
* A reference to the model
|
||||
*
|
||||
* @type {Model}
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
this.model = model;
|
||||
|
||||
/**
|
||||
* Pipeline stages to apply to this primitive. This
|
||||
* is an array of classes, each with a static method called
|
||||
* <code>process()</code>
|
||||
*
|
||||
* @type {object[]}
|
||||
* @readonly
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
this.pipelineStages = [];
|
||||
|
||||
/**
|
||||
* The generated {@link ModelDrawCommand} or {@link ClassificationModelDrawCommand}
|
||||
* associated with this primitive.
|
||||
*
|
||||
* @type {ModelDrawCommand|ClassificationModelDrawCommand}
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
this.drawCommand = undefined;
|
||||
|
||||
/**
|
||||
* The bounding sphere of this primitive in object-space.
|
||||
*
|
||||
* @type {BoundingSphere}
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
this.boundingSphere = undefined;
|
||||
|
||||
/**
|
||||
* The bounding sphere of this primitive in 2D world space.
|
||||
*
|
||||
* @type {BoundingSphere}
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
this.boundingSphere2D = undefined;
|
||||
|
||||
/**
|
||||
* A buffer containing the primitive's positions projected to 2D world
|
||||
* coordinates. This is generated by SceneMode2DPipelineStage and used for
|
||||
* rendering in 2D / CV mode. The memory is managed by Model; this is just
|
||||
* a reference.
|
||||
*
|
||||
* @type {Buffer}
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
this.positionBuffer2D = undefined;
|
||||
|
||||
/**
|
||||
* An array containing the lengths of the vertex batches for classification.
|
||||
* Vertices with the same feature ID are batched together, and each batch is
|
||||
* drawn with a different draw command in order to properly classify other
|
||||
* assets.
|
||||
* <p>
|
||||
* This is generated by ClassificationPipelineStage. The memory is managed by
|
||||
* Model; this is just a reference.
|
||||
* </p>
|
||||
*
|
||||
* @type {number[]}
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
this.batchLengths = undefined;
|
||||
|
||||
/**
|
||||
* An array containing the offsets of the vertex batches for classification.
|
||||
* Vertices with the same feature ID are batched together, and each batch is
|
||||
* drawn with a different draw command in order to properly classify other
|
||||
* assets.
|
||||
* <p>
|
||||
* This is generated by ClassificationPipelineStage. The memory is managed by
|
||||
* Model; this is just a reference.
|
||||
* </p>
|
||||
*
|
||||
* @type {number[]}
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
this.batchOffsets = undefined;
|
||||
|
||||
/**
|
||||
* Update stages to apply to this primitive.
|
||||
*
|
||||
* @type {object[]}
|
||||
* @readonly
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
this.updateStages = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the primitive pipeline stages. If the pipeline needs to be re-run,
|
||||
* call this method again to ensure the correct sequence of pipeline stages are
|
||||
* used.
|
||||
*
|
||||
* @param {FrameState} frameState The frame state.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
ModelRuntimePrimitive.prototype.configurePipeline = function (frameState) {
|
||||
const pipelineStages = this.pipelineStages;
|
||||
pipelineStages.length = 0;
|
||||
|
||||
const primitive = this.primitive;
|
||||
const node = this.node;
|
||||
const model = this.model;
|
||||
|
||||
const customShader = model.customShader;
|
||||
const style = model.style;
|
||||
|
||||
const useWebgl2 = frameState.context.webgl2;
|
||||
const mode = frameState.mode;
|
||||
const use2D =
|
||||
mode !== SceneMode.SCENE3D && !frameState.scene3DOnly && model._projectTo2D;
|
||||
const hasVerticalExaggeration =
|
||||
frameState.verticalExaggeration !== 1.0 && model.hasVerticalExaggeration;
|
||||
|
||||
const hasMorphTargets =
|
||||
defined(primitive.morphTargets) && primitive.morphTargets.length > 0;
|
||||
const hasSkinning = defined(node.skin);
|
||||
|
||||
// Check whether the model is part of a `Model3DTileContent` that
|
||||
// belongs to a tileset that has imagery layers. If this is the
|
||||
// case, then the `ImageryPipelineStage` will be required.
|
||||
const hasImageryLayers =
|
||||
defined(model.imageryLayers) && model.imageryLayers.length > 0;
|
||||
|
||||
const hasCustomShader = defined(customShader);
|
||||
const hasCustomFragmentShader =
|
||||
hasCustomShader && defined(customShader.fragmentShaderText);
|
||||
const materialsEnabled =
|
||||
!hasCustomFragmentShader ||
|
||||
customShader.mode !== CustomShaderMode.REPLACE_MATERIAL;
|
||||
const hasQuantization = ModelUtility.hasQuantizedAttributes(
|
||||
primitive.attributes,
|
||||
);
|
||||
|
||||
const generateWireframeIndices =
|
||||
model.debugWireframe &&
|
||||
PrimitiveType.isTriangles(primitive.primitiveType) &&
|
||||
// Generating index buffers for wireframes is always possible in WebGL2.
|
||||
// However, this will only work in WebGL1 if the model was constructed with
|
||||
// enableDebugWireframe set to true.
|
||||
(model._enableDebugWireframe || useWebgl2);
|
||||
|
||||
const pointCloudShading = model.pointCloudShading;
|
||||
const hasAttenuation =
|
||||
defined(pointCloudShading) && pointCloudShading.attenuation;
|
||||
const hasPointCloudBackFaceCulling =
|
||||
defined(pointCloudShading) && pointCloudShading.backFaceCulling;
|
||||
const hasPointCloudStyle =
|
||||
primitive.primitiveType === PrimitiveType.POINTS &&
|
||||
(defined(style) || hasAttenuation || hasPointCloudBackFaceCulling);
|
||||
|
||||
const hasOutlines =
|
||||
model._enableShowOutline && defined(primitive.outlineCoordinates);
|
||||
|
||||
const hasEdgeVisibility = defined(primitive.edgeVisibility);
|
||||
|
||||
const featureIdFlags = inspectFeatureIds(model, node, primitive);
|
||||
|
||||
const hasClassification = defined(model.classificationType);
|
||||
|
||||
// Start of pipeline -----------------------------------------------------
|
||||
if (use2D) {
|
||||
pipelineStages.push(SceneMode2DPipelineStage);
|
||||
}
|
||||
|
||||
pipelineStages.push(GeometryPipelineStage);
|
||||
|
||||
if (generateWireframeIndices) {
|
||||
pipelineStages.push(WireframePipelineStage);
|
||||
}
|
||||
|
||||
if (hasClassification) {
|
||||
pipelineStages.push(ClassificationPipelineStage);
|
||||
}
|
||||
|
||||
if (hasMorphTargets) {
|
||||
pipelineStages.push(MorphTargetsPipelineStage);
|
||||
}
|
||||
|
||||
if (hasSkinning) {
|
||||
pipelineStages.push(SkinningPipelineStage);
|
||||
}
|
||||
|
||||
if (hasPointCloudStyle) {
|
||||
pipelineStages.push(PointCloudStylingPipelineStage);
|
||||
}
|
||||
|
||||
if (hasQuantization) {
|
||||
pipelineStages.push(DequantizationPipelineStage);
|
||||
}
|
||||
|
||||
if (hasImageryLayers) {
|
||||
if (hasOutlines) {
|
||||
oneTimeWarning(
|
||||
"outlines-and-draping",
|
||||
"Primitive outlines disable imagery draping",
|
||||
);
|
||||
} else {
|
||||
pipelineStages.push(ImageryPipelineStage);
|
||||
}
|
||||
}
|
||||
|
||||
if (materialsEnabled) {
|
||||
pipelineStages.push(MaterialPipelineStage);
|
||||
}
|
||||
|
||||
// These stages are always run to ensure structs
|
||||
// are declared to avoid compilation errors.
|
||||
pipelineStages.push(FeatureIdPipelineStage);
|
||||
pipelineStages.push(MetadataPipelineStage);
|
||||
pipelineStages.push(MetadataPickingPipelineStage);
|
||||
|
||||
if (featureIdFlags.hasPropertyTable) {
|
||||
pipelineStages.push(SelectedFeatureIdPipelineStage);
|
||||
pipelineStages.push(BatchTexturePipelineStage);
|
||||
pipelineStages.push(CPUStylingPipelineStage);
|
||||
}
|
||||
|
||||
if (hasVerticalExaggeration) {
|
||||
pipelineStages.push(VerticalExaggerationPipelineStage);
|
||||
}
|
||||
|
||||
if (hasCustomShader) {
|
||||
pipelineStages.push(CustomShaderPipelineStage);
|
||||
}
|
||||
|
||||
pipelineStages.push(LightingPipelineStage);
|
||||
|
||||
if (model.allowPicking) {
|
||||
pipelineStages.push(PickingPipelineStage);
|
||||
}
|
||||
|
||||
if (hasOutlines) {
|
||||
pipelineStages.push(PrimitiveOutlinePipelineStage);
|
||||
}
|
||||
|
||||
if (hasEdgeVisibility) {
|
||||
// Indicate to Scene (after primitive updates) that the edge MRT should be enabled.
|
||||
frameState.edgeVisibilityRequested = true;
|
||||
pipelineStages.push(EdgeVisibilityPipelineStage);
|
||||
pipelineStages.push(EdgeDetectionPipelineStage);
|
||||
}
|
||||
|
||||
pipelineStages.push(AlphaPipelineStage);
|
||||
|
||||
pipelineStages.push(PrimitiveStatisticsPipelineStage);
|
||||
|
||||
return;
|
||||
};
|
||||
|
||||
function inspectFeatureIds(model, node, primitive) {
|
||||
let featureIds;
|
||||
// Check instances first, as this is the most specific type of
|
||||
// feature ID
|
||||
if (defined(node.instances)) {
|
||||
featureIds = ModelUtility.getFeatureIdsByLabel(
|
||||
node.instances.featureIds,
|
||||
model.instanceFeatureIdLabel,
|
||||
);
|
||||
|
||||
if (defined(featureIds)) {
|
||||
return {
|
||||
hasFeatureIds: true,
|
||||
hasPropertyTable: defined(featureIds.propertyTableId),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
featureIds = ModelUtility.getFeatureIdsByLabel(
|
||||
primitive.featureIds,
|
||||
model.featureIdLabel,
|
||||
);
|
||||
if (defined(featureIds)) {
|
||||
return {
|
||||
hasFeatureIds: true,
|
||||
hasPropertyTable: defined(featureIds.propertyTableId),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
hasFeatureIds: false,
|
||||
hasPropertyTable: false,
|
||||
};
|
||||
}
|
||||
|
||||
export default ModelRuntimePrimitive;
|
||||
Reference in New Issue
Block a user