1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282 |
- import Cartesian3 from "../Core/Cartesian3.js";
- import Color from "../Core/Color.js";
- import ComponentDatatype from "../Core/ComponentDatatype.js";
- import defaultValue from "../Core/defaultValue.js";
- import defined from "../Core/defined.js";
- import destroyObject from "../Core/destroyObject.js";
- import IndexDatatype from "../Core/IndexDatatype.js";
- import Matrix4 from "../Core/Matrix4.js";
- import PrimitiveType from "../Core/PrimitiveType.js";
- import Buffer from "../Renderer/Buffer.js";
- import BufferUsage from "../Renderer/BufferUsage.js";
- import DrawCommand from "../Renderer/DrawCommand.js";
- import Pass from "../Renderer/Pass.js";
- import RenderState from "../Renderer/RenderState.js";
- import ShaderProgram from "../Renderer/ShaderProgram.js";
- import ShaderSource from "../Renderer/ShaderSource.js";
- import VertexArray from "../Renderer/VertexArray.js";
- import ShadowVolumeFS from "../Shaders/ShadowVolumeFS.js";
- import VectorTileVS from "../Shaders/VectorTileVS.js";
- import BlendingState from "./BlendingState.js";
- import Cesium3DTileFeature from "./Cesium3DTileFeature.js";
- import ClassificationType from "./ClassificationType.js";
- import DepthFunction from "./DepthFunction.js";
- import Expression from "./Expression.js";
- import StencilConstants from "./StencilConstants.js";
- import StencilFunction from "./StencilFunction.js";
- import StencilOperation from "./StencilOperation.js";
- import Vector3DTileBatch from "./Vector3DTileBatch.js";
- /**
- * Creates a batch of classification meshes.
- *
- * @alias Vector3DTilePrimitive
- * @constructor
- *
- * @param {Object} options An object with following properties:
- * @param {Float32Array} options.positions The positions of the meshes.
- * @param {Uint16Array|Uint32Array} options.indices The indices of the triangulated meshes. The indices must be contiguous so that
- * the indices for mesh n are in [i, i + indexCounts[n]] where i = sum{indexCounts[0], indexCounts[n - 1]}.
- * @param {Uint32Array} options.indexCounts The number of indices for each mesh.
- * @param {Uint32Array} options.indexOffsets The offset into the index buffer for each mesh.
- * @param {Vector3DTileBatch[]} options.batchedIndices The index offset and count for each batch with the same color.
- * @param {Cartesian3} [options.center=Cartesian3.ZERO] The RTC center.
- * @param {Cesium3DTileBatchTable} options.batchTable The batch table for the tile containing the batched meshes.
- * @param {Uint16Array} options.batchIds The batch ids for each mesh.
- * @param {Uint16Array} options.vertexBatchIds The batch id for each vertex.
- * @param {BoundingSphere} options.boundingVolume The bounding volume for the entire batch of meshes.
- * @param {BoundingSphere[]} options.boundingVolumes The bounding volume for each mesh.
- * @param {ClassificationType} [options.classificationType] What this tile will classify.
- *
- * @private
- */
- function Vector3DTilePrimitive(options) {
- options = defaultValue(options, defaultValue.EMPTY_OBJECT);
- this._batchTable = options.batchTable;
- this._batchIds = options.batchIds;
- // These arrays are released after VAO creation.
- this._positions = options.positions;
- this._vertexBatchIds = options.vertexBatchIds;
- // These arrays are kept for re-batching indices based on colors.
- // If WebGL 2 is supported, indices will be released and re-batching uses buffer-to-buffer copies.
- this._indices = options.indices;
- this._indexCounts = options.indexCounts;
- this._indexOffsets = options.indexOffsets;
- this._batchedIndices = options.batchedIndices;
- this._boundingVolume = options.boundingVolume;
- this._boundingVolumes = options.boundingVolumes;
- this._center = defaultValue(options.center, Cartesian3.ZERO);
- this._va = undefined;
- this._sp = undefined;
- this._spStencil = undefined;
- this._spPick = undefined;
- this._uniformMap = undefined;
- // Only used with WebGL 2 to ping-pong ibos after copy.
- this._vaSwap = undefined;
- this._rsStencilDepthPass = undefined;
- this._rsStencilDepthPass3DTiles = undefined;
- this._rsColorPass = undefined;
- this._rsPickPass = undefined;
- this._rsWireframe = undefined;
- this._commands = [];
- this._commandsIgnoreShow = [];
- this._pickCommands = [];
- this._constantColor = Color.clone(Color.WHITE);
- this._highlightColor = this._constantColor;
- this._batchDirty = true;
- this._pickCommandsDirty = true;
- this._framesSinceLastRebatch = 0;
- this._updatingAllCommands = false;
- this._trianglesLength = this._indices.length / 3;
- this._geometryByteLength =
- this._indices.byteLength +
- this._positions.byteLength +
- this._vertexBatchIds.byteLength;
- /**
- * Draw the wireframe of the classification meshes.
- * @type {Boolean}
- * @default false
- */
- this.debugWireframe = false;
- this._debugWireframe = this.debugWireframe;
- this._wireframeDirty = false;
- /**
- * Forces a re-batch instead of waiting after a number of frames have been rendered. For testing only.
- * @type {Boolean}
- * @default false
- */
- this.forceRebatch = false;
- /**
- * What this tile will classify.
- * @type {ClassificationType}
- * @default ClassificationType.BOTH
- */
- this.classificationType = defaultValue(
- options.classificationType,
- ClassificationType.BOTH
- );
- // Hidden options
- this._vertexShaderSource = options._vertexShaderSource;
- this._fragmentShaderSource = options._fragmentShaderSource;
- this._attributeLocations = options._attributeLocations;
- this._uniformMap = options._uniformMap;
- this._pickId = options._pickId;
- this._modelMatrix = options._modelMatrix;
- this._boundingSphere = options._boundingSphere;
- this._batchIdLookUp = {};
- const length = this._batchIds.length;
- for (let i = 0; i < length; ++i) {
- const batchId = this._batchIds[i];
- this._batchIdLookUp[batchId] = i;
- }
- }
- Object.defineProperties(Vector3DTilePrimitive.prototype, {
- /**
- * Gets the number of triangles.
- *
- * @memberof Vector3DTilePrimitive.prototype
- *
- * @type {Number}
- * @readonly
- */
- trianglesLength: {
- get: function () {
- return this._trianglesLength;
- },
- },
- /**
- * Gets the geometry memory in bytes.
- *
- * @memberof Vector3DTilePrimitive.prototype
- *
- * @type {Number}
- * @readonly
- */
- geometryByteLength: {
- get: function () {
- return this._geometryByteLength;
- },
- },
- });
- const defaultAttributeLocations = {
- position: 0,
- a_batchId: 1,
- };
- function createVertexArray(primitive, context) {
- if (defined(primitive._va)) {
- return;
- }
- const positionBuffer = Buffer.createVertexBuffer({
- context: context,
- typedArray: primitive._positions,
- usage: BufferUsage.STATIC_DRAW,
- });
- const idBuffer = Buffer.createVertexBuffer({
- context: context,
- typedArray: primitive._vertexBatchIds,
- usage: BufferUsage.STATIC_DRAW,
- });
- const indexBuffer = Buffer.createIndexBuffer({
- context: context,
- typedArray: primitive._indices,
- usage: BufferUsage.DYNAMIC_DRAW,
- indexDatatype:
- primitive._indices.BYTES_PER_ELEMENT === 2
- ? IndexDatatype.UNSIGNED_SHORT
- : IndexDatatype.UNSIGNED_INT,
- });
- const vertexAttributes = [
- {
- index: 0,
- vertexBuffer: positionBuffer,
- componentDatatype: ComponentDatatype.fromTypedArray(primitive._positions),
- componentsPerAttribute: 3,
- },
- {
- index: 1,
- vertexBuffer: idBuffer,
- componentDatatype: ComponentDatatype.fromTypedArray(
- primitive._vertexBatchIds
- ),
- componentsPerAttribute: 1,
- },
- ];
- primitive._va = new VertexArray({
- context: context,
- attributes: vertexAttributes,
- indexBuffer: indexBuffer,
- });
- if (context.webgl2) {
- primitive._vaSwap = new VertexArray({
- context: context,
- attributes: vertexAttributes,
- indexBuffer: Buffer.createIndexBuffer({
- context: context,
- sizeInBytes: indexBuffer.sizeInBytes,
- usage: BufferUsage.DYNAMIC_DRAW,
- indexDatatype: indexBuffer.indexDatatype,
- }),
- });
- }
- primitive._batchedPositions = undefined;
- primitive._transferrableBatchIds = undefined;
- primitive._vertexBatchIds = undefined;
- primitive._verticesPromise = undefined;
- }
- function createShaders(primitive, context) {
- if (defined(primitive._sp)) {
- return;
- }
- const batchTable = primitive._batchTable;
- const attributeLocations = defaultValue(
- primitive._attributeLocations,
- defaultAttributeLocations
- );
- let pickId = primitive._pickId;
- const vertexShaderSource = primitive._vertexShaderSource;
- let fragmentShaderSource = primitive._fragmentShaderSource;
- if (defined(vertexShaderSource)) {
- primitive._sp = ShaderProgram.fromCache({
- context: context,
- vertexShaderSource: vertexShaderSource,
- fragmentShaderSource: fragmentShaderSource,
- attributeLocations: attributeLocations,
- });
- primitive._spStencil = primitive._sp;
- fragmentShaderSource = ShaderSource.replaceMain(
- fragmentShaderSource,
- "czm_non_pick_main"
- );
- fragmentShaderSource =
- `${fragmentShaderSource}void main() \n` +
- `{ \n` +
- ` czm_non_pick_main(); \n` +
- ` gl_FragColor = ${pickId}; \n` +
- `} \n`;
- primitive._spPick = ShaderProgram.fromCache({
- context: context,
- vertexShaderSource: vertexShaderSource,
- fragmentShaderSource: fragmentShaderSource,
- attributeLocations: attributeLocations,
- });
- return;
- }
- const vsSource = batchTable.getVertexShaderCallback(
- false,
- "a_batchId",
- undefined
- )(VectorTileVS);
- let fsSource = batchTable.getFragmentShaderCallback(
- false,
- undefined,
- true
- )(ShadowVolumeFS);
- pickId = batchTable.getPickId();
- let vs = new ShaderSource({
- sources: [vsSource],
- });
- let fs = new ShaderSource({
- defines: ["VECTOR_TILE"],
- sources: [fsSource],
- });
- primitive._sp = ShaderProgram.fromCache({
- context: context,
- vertexShaderSource: vs,
- fragmentShaderSource: fs,
- attributeLocations: attributeLocations,
- });
- vs = new ShaderSource({
- sources: [VectorTileVS],
- });
- fs = new ShaderSource({
- defines: ["VECTOR_TILE"],
- sources: [ShadowVolumeFS],
- });
- primitive._spStencil = ShaderProgram.fromCache({
- context: context,
- vertexShaderSource: vs,
- fragmentShaderSource: fs,
- attributeLocations: attributeLocations,
- });
- fsSource = ShaderSource.replaceMain(fsSource, "czm_non_pick_main");
- fsSource =
- `${fsSource}\n` +
- `void main() \n` +
- `{ \n` +
- ` czm_non_pick_main(); \n` +
- ` gl_FragColor = ${pickId}; \n` +
- `} \n`;
- const pickVS = new ShaderSource({
- sources: [vsSource],
- });
- const pickFS = new ShaderSource({
- defines: ["VECTOR_TILE"],
- sources: [fsSource],
- });
- primitive._spPick = ShaderProgram.fromCache({
- context: context,
- vertexShaderSource: pickVS,
- fragmentShaderSource: pickFS,
- attributeLocations: attributeLocations,
- });
- }
- function getStencilDepthRenderState(mask3DTiles) {
- const stencilFunction = mask3DTiles
- ? StencilFunction.EQUAL
- : StencilFunction.ALWAYS;
- 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,
- };
- function createRenderStates(primitive) {
- if (defined(primitive._rsStencilDepthPass)) {
- return;
- }
- primitive._rsStencilDepthPass = RenderState.fromCache(
- getStencilDepthRenderState(false)
- );
- primitive._rsStencilDepthPass3DTiles = RenderState.fromCache(
- getStencilDepthRenderState(true)
- );
- primitive._rsColorPass = RenderState.fromCache(colorRenderState);
- primitive._rsPickPass = RenderState.fromCache(pickRenderState);
- }
- const modifiedModelViewScratch = new Matrix4();
- const rtcScratch = new Cartesian3();
- function createUniformMap(primitive, context) {
- if (defined(primitive._uniformMap)) {
- return;
- }
- const uniformMap = {
- u_modifiedModelViewProjection: function () {
- const viewMatrix = context.uniformState.view;
- const projectionMatrix = context.uniformState.projection;
- Matrix4.clone(viewMatrix, modifiedModelViewScratch);
- Matrix4.multiplyByPoint(
- modifiedModelViewScratch,
- primitive._center,
- rtcScratch
- );
- Matrix4.setTranslation(
- modifiedModelViewScratch,
- rtcScratch,
- modifiedModelViewScratch
- );
- Matrix4.multiply(
- projectionMatrix,
- modifiedModelViewScratch,
- modifiedModelViewScratch
- );
- return modifiedModelViewScratch;
- },
- u_highlightColor: function () {
- return primitive._highlightColor;
- },
- };
- primitive._uniformMap = primitive._batchTable.getUniformMapCallback()(
- uniformMap
- );
- }
- function copyIndicesCPU(
- indices,
- newIndices,
- currentOffset,
- offsets,
- counts,
- batchIds,
- batchIdLookUp
- ) {
- const sizeInBytes = indices.constructor.BYTES_PER_ELEMENT;
- const batchedIdsLength = batchIds.length;
- for (let j = 0; j < batchedIdsLength; ++j) {
- const batchedId = batchIds[j];
- const index = batchIdLookUp[batchedId];
- const offset = offsets[index];
- const count = counts[index];
- const subarray = new indices.constructor(
- indices.buffer,
- sizeInBytes * offset,
- count
- );
- newIndices.set(subarray, currentOffset);
- offsets[index] = currentOffset;
- currentOffset += count;
- }
- return currentOffset;
- }
- function rebatchCPU(primitive, batchedIndices) {
- const indices = primitive._indices;
- const indexOffsets = primitive._indexOffsets;
- const indexCounts = primitive._indexCounts;
- const batchIdLookUp = primitive._batchIdLookUp;
- const newIndices = new indices.constructor(indices.length);
- let current = batchedIndices.pop();
- const newBatchedIndices = [current];
- let currentOffset = copyIndicesCPU(
- indices,
- newIndices,
- 0,
- indexOffsets,
- indexCounts,
- current.batchIds,
- batchIdLookUp
- );
- current.offset = 0;
- current.count = currentOffset;
- while (batchedIndices.length > 0) {
- const next = batchedIndices.pop();
- if (Color.equals(next.color, current.color)) {
- currentOffset = copyIndicesCPU(
- indices,
- newIndices,
- currentOffset,
- indexOffsets,
- indexCounts,
- next.batchIds,
- batchIdLookUp
- );
- current.batchIds = current.batchIds.concat(next.batchIds);
- current.count = currentOffset - current.offset;
- } else {
- const offset = currentOffset;
- currentOffset = copyIndicesCPU(
- indices,
- newIndices,
- currentOffset,
- indexOffsets,
- indexCounts,
- next.batchIds,
- batchIdLookUp
- );
- next.offset = offset;
- next.count = currentOffset - offset;
- newBatchedIndices.push(next);
- current = next;
- }
- }
- primitive._va.indexBuffer.copyFromArrayView(newIndices);
- primitive._indices = newIndices;
- primitive._batchedIndices = newBatchedIndices;
- }
- function copyIndicesGPU(
- readBuffer,
- writeBuffer,
- currentOffset,
- offsets,
- counts,
- batchIds,
- batchIdLookUp
- ) {
- const sizeInBytes = readBuffer.bytesPerIndex;
- const batchedIdsLength = batchIds.length;
- for (let j = 0; j < batchedIdsLength; ++j) {
- const batchedId = batchIds[j];
- const index = batchIdLookUp[batchedId];
- const offset = offsets[index];
- const count = counts[index];
- writeBuffer.copyFromBuffer(
- readBuffer,
- offset * sizeInBytes,
- currentOffset * sizeInBytes,
- count * sizeInBytes
- );
- offsets[index] = currentOffset;
- currentOffset += count;
- }
- return currentOffset;
- }
- function rebatchGPU(primitive, batchedIndices) {
- const indexOffsets = primitive._indexOffsets;
- const indexCounts = primitive._indexCounts;
- const batchIdLookUp = primitive._batchIdLookUp;
- let current = batchedIndices.pop();
- const newBatchedIndices = [current];
- const readBuffer = primitive._va.indexBuffer;
- const writeBuffer = primitive._vaSwap.indexBuffer;
- let currentOffset = copyIndicesGPU(
- readBuffer,
- writeBuffer,
- 0,
- indexOffsets,
- indexCounts,
- current.batchIds,
- batchIdLookUp
- );
- current.offset = 0;
- current.count = currentOffset;
- while (batchedIndices.length > 0) {
- const next = batchedIndices.pop();
- if (Color.equals(next.color, current.color)) {
- currentOffset = copyIndicesGPU(
- readBuffer,
- writeBuffer,
- currentOffset,
- indexOffsets,
- indexCounts,
- next.batchIds,
- batchIdLookUp
- );
- current.batchIds = current.batchIds.concat(next.batchIds);
- current.count = currentOffset - current.offset;
- } else {
- const offset = currentOffset;
- currentOffset = copyIndicesGPU(
- readBuffer,
- writeBuffer,
- currentOffset,
- indexOffsets,
- indexCounts,
- next.batchIds,
- batchIdLookUp
- );
- next.offset = offset;
- next.count = currentOffset - offset;
- newBatchedIndices.push(next);
- current = next;
- }
- }
- const temp = primitive._va;
- primitive._va = primitive._vaSwap;
- primitive._vaSwap = temp;
- primitive._batchedIndices = newBatchedIndices;
- }
- function compareColors(a, b) {
- return b.color.toRgba() - a.color.toRgba();
- }
- // PERFORMANCE_IDEA: For WebGL 2, we can use copyBufferSubData for buffer-to-buffer copies.
- // PERFORMANCE_IDEA: Not supported, but we could use glMultiDrawElements here.
- function rebatchCommands(primitive, context) {
- if (!primitive._batchDirty) {
- return false;
- }
- const batchedIndices = primitive._batchedIndices;
- const length = batchedIndices.length;
- let needToRebatch = false;
- const colorCounts = {};
- for (let i = 0; i < length; ++i) {
- const color = batchedIndices[i].color;
- const rgba = color.toRgba();
- if (defined(colorCounts[rgba])) {
- needToRebatch = true;
- break;
- } else {
- colorCounts[rgba] = true;
- }
- }
- if (!needToRebatch) {
- primitive._batchDirty = false;
- return false;
- }
- if (
- needToRebatch &&
- !primitive.forceRebatch &&
- primitive._framesSinceLastRebatch < 120
- ) {
- ++primitive._framesSinceLastRebatch;
- return;
- }
- batchedIndices.sort(compareColors);
- if (context.webgl2) {
- rebatchGPU(primitive, batchedIndices);
- } else {
- rebatchCPU(primitive, batchedIndices);
- }
- primitive._framesSinceLastRebatch = 0;
- primitive._batchDirty = false;
- primitive._pickCommandsDirty = true;
- primitive._wireframeDirty = true;
- return true;
- }
- function createColorCommands(primitive, context) {
- const needsRebatch = rebatchCommands(primitive, context);
- const commands = primitive._commands;
- const batchedIndices = primitive._batchedIndices;
- const length = batchedIndices.length;
- const commandsLength = length * 2;
- if (
- defined(commands) &&
- !needsRebatch &&
- commands.length === commandsLength
- ) {
- return;
- }
- commands.length = commandsLength;
- const vertexArray = primitive._va;
- const sp = primitive._sp;
- const modelMatrix = defaultValue(primitive._modelMatrix, Matrix4.IDENTITY);
- const uniformMap = primitive._uniformMap;
- const bv = primitive._boundingVolume;
- for (let j = 0; j < length; ++j) {
- const offset = batchedIndices[j].offset;
- const count = batchedIndices[j].count;
- let stencilDepthCommand = commands[j * 2];
- if (!defined(stencilDepthCommand)) {
- stencilDepthCommand = commands[j * 2] = new DrawCommand({
- owner: primitive,
- });
- }
- stencilDepthCommand.vertexArray = vertexArray;
- stencilDepthCommand.modelMatrix = modelMatrix;
- stencilDepthCommand.offset = offset;
- stencilDepthCommand.count = count;
- stencilDepthCommand.renderState = primitive._rsStencilDepthPass;
- stencilDepthCommand.shaderProgram = sp;
- stencilDepthCommand.uniformMap = uniformMap;
- stencilDepthCommand.boundingVolume = bv;
- stencilDepthCommand.cull = false;
- stencilDepthCommand.pass = Pass.TERRAIN_CLASSIFICATION;
- const stencilDepthDerivedCommand = DrawCommand.shallowClone(
- stencilDepthCommand,
- stencilDepthCommand.derivedCommands.tileset
- );
- stencilDepthDerivedCommand.renderState =
- primitive._rsStencilDepthPass3DTiles;
- stencilDepthDerivedCommand.pass = Pass.CESIUM_3D_TILE_CLASSIFICATION;
- stencilDepthCommand.derivedCommands.tileset = stencilDepthDerivedCommand;
- let colorCommand = commands[j * 2 + 1];
- if (!defined(colorCommand)) {
- colorCommand = commands[j * 2 + 1] = new DrawCommand({
- owner: primitive,
- });
- }
- colorCommand.vertexArray = vertexArray;
- colorCommand.modelMatrix = modelMatrix;
- colorCommand.offset = offset;
- colorCommand.count = count;
- colorCommand.renderState = primitive._rsColorPass;
- colorCommand.shaderProgram = sp;
- colorCommand.uniformMap = uniformMap;
- colorCommand.boundingVolume = bv;
- colorCommand.cull = false;
- colorCommand.pass = Pass.TERRAIN_CLASSIFICATION;
- const colorDerivedCommand = DrawCommand.shallowClone(
- colorCommand,
- colorCommand.derivedCommands.tileset
- );
- colorDerivedCommand.pass = Pass.CESIUM_3D_TILE_CLASSIFICATION;
- colorCommand.derivedCommands.tileset = colorDerivedCommand;
- }
- primitive._commandsDirty = true;
- }
- function createColorCommandsIgnoreShow(primitive, frameState) {
- if (
- primitive.classificationType === ClassificationType.TERRAIN ||
- !frameState.invertClassification ||
- (defined(primitive._commandsIgnoreShow) && !primitive._commandsDirty)
- ) {
- return;
- }
- const commands = primitive._commands;
- const commandsIgnoreShow = primitive._commandsIgnoreShow;
- const spStencil = primitive._spStencil;
- const commandsLength = commands.length;
- const length = (commandsIgnoreShow.length = commandsLength / 2);
- let commandIndex = 0;
- for (let j = 0; j < length; ++j) {
- const commandIgnoreShow = (commandsIgnoreShow[j] = DrawCommand.shallowClone(
- commands[commandIndex],
- commandsIgnoreShow[j]
- ));
- commandIgnoreShow.shaderProgram = spStencil;
- commandIgnoreShow.pass = Pass.CESIUM_3D_TILE_CLASSIFICATION_IGNORE_SHOW;
- commandIndex += 2;
- }
- primitive._commandsDirty = false;
- }
- function createPickCommands(primitive) {
- if (!primitive._pickCommandsDirty) {
- return;
- }
- const length = primitive._indexOffsets.length;
- const pickCommands = primitive._pickCommands;
- pickCommands.length = length * 2;
- const vertexArray = primitive._va;
- const spStencil = primitive._spStencil;
- const spPick = primitive._spPick;
- const modelMatrix = defaultValue(primitive._modelMatrix, Matrix4.IDENTITY);
- const uniformMap = primitive._uniformMap;
- for (let j = 0; j < length; ++j) {
- const offset = primitive._indexOffsets[j];
- const count = primitive._indexCounts[j];
- const bv = defined(primitive._boundingVolumes)
- ? primitive._boundingVolumes[j]
- : primitive.boundingVolume;
- let stencilDepthCommand = pickCommands[j * 2];
- if (!defined(stencilDepthCommand)) {
- stencilDepthCommand = pickCommands[j * 2] = new DrawCommand({
- owner: primitive,
- pickOnly: true,
- });
- }
- stencilDepthCommand.vertexArray = vertexArray;
- stencilDepthCommand.modelMatrix = modelMatrix;
- stencilDepthCommand.offset = offset;
- stencilDepthCommand.count = count;
- stencilDepthCommand.renderState = primitive._rsStencilDepthPass;
- stencilDepthCommand.shaderProgram = spStencil;
- stencilDepthCommand.uniformMap = uniformMap;
- stencilDepthCommand.boundingVolume = bv;
- stencilDepthCommand.pass = Pass.TERRAIN_CLASSIFICATION;
- const stencilDepthDerivedCommand = DrawCommand.shallowClone(
- stencilDepthCommand,
- stencilDepthCommand.derivedCommands.tileset
- );
- stencilDepthDerivedCommand.renderState =
- primitive._rsStencilDepthPass3DTiles;
- stencilDepthDerivedCommand.pass = Pass.CESIUM_3D_TILE_CLASSIFICATION;
- stencilDepthCommand.derivedCommands.tileset = stencilDepthDerivedCommand;
- let colorCommand = pickCommands[j * 2 + 1];
- if (!defined(colorCommand)) {
- colorCommand = pickCommands[j * 2 + 1] = new DrawCommand({
- owner: primitive,
- pickOnly: true,
- });
- }
- colorCommand.vertexArray = vertexArray;
- colorCommand.modelMatrix = modelMatrix;
- colorCommand.offset = offset;
- colorCommand.count = count;
- colorCommand.renderState = primitive._rsPickPass;
- colorCommand.shaderProgram = spPick;
- colorCommand.uniformMap = uniformMap;
- colorCommand.boundingVolume = bv;
- colorCommand.pass = Pass.TERRAIN_CLASSIFICATION;
- const colorDerivedCommand = DrawCommand.shallowClone(
- colorCommand,
- colorCommand.derivedCommands.tileset
- );
- colorDerivedCommand.pass = Pass.CESIUM_3D_TILE_CLASSIFICATION;
- colorCommand.derivedCommands.tileset = colorDerivedCommand;
- }
- primitive._pickCommandsDirty = false;
- }
- /**
- * Creates features for each mesh and places it at the batch id index of features.
- *
- * @param {Vector3DTileContent} content The vector tile content.
- * @param {Cesium3DTileFeature[]} features An array of features where the polygon features will be placed.
- */
- Vector3DTilePrimitive.prototype.createFeatures = function (content, features) {
- const batchIds = this._batchIds;
- const length = batchIds.length;
- for (let i = 0; i < length; ++i) {
- const batchId = batchIds[i];
- features[batchId] = new Cesium3DTileFeature(content, batchId);
- }
- };
- /**
- * Colors the entire tile when enabled is true. The resulting color will be (mesh batch table color * color).
- *
- * @param {Boolean} enabled Whether to enable debug coloring.
- * @param {Color} color The debug color.
- */
- Vector3DTilePrimitive.prototype.applyDebugSettings = function (enabled, color) {
- this._highlightColor = enabled ? color : this._constantColor;
- };
- function clearStyle(polygons, features) {
- polygons._updatingAllCommands = true;
- const batchIds = polygons._batchIds;
- let length = batchIds.length;
- let i;
- for (i = 0; i < length; ++i) {
- const batchId = batchIds[i];
- const feature = features[batchId];
- feature.show = true;
- feature.color = Color.WHITE;
- }
- const batchedIndices = polygons._batchedIndices;
- length = batchedIndices.length;
- for (i = 0; i < length; ++i) {
- batchedIndices[i].color = Color.clone(Color.WHITE);
- }
- polygons._updatingAllCommands = false;
- polygons._batchDirty = true;
- }
- const scratchColor = new Color();
- const DEFAULT_COLOR_VALUE = Color.WHITE;
- const DEFAULT_SHOW_VALUE = true;
- const complexExpressionReg = /\$/;
- /**
- * Apply a style to the content.
- *
- * @param {Cesium3DTileStyle} style The style.
- * @param {Cesium3DTileFeature[]} features The array of features.
- */
- Vector3DTilePrimitive.prototype.applyStyle = function (style, features) {
- if (!defined(style)) {
- clearStyle(this, features);
- return;
- }
- const colorExpression = style.color;
- const isSimpleStyle =
- colorExpression instanceof Expression &&
- !complexExpressionReg.test(colorExpression.expression);
- this._updatingAllCommands = isSimpleStyle;
- const batchIds = this._batchIds;
- let length = batchIds.length;
- let i;
- for (i = 0; i < length; ++i) {
- const batchId = batchIds[i];
- const feature = features[batchId];
- feature.color = defined(style.color)
- ? style.color.evaluateColor(feature, scratchColor)
- : DEFAULT_COLOR_VALUE;
- feature.show = defined(style.show)
- ? style.show.evaluate(feature)
- : DEFAULT_SHOW_VALUE;
- }
- if (isSimpleStyle) {
- const batchedIndices = this._batchedIndices;
- length = batchedIndices.length;
- for (i = 0; i < length; ++i) {
- batchedIndices[i].color = Color.clone(Color.WHITE);
- }
- this._updatingAllCommands = false;
- this._batchDirty = true;
- }
- };
- /**
- * Call when updating the color of a mesh with batchId changes color. The meshes will need to be re-batched
- * on the next update.
- *
- * @param {Number} batchId The batch id of the meshes whose color has changed.
- * @param {Color} color The new polygon color.
- */
- Vector3DTilePrimitive.prototype.updateCommands = function (batchId, color) {
- if (this._updatingAllCommands) {
- return;
- }
- const batchIdLookUp = this._batchIdLookUp;
- const index = batchIdLookUp[batchId];
- if (!defined(index)) {
- return;
- }
- const indexOffsets = this._indexOffsets;
- const indexCounts = this._indexCounts;
- const offset = indexOffsets[index];
- const count = indexCounts[index];
- const batchedIndices = this._batchedIndices;
- const length = batchedIndices.length;
- let i;
- for (i = 0; i < length; ++i) {
- const batchedOffset = batchedIndices[i].offset;
- const batchedCount = batchedIndices[i].count;
- if (offset >= batchedOffset && offset < batchedOffset + batchedCount) {
- break;
- }
- }
- batchedIndices.push(
- new Vector3DTileBatch({
- color: Color.clone(color),
- offset: offset,
- count: count,
- batchIds: [batchId],
- })
- );
- const startIds = [];
- const endIds = [];
- const batchIds = batchedIndices[i].batchIds;
- const batchIdsLength = batchIds.length;
- for (let j = 0; j < batchIdsLength; ++j) {
- const id = batchIds[j];
- if (id === batchId) {
- continue;
- }
- const offsetIndex = batchIdLookUp[id];
- if (indexOffsets[offsetIndex] < offset) {
- startIds.push(id);
- } else {
- endIds.push(id);
- }
- }
- if (endIds.length !== 0) {
- batchedIndices.push(
- new Vector3DTileBatch({
- color: Color.clone(batchedIndices[i].color),
- offset: offset + count,
- count:
- batchedIndices[i].offset + batchedIndices[i].count - (offset + count),
- batchIds: endIds,
- })
- );
- }
- if (startIds.length !== 0) {
- batchedIndices[i].count = offset - batchedIndices[i].offset;
- batchedIndices[i].batchIds = startIds;
- } else {
- batchedIndices.splice(i, 1);
- }
- this._batchDirty = true;
- };
- function queueCommands(primitive, frameState, commands, commandsIgnoreShow) {
- const classificationType = primitive.classificationType;
- const queueTerrainCommands =
- classificationType !== ClassificationType.CESIUM_3D_TILE;
- const queue3DTilesCommands =
- classificationType !== ClassificationType.TERRAIN;
- const commandList = frameState.commandList;
- let commandLength = commands.length;
- let command;
- let i;
- for (i = 0; i < commandLength; ++i) {
- if (queueTerrainCommands) {
- command = commands[i];
- command.pass = Pass.TERRAIN_CLASSIFICATION;
- commandList.push(command);
- }
- if (queue3DTilesCommands) {
- command = commands[i].derivedCommands.tileset;
- command.pass = Pass.CESIUM_3D_TILE_CLASSIFICATION;
- commandList.push(command);
- }
- }
- if (!frameState.invertClassification || !defined(commandsIgnoreShow)) {
- return;
- }
- commandLength = commandsIgnoreShow.length;
- for (i = 0; i < commandLength; ++i) {
- commandList.push(commandsIgnoreShow[i]);
- }
- }
- function queueWireframeCommands(frameState, commands) {
- const commandList = frameState.commandList;
- const commandLength = commands.length;
- for (let i = 0; i < commandLength; i += 2) {
- const command = commands[i + 1];
- command.pass = Pass.OPAQUE;
- commandList.push(command);
- }
- }
- function updateWireframe(primitive) {
- let earlyExit = primitive.debugWireframe === primitive._debugWireframe;
- earlyExit =
- earlyExit && !(primitive.debugWireframe && primitive._wireframeDirty);
- if (earlyExit) {
- return;
- }
- if (!defined(primitive._rsWireframe)) {
- primitive._rsWireframe = RenderState.fromCache({});
- }
- let rs;
- let type;
- if (primitive.debugWireframe) {
- rs = primitive._rsWireframe;
- type = PrimitiveType.LINES;
- } else {
- rs = primitive._rsColorPass;
- type = PrimitiveType.TRIANGLES;
- }
- const commands = primitive._commands;
- const commandLength = commands.length;
- for (let i = 0; i < commandLength; i += 2) {
- const command = commands[i + 1];
- command.renderState = rs;
- command.primitiveType = type;
- }
- primitive._debugWireframe = primitive.debugWireframe;
- primitive._wireframeDirty = false;
- }
- /**
- * Updates the batches and queues the commands for rendering.
- *
- * @param {FrameState} frameState The current frame state.
- */
- Vector3DTilePrimitive.prototype.update = function (frameState) {
- const context = frameState.context;
- createVertexArray(this, context);
- createShaders(this, context);
- createRenderStates(this);
- createUniformMap(this, context);
- const passes = frameState.passes;
- if (passes.render) {
- createColorCommands(this, context);
- createColorCommandsIgnoreShow(this, frameState);
- updateWireframe(this);
- if (this._debugWireframe) {
- queueWireframeCommands(frameState, this._commands);
- } else {
- queueCommands(this, frameState, this._commands, this._commandsIgnoreShow);
- }
- }
- if (passes.pick) {
- createPickCommands(this);
- queueCommands(this, frameState, this._pickCommands);
- }
- };
- /**
- * Returns true if this object was destroyed; otherwise, false.
- * <p>
- * If this object was destroyed, it should not be used; calling any function other than
- * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
- * </p>
- *
- * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
- */
- Vector3DTilePrimitive.prototype.isDestroyed = function () {
- return false;
- };
- /**
- * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
- * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
- * <p>
- * Once an object is destroyed, it should not be used; calling any function other than
- * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
- * assign the return value (<code>undefined</code>) to the object as done in the example.
- * </p>
- *
- * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
- */
- Vector3DTilePrimitive.prototype.destroy = function () {
- this._va = this._va && this._va.destroy();
- this._sp = this._sp && this._sp.destroy();
- this._spPick = this._spPick && this._spPick.destroy();
- this._vaSwap = this._vaSwap && this._vaSwap.destroy();
- return destroyObject(this);
- };
- export default Vector3DTilePrimitive;
|