UNPKG

@cesium/engine

Version:

CesiumJS is a JavaScript library for creating 3D globes and 2D maps in a web browser without a plugin.

133 lines (111 loc) 3.97 kB
import defined from "../../Core/defined.js"; import RuntimeError from "../../Core/RuntimeError.js"; import ShaderDestination from "../../Renderer/ShaderDestination.js"; import VertexAttributeSemantic from "../VertexAttributeSemantic.js"; import ModelUtility from "./ModelUtility.js"; /** * The classification pipeline stage is responsible for batching features * together to be rendered by the {@link ClassificationModelDrawCommand}. * * @namespace ClassificationPipelineStage * * @private */ const ClassificationPipelineStage = { name: "ClassificationPipelineStage", // Helps with debugging }; /** * Process a primitive. This modifies the following parts of the render resources: * * <ul> * <li>adds a define to the shader to indicate that the primitive classifies other assets</li> * <li>adds arrays containing batch lengths and offsets to the primitive's resources * </ul> * * <p> * See {@link ClassificationModelDrawCommand} for the use of the batch offsets and lengths. * </p> * * @param {PrimitiveRenderResources} renderResources The render resources for this primitive. * @param {ModelComponents.Primitive} primitive The primitive. * @param {FrameState} frameState The frame state. * * @private */ ClassificationPipelineStage.process = function ( renderResources, primitive, frameState, ) { const shaderBuilder = renderResources.shaderBuilder; shaderBuilder.addDefine( "HAS_CLASSIFICATION", undefined, ShaderDestination.BOTH, ); const runtimePrimitive = renderResources.runtimePrimitive; if (!defined(runtimePrimitive.batchLengths)) { createClassificationBatches(primitive, runtimePrimitive); } }; function createClassificationBatches(primitive, runtimePrimitive) { const positionAttribute = ModelUtility.getAttributeBySemantic( primitive, VertexAttributeSemantic.POSITION, ); if (!defined(positionAttribute)) { throw new RuntimeError( "Primitives must have a position attribute to be used for classification.", ); } let indicesArray; const indices = primitive.indices; const hasIndices = defined(indices); if (hasIndices) { indicesArray = indices.typedArray; // Unload the typed array. This is just a pointer to the array in // the index buffer loader. indices.typedArray = undefined; } const count = hasIndices ? indices.count : positionAttribute.count; const featureIdAttribute = ModelUtility.getAttributeBySemantic( primitive, VertexAttributeSemantic.FEATURE_ID, 0, ); // If there are no feature IDs, render the primitive in a single batch. if (!defined(featureIdAttribute)) { runtimePrimitive.batchLengths = [count]; runtimePrimitive.batchOffsets = [0]; return; } const featureIds = featureIdAttribute.typedArray; // Unload the typed array. This is just a pointer to the array in // the vertex buffer loader, so if the typed array is shared by // multiple primitives (i.e. multiple instances of the same mesh), // this will not affect the other primitives. featureIdAttribute.typedArray = undefined; const batchLengths = []; const batchOffsets = [0]; const firstIndex = hasIndices ? indicesArray[0] : 0; let currentBatchId = featureIds[firstIndex]; let currentOffset = 0; for (let i = 1; i < count; i++) { const index = hasIndices ? indicesArray[i] : i; const batchId = featureIds[index]; if (batchId !== currentBatchId) { // Store the length of this batch and begin counting the next one. const batchLength = i - currentOffset; const newOffset = i; batchLengths.push(batchLength); batchOffsets.push(newOffset); currentOffset = newOffset; currentBatchId = batchId; } } const finalBatchLength = count - currentOffset; batchLengths.push(finalBatchLength); runtimePrimitive.batchLengths = batchLengths; runtimePrimitive.batchOffsets = batchOffsets; } export default ClassificationPipelineStage;