Vector3DTilePrimitive.js 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210
  1. import Cartesian3 from '../Core/Cartesian3.js';
  2. import Color from '../Core/Color.js';
  3. import ComponentDatatype from '../Core/ComponentDatatype.js';
  4. import defaultValue from '../Core/defaultValue.js';
  5. import defined from '../Core/defined.js';
  6. import defineProperties from '../Core/defineProperties.js';
  7. import destroyObject from '../Core/destroyObject.js';
  8. import IndexDatatype from '../Core/IndexDatatype.js';
  9. import Matrix4 from '../Core/Matrix4.js';
  10. import PrimitiveType from '../Core/PrimitiveType.js';
  11. import Buffer from '../Renderer/Buffer.js';
  12. import BufferUsage from '../Renderer/BufferUsage.js';
  13. import DrawCommand from '../Renderer/DrawCommand.js';
  14. import Pass from '../Renderer/Pass.js';
  15. import RenderState from '../Renderer/RenderState.js';
  16. import ShaderProgram from '../Renderer/ShaderProgram.js';
  17. import ShaderSource from '../Renderer/ShaderSource.js';
  18. import VertexArray from '../Renderer/VertexArray.js';
  19. import ShadowVolumeFS from '../Shaders/ShadowVolumeFS.js';
  20. import VectorTileVS from '../Shaders/VectorTileVS.js';
  21. import BlendingState from './BlendingState.js';
  22. import Cesium3DTileFeature from './Cesium3DTileFeature.js';
  23. import ClassificationType from './ClassificationType.js';
  24. import DepthFunction from './DepthFunction.js';
  25. import Expression from './Expression.js';
  26. import StencilConstants from './StencilConstants.js';
  27. import StencilFunction from './StencilFunction.js';
  28. import StencilOperation from './StencilOperation.js';
  29. import Vector3DTileBatch from './Vector3DTileBatch.js';
  30. /**
  31. * Creates a batch of classification meshes.
  32. *
  33. * @alias Vector3DTilePrimitive
  34. * @constructor
  35. *
  36. * @param {Object} options An object with following properties:
  37. * @param {Float32Array} options.positions The positions of the meshes.
  38. * @param {Uint16Array|Uint32Array} options.indices The indices of the triangulated meshes. The indices must be contiguous so that
  39. * the indices for mesh n are in [i, i + indexCounts[n]] where i = sum{indexCounts[0], indexCounts[n - 1]}.
  40. * @param {Uint32Array} options.indexCounts The number of indices for each mesh.
  41. * @param {Uint32Array} options.indexOffsets The offset into the index buffer for each mesh.
  42. * @param {Vector3DTileBatch[]} options.batchedIndices The index offset and count for each batch with the same color.
  43. * @param {Cartesian3} [options.center=Cartesian3.ZERO] The RTC center.
  44. * @param {Cesium3DTileBatchTable} options.batchTable The batch table for the tile containing the batched meshes.
  45. * @param {Uint16Array} options.batchIds The batch ids for each mesh.
  46. * @param {Uint16Array} options.vertexBatchIds The batch id for each vertex.
  47. * @param {BoundingSphere} options.boundingVolume The bounding volume for the entire batch of meshes.
  48. * @param {BoundingSphere[]} options.boundingVolumes The bounding volume for each mesh.
  49. * @param {ClassificationType} [options.classificationType] What this tile will classify.
  50. *
  51. * @private
  52. */
  53. function Vector3DTilePrimitive(options) {
  54. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  55. this._batchTable = options.batchTable;
  56. this._batchIds = options.batchIds;
  57. // These arrays are released after VAO creation.
  58. this._positions = options.positions;
  59. this._vertexBatchIds = options.vertexBatchIds;
  60. // These arrays are kept for re-batching indices based on colors.
  61. // If WebGL 2 is supported, indices will be released and re-batching uses buffer-to-buffer copies.
  62. this._indices = options.indices;
  63. this._indexCounts = options.indexCounts;
  64. this._indexOffsets = options.indexOffsets;
  65. this._batchedIndices = options.batchedIndices;
  66. this._boundingVolume = options.boundingVolume;
  67. this._boundingVolumes = options.boundingVolumes;
  68. this._center = defaultValue(options.center, Cartesian3.ZERO);
  69. this._va = undefined;
  70. this._sp = undefined;
  71. this._spStencil = undefined;
  72. this._spPick = undefined;
  73. this._uniformMap = undefined;
  74. // Only used with WebGL 2 to ping-pong ibos after copy.
  75. this._vaSwap = undefined;
  76. this._rsStencilPreloadPass = undefined;
  77. this._rsStencilPreloadPass3DTiles = undefined;
  78. this._rsStencilDepthPass = undefined;
  79. this._rsStencilDepthPass3DTiles = undefined;
  80. this._rsColorPass = undefined;
  81. this._rsPickPass = undefined;
  82. this._rsWireframe = undefined;
  83. this._commands = [];
  84. this._commandsIgnoreShow = [];
  85. this._pickCommands = [];
  86. this._constantColor = Color.clone(Color.WHITE);
  87. this._highlightColor = this._constantColor;
  88. this._batchDirty = true;
  89. this._pickCommandsDirty = true;
  90. this._framesSinceLastRebatch = 0;
  91. this._updatingAllCommands = false;
  92. this._trianglesLength = this._indices.length / 3;
  93. this._geometryByteLength = this._indices.byteLength + this._positions.byteLength + this._vertexBatchIds.byteLength;
  94. /**
  95. * Draw the wireframe of the classification meshes.
  96. * @type {Boolean}
  97. * @default false
  98. */
  99. this.debugWireframe = false;
  100. this._debugWireframe = this.debugWireframe;
  101. this._wireframeDirty = false;
  102. /**
  103. * Forces a re-batch instead of waiting after a number of frames have been rendered. For testing only.
  104. * @type {Boolean}
  105. * @default false
  106. */
  107. this.forceRebatch = false;
  108. /**
  109. * What this tile will classify.
  110. * @type {ClassificationType}
  111. * @default ClassificationType.BOTH
  112. */
  113. this.classificationType = defaultValue(options.classificationType, ClassificationType.BOTH);
  114. // Hidden options
  115. this._vertexShaderSource = options._vertexShaderSource;
  116. this._fragmentShaderSource = options._fragmentShaderSource;
  117. this._attributeLocations = options._attributeLocations;
  118. this._uniformMap = options._uniformMap;
  119. this._pickId = options._pickId;
  120. this._modelMatrix = options._modelMatrix;
  121. this._boundingSphere = options._boundingSphere;
  122. this._batchIdLookUp = {};
  123. var length = this._batchIds.length;
  124. for (var i = 0; i < length; ++i) {
  125. var batchId = this._batchIds[i];
  126. this._batchIdLookUp[batchId] = i;
  127. }
  128. }
  129. defineProperties(Vector3DTilePrimitive.prototype, {
  130. /**
  131. * Gets the number of triangles.
  132. *
  133. * @memberof Vector3DTilePrimitive.prototype
  134. *
  135. * @type {Number}
  136. * @readonly
  137. */
  138. trianglesLength : {
  139. get : function() {
  140. return this._trianglesLength;
  141. }
  142. },
  143. /**
  144. * Gets the geometry memory in bytes.
  145. *
  146. * @memberof Vector3DTilePrimitive.prototype
  147. *
  148. * @type {Number}
  149. * @readonly
  150. */
  151. geometryByteLength : {
  152. get : function() {
  153. return this._geometryByteLength;
  154. }
  155. }
  156. });
  157. var defaultAttributeLocations = {
  158. position : 0,
  159. a_batchId : 1
  160. };
  161. function createVertexArray(primitive, context) {
  162. if (defined(primitive._va)) {
  163. return;
  164. }
  165. var positionBuffer = Buffer.createVertexBuffer({
  166. context : context,
  167. typedArray : primitive._positions,
  168. usage : BufferUsage.STATIC_DRAW
  169. });
  170. var idBuffer = Buffer.createVertexBuffer({
  171. context : context,
  172. typedArray : primitive._vertexBatchIds,
  173. usage : BufferUsage.STATIC_DRAW
  174. });
  175. var indexBuffer = Buffer.createIndexBuffer({
  176. context : context,
  177. typedArray : primitive._indices,
  178. usage : BufferUsage.DYNAMIC_DRAW,
  179. indexDatatype : (primitive._indices.BYTES_PER_ELEMENT === 2) ? IndexDatatype.UNSIGNED_SHORT : IndexDatatype.UNSIGNED_INT
  180. });
  181. var vertexAttributes = [{
  182. index : 0,
  183. vertexBuffer : positionBuffer,
  184. componentDatatype : ComponentDatatype.fromTypedArray(primitive._positions),
  185. componentsPerAttribute : 3
  186. }, {
  187. index : 1,
  188. vertexBuffer : idBuffer,
  189. componentDatatype : ComponentDatatype.fromTypedArray(primitive._vertexBatchIds),
  190. componentsPerAttribute : 1
  191. }];
  192. primitive._va = new VertexArray({
  193. context : context,
  194. attributes : vertexAttributes,
  195. indexBuffer : indexBuffer
  196. });
  197. if (context.webgl2) {
  198. primitive._vaSwap = new VertexArray({
  199. context : context,
  200. attributes : vertexAttributes,
  201. indexBuffer : Buffer.createIndexBuffer({
  202. context : context,
  203. sizeInBytes : indexBuffer.sizeInBytes,
  204. usage : BufferUsage.DYNAMIC_DRAW,
  205. indexDatatype : indexBuffer.indexDatatype
  206. })
  207. });
  208. }
  209. primitive._batchedPositions = undefined;
  210. primitive._transferrableBatchIds = undefined;
  211. primitive._vertexBatchIds = undefined;
  212. primitive._verticesPromise = undefined;
  213. }
  214. function createShaders(primitive, context) {
  215. if (defined(primitive._sp)) {
  216. return;
  217. }
  218. var batchTable = primitive._batchTable;
  219. var attributeLocations = defaultValue(primitive._attributeLocations, defaultAttributeLocations);
  220. var pickId = primitive._pickId;
  221. var vertexShaderSource = primitive._vertexShaderSource;
  222. var fragmentShaderSource = primitive._fragmentShaderSource;
  223. if (defined(vertexShaderSource)) {
  224. primitive._sp = ShaderProgram.fromCache({
  225. context : context,
  226. vertexShaderSource : vertexShaderSource,
  227. fragmentShaderSource : fragmentShaderSource,
  228. attributeLocations : attributeLocations
  229. });
  230. primitive._spStencil = primitive._sp;
  231. fragmentShaderSource = ShaderSource.replaceMain(fragmentShaderSource, 'czm_non_pick_main');
  232. fragmentShaderSource =
  233. fragmentShaderSource +
  234. 'void main() \n' +
  235. '{ \n' +
  236. ' czm_non_pick_main(); \n' +
  237. ' gl_FragColor = ' + pickId + '; \n' +
  238. '} \n';
  239. primitive._spPick = ShaderProgram.fromCache({
  240. context : context,
  241. vertexShaderSource : vertexShaderSource,
  242. fragmentShaderSource : fragmentShaderSource,
  243. attributeLocations : attributeLocations
  244. });
  245. return;
  246. }
  247. var vsSource = batchTable.getVertexShaderCallback(false, 'a_batchId', undefined)(VectorTileVS);
  248. var fsSource = batchTable.getFragmentShaderCallback()(ShadowVolumeFS, false, undefined);
  249. pickId = batchTable.getPickId();
  250. var vs = new ShaderSource({
  251. sources : [vsSource]
  252. });
  253. var fs = new ShaderSource({
  254. defines : ['VECTOR_TILE'],
  255. sources : [fsSource]
  256. });
  257. primitive._sp = ShaderProgram.fromCache({
  258. context : context,
  259. vertexShaderSource : vs,
  260. fragmentShaderSource : fs,
  261. attributeLocations : attributeLocations
  262. });
  263. vs = new ShaderSource({
  264. sources : [VectorTileVS]
  265. });
  266. fs = new ShaderSource({
  267. defines : ['VECTOR_TILE'],
  268. sources : [ShadowVolumeFS]
  269. });
  270. primitive._spStencil = ShaderProgram.fromCache({
  271. context : context,
  272. vertexShaderSource : vs,
  273. fragmentShaderSource : fs,
  274. attributeLocations : attributeLocations
  275. });
  276. fsSource = ShaderSource.replaceMain(fsSource, 'czm_non_pick_main');
  277. fsSource =
  278. fsSource + '\n' +
  279. 'void main() \n' +
  280. '{ \n' +
  281. ' czm_non_pick_main(); \n' +
  282. ' gl_FragColor = ' + pickId + '; \n' +
  283. '} \n';
  284. var pickVS = new ShaderSource({
  285. sources : [vsSource]
  286. });
  287. var pickFS = new ShaderSource({
  288. defines : ['VECTOR_TILE'],
  289. sources : [fsSource]
  290. });
  291. primitive._spPick = ShaderProgram.fromCache({
  292. context : context,
  293. vertexShaderSource : pickVS,
  294. fragmentShaderSource : pickFS,
  295. attributeLocations : attributeLocations
  296. });
  297. }
  298. function getStencilPreloadRenderState(mask3DTiles) {
  299. var stencilFunction = mask3DTiles ? StencilFunction.EQUAL : StencilFunction.ALWAYS;
  300. return {
  301. colorMask : {
  302. red : false,
  303. green : false,
  304. blue : false,
  305. alpha : false
  306. },
  307. stencilTest : {
  308. enabled : true,
  309. frontFunction : stencilFunction,
  310. frontOperation : {
  311. fail : StencilOperation.KEEP,
  312. zFail : StencilOperation.DECREMENT_WRAP,
  313. zPass : StencilOperation.DECREMENT_WRAP
  314. },
  315. backFunction : stencilFunction,
  316. backOperation : {
  317. fail : StencilOperation.KEEP,
  318. zFail : StencilOperation.INCREMENT_WRAP,
  319. zPass : StencilOperation.INCREMENT_WRAP
  320. },
  321. reference : StencilConstants.CESIUM_3D_TILE_MASK,
  322. mask : StencilConstants.CESIUM_3D_TILE_MASK
  323. },
  324. stencilMask : StencilConstants.CLASSIFICATION_MASK,
  325. depthTest : {
  326. enabled : false
  327. },
  328. depthMask : false
  329. };
  330. }
  331. function getStencilDepthRenderState(mask3DTiles) {
  332. var stencilFunction = mask3DTiles ? StencilFunction.EQUAL : StencilFunction.ALWAYS;
  333. return {
  334. colorMask : {
  335. red : false,
  336. green : false,
  337. blue : false,
  338. alpha : false
  339. },
  340. stencilTest : {
  341. enabled : true,
  342. frontFunction : stencilFunction,
  343. frontOperation : {
  344. fail : StencilOperation.KEEP,
  345. zFail : StencilOperation.KEEP,
  346. zPass : StencilOperation.INCREMENT_WRAP
  347. },
  348. backFunction : stencilFunction,
  349. backOperation : {
  350. fail : StencilOperation.KEEP,
  351. zFail : StencilOperation.KEEP,
  352. zPass : StencilOperation.DECREMENT_WRAP
  353. },
  354. reference : StencilConstants.CESIUM_3D_TILE_MASK,
  355. mask : StencilConstants.CESIUM_3D_TILE_MASK
  356. },
  357. stencilMask : StencilConstants.CLASSIFICATION_MASK,
  358. depthTest : {
  359. enabled : true,
  360. func : DepthFunction.LESS_OR_EQUAL
  361. },
  362. depthMask : false
  363. };
  364. }
  365. var colorRenderState = {
  366. stencilTest : {
  367. enabled : true,
  368. frontFunction : StencilFunction.NOT_EQUAL,
  369. frontOperation : {
  370. fail : StencilOperation.KEEP,
  371. zFail : StencilOperation.KEEP,
  372. zPass : StencilOperation.DECREMENT_WRAP
  373. },
  374. backFunction : StencilFunction.NOT_EQUAL,
  375. backOperation : {
  376. fail : StencilOperation.KEEP,
  377. zFail : StencilOperation.KEEP,
  378. zPass : StencilOperation.DECREMENT_WRAP
  379. },
  380. reference : 0,
  381. mask : StencilConstants.CLASSIFICATION_MASK
  382. },
  383. stencilMask : StencilConstants.CLASSIFICATION_MASK,
  384. depthTest : {
  385. enabled : false
  386. },
  387. depthMask : false,
  388. blending : BlendingState.ALPHA_BLEND
  389. };
  390. var pickRenderState = {
  391. stencilTest : {
  392. enabled : true,
  393. frontFunction : StencilFunction.NOT_EQUAL,
  394. frontOperation : {
  395. fail : StencilOperation.KEEP,
  396. zFail : StencilOperation.KEEP,
  397. zPass : StencilOperation.DECREMENT_WRAP
  398. },
  399. backFunction : StencilFunction.NOT_EQUAL,
  400. backOperation : {
  401. fail : StencilOperation.KEEP,
  402. zFail : StencilOperation.KEEP,
  403. zPass : StencilOperation.DECREMENT_WRAP
  404. },
  405. reference : 0,
  406. mask : StencilConstants.CLASSIFICATION_MASK
  407. },
  408. stencilMask : StencilConstants.CLASSIFICATION_MASK,
  409. depthTest : {
  410. enabled : false
  411. },
  412. depthMask : false
  413. };
  414. function createRenderStates(primitive) {
  415. if (defined(primitive._rsStencilPreloadPass)) {
  416. return;
  417. }
  418. primitive._rsStencilPreloadPass = RenderState.fromCache(getStencilPreloadRenderState(false));
  419. primitive._rsStencilPreloadPass3DTiles = RenderState.fromCache(getStencilPreloadRenderState(true));
  420. primitive._rsStencilDepthPass = RenderState.fromCache(getStencilDepthRenderState(false));
  421. primitive._rsStencilDepthPass3DTiles = RenderState.fromCache(getStencilDepthRenderState(true));
  422. primitive._rsColorPass = RenderState.fromCache(colorRenderState);
  423. primitive._rsPickPass = RenderState.fromCache(pickRenderState);
  424. }
  425. var modifiedModelViewScratch = new Matrix4();
  426. var rtcScratch = new Cartesian3();
  427. function createUniformMap(primitive, context) {
  428. if (defined(primitive._uniformMap)) {
  429. return;
  430. }
  431. var uniformMap = {
  432. u_modifiedModelViewProjection : function() {
  433. var viewMatrix = context.uniformState.view;
  434. var projectionMatrix = context.uniformState.projection;
  435. Matrix4.clone(viewMatrix, modifiedModelViewScratch);
  436. Matrix4.multiplyByPoint(modifiedModelViewScratch, primitive._center, rtcScratch);
  437. Matrix4.setTranslation(modifiedModelViewScratch, rtcScratch, modifiedModelViewScratch);
  438. Matrix4.multiply(projectionMatrix, modifiedModelViewScratch, modifiedModelViewScratch);
  439. return modifiedModelViewScratch;
  440. },
  441. u_highlightColor : function() {
  442. return primitive._highlightColor;
  443. }
  444. };
  445. primitive._uniformMap = primitive._batchTable.getUniformMapCallback()(uniformMap);
  446. }
  447. function copyIndicesCPU(indices, newIndices, currentOffset, offsets, counts, batchIds, batchIdLookUp) {
  448. var sizeInBytes = indices.constructor.BYTES_PER_ELEMENT;
  449. var batchedIdsLength = batchIds.length;
  450. for (var j = 0; j < batchedIdsLength; ++j) {
  451. var batchedId = batchIds[j];
  452. var index = batchIdLookUp[batchedId];
  453. var offset = offsets[index];
  454. var count = counts[index];
  455. var subarray = new indices.constructor(indices.buffer, sizeInBytes * offset, count);
  456. newIndices.set(subarray, currentOffset);
  457. offsets[index] = currentOffset;
  458. currentOffset += count;
  459. }
  460. return currentOffset;
  461. }
  462. function rebatchCPU(primitive, batchedIndices) {
  463. var indices = primitive._indices;
  464. var indexOffsets = primitive._indexOffsets;
  465. var indexCounts = primitive._indexCounts;
  466. var batchIdLookUp = primitive._batchIdLookUp;
  467. var newIndices = new indices.constructor(indices.length);
  468. var current = batchedIndices.pop();
  469. var newBatchedIndices = [current];
  470. var currentOffset = copyIndicesCPU(indices, newIndices, 0, indexOffsets, indexCounts, current.batchIds, batchIdLookUp);
  471. current.offset = 0;
  472. current.count = currentOffset;
  473. while (batchedIndices.length > 0) {
  474. var next = batchedIndices.pop();
  475. if (Color.equals(next.color, current.color)) {
  476. currentOffset = copyIndicesCPU(indices, newIndices, currentOffset, indexOffsets, indexCounts, next.batchIds, batchIdLookUp);
  477. current.batchIds = current.batchIds.concat(next.batchIds);
  478. current.count = currentOffset - current.offset;
  479. } else {
  480. var offset = currentOffset;
  481. currentOffset = copyIndicesCPU(indices, newIndices, currentOffset, indexOffsets, indexCounts, next.batchIds, batchIdLookUp);
  482. next.offset = offset;
  483. next.count = currentOffset - offset;
  484. newBatchedIndices.push(next);
  485. current = next;
  486. }
  487. }
  488. primitive._va.indexBuffer.copyFromArrayView(newIndices);
  489. primitive._indices = newIndices;
  490. primitive._batchedIndices = newBatchedIndices;
  491. }
  492. function copyIndicesGPU(readBuffer, writeBuffer, currentOffset, offsets, counts, batchIds, batchIdLookUp) {
  493. var sizeInBytes = readBuffer.bytesPerIndex;
  494. var batchedIdsLength = batchIds.length;
  495. for (var j = 0; j < batchedIdsLength; ++j) {
  496. var batchedId = batchIds[j];
  497. var index = batchIdLookUp[batchedId];
  498. var offset = offsets[index];
  499. var count = counts[index];
  500. writeBuffer.copyFromBuffer(readBuffer, offset * sizeInBytes, currentOffset * sizeInBytes, count * sizeInBytes);
  501. offsets[index] = currentOffset;
  502. currentOffset += count;
  503. }
  504. return currentOffset;
  505. }
  506. function rebatchGPU(primitive, batchedIndices) {
  507. var indexOffsets = primitive._indexOffsets;
  508. var indexCounts = primitive._indexCounts;
  509. var batchIdLookUp = primitive._batchIdLookUp;
  510. var current = batchedIndices.pop();
  511. var newBatchedIndices = [current];
  512. var readBuffer = primitive._va.indexBuffer;
  513. var writeBuffer = primitive._vaSwap.indexBuffer;
  514. var currentOffset = copyIndicesGPU(readBuffer, writeBuffer, 0, indexOffsets, indexCounts, current.batchIds, batchIdLookUp);
  515. current.offset = 0;
  516. current.count = currentOffset;
  517. while (batchedIndices.length > 0) {
  518. var next = batchedIndices.pop();
  519. if (Color.equals(next.color, current.color)) {
  520. currentOffset = copyIndicesGPU(readBuffer, writeBuffer, currentOffset, indexOffsets, indexCounts, next.batchIds, batchIdLookUp);
  521. current.batchIds = current.batchIds.concat(next.batchIds);
  522. current.count = currentOffset - current.offset;
  523. } else {
  524. var offset = currentOffset;
  525. currentOffset = copyIndicesGPU(readBuffer, writeBuffer, currentOffset, indexOffsets, indexCounts, next.batchIds, batchIdLookUp);
  526. next.offset = offset;
  527. next.count = currentOffset - offset;
  528. newBatchedIndices.push(next);
  529. current = next;
  530. }
  531. }
  532. var temp = primitive._va;
  533. primitive._va = primitive._vaSwap;
  534. primitive._vaSwap = temp;
  535. primitive._batchedIndices = newBatchedIndices;
  536. }
  537. function compareColors(a, b) {
  538. return b.color.toRgba() - a.color.toRgba();
  539. }
  540. // PERFORMANCE_IDEA: For WebGL 2, we can use copyBufferSubData for buffer-to-buffer copies.
  541. // PERFORMANCE_IDEA: Not supported, but we could use glMultiDrawElements here.
  542. function rebatchCommands(primitive, context) {
  543. if (!primitive._batchDirty) {
  544. return false;
  545. }
  546. var batchedIndices = primitive._batchedIndices;
  547. var length = batchedIndices.length;
  548. var needToRebatch = false;
  549. var colorCounts = {};
  550. for (var i = 0; i < length; ++i) {
  551. var color = batchedIndices[i].color;
  552. var rgba = color.toRgba();
  553. if (defined(colorCounts[rgba])) {
  554. needToRebatch = true;
  555. break;
  556. } else {
  557. colorCounts[rgba] = true;
  558. }
  559. }
  560. if (!needToRebatch) {
  561. primitive._batchDirty = false;
  562. return false;
  563. }
  564. if (needToRebatch && !primitive.forceRebatch && primitive._framesSinceLastRebatch < 120) {
  565. ++primitive._framesSinceLastRebatch;
  566. return;
  567. }
  568. batchedIndices.sort(compareColors);
  569. if (context.webgl2) {
  570. rebatchGPU(primitive, batchedIndices);
  571. } else {
  572. rebatchCPU(primitive, batchedIndices);
  573. }
  574. primitive._framesSinceLastRebatch = 0;
  575. primitive._batchDirty = false;
  576. primitive._pickCommandsDirty = true;
  577. primitive._wireframeDirty = true;
  578. return true;
  579. }
  580. function createColorCommands(primitive, context) {
  581. var needsRebatch = rebatchCommands(primitive, context);
  582. var commands = primitive._commands;
  583. var batchedIndices = primitive._batchedIndices;
  584. var length = batchedIndices.length;
  585. var commandsLength = length * 3;
  586. if (defined(commands) &&
  587. !needsRebatch &&
  588. commands.length === commandsLength) {
  589. return;
  590. }
  591. commands.length = commandsLength;
  592. var vertexArray = primitive._va;
  593. var sp = primitive._sp;
  594. var modelMatrix = defaultValue(primitive._modelMatrix, Matrix4.IDENTITY);
  595. var uniformMap = primitive._uniformMap;
  596. var bv = primitive._boundingVolume;
  597. for (var j = 0; j < length; ++j) {
  598. var offset = batchedIndices[j].offset;
  599. var count = batchedIndices[j].count;
  600. var stencilPreloadCommand = commands[j * 3];
  601. if (!defined(stencilPreloadCommand)) {
  602. stencilPreloadCommand = commands[j * 3] = new DrawCommand({
  603. owner : primitive
  604. });
  605. }
  606. stencilPreloadCommand.vertexArray = vertexArray;
  607. stencilPreloadCommand.modelMatrix = modelMatrix;
  608. stencilPreloadCommand.offset = offset;
  609. stencilPreloadCommand.count = count;
  610. stencilPreloadCommand.renderState = primitive._rsStencilPreloadPass;
  611. stencilPreloadCommand.shaderProgram = sp;
  612. stencilPreloadCommand.uniformMap = uniformMap;
  613. stencilPreloadCommand.boundingVolume = bv;
  614. stencilPreloadCommand.cull = false;
  615. stencilPreloadCommand.pass = Pass.TERRAIN_CLASSIFICATION;
  616. var stencilPreloadDerivedCommand = DrawCommand.shallowClone(stencilPreloadCommand, stencilPreloadCommand.derivedCommands.tileset);
  617. stencilPreloadDerivedCommand.renderState = primitive._rsStencilPreloadPass3DTiles;
  618. stencilPreloadDerivedCommand.pass = Pass.CESIUM_3D_TILE_CLASSIFICATION;
  619. stencilPreloadCommand.derivedCommands.tileset = stencilPreloadDerivedCommand;
  620. var stencilDepthCommand = commands[j * 3 + 1];
  621. if (!defined(stencilDepthCommand)) {
  622. stencilDepthCommand = commands[j * 3 + 1] = new DrawCommand({
  623. owner : primitive
  624. });
  625. }
  626. stencilDepthCommand.vertexArray = vertexArray;
  627. stencilDepthCommand.modelMatrix = modelMatrix;
  628. stencilDepthCommand.offset = offset;
  629. stencilDepthCommand.count = count;
  630. stencilDepthCommand.renderState = primitive._rsStencilDepthPass;
  631. stencilDepthCommand.shaderProgram = sp;
  632. stencilDepthCommand.uniformMap = uniformMap;
  633. stencilDepthCommand.boundingVolume = bv;
  634. stencilDepthCommand.cull = false;
  635. stencilDepthCommand.pass = Pass.TERRAIN_CLASSIFICATION;
  636. var stencilDepthDerivedCommand = DrawCommand.shallowClone(stencilDepthCommand, stencilDepthCommand.derivedCommands.tileset);
  637. stencilDepthDerivedCommand.renderState = primitive._rsStencilDepthPass3DTiles;
  638. stencilDepthDerivedCommand.pass = Pass.CESIUM_3D_TILE_CLASSIFICATION;
  639. stencilDepthCommand.derivedCommands.tileset = stencilDepthDerivedCommand;
  640. var colorCommand = commands[j * 3 + 2];
  641. if (!defined(colorCommand)) {
  642. colorCommand = commands[j * 3 + 2] = new DrawCommand({
  643. owner : primitive
  644. });
  645. }
  646. colorCommand.vertexArray = vertexArray;
  647. colorCommand.modelMatrix = modelMatrix;
  648. colorCommand.offset = offset;
  649. colorCommand.count = count;
  650. colorCommand.renderState = primitive._rsColorPass;
  651. colorCommand.shaderProgram = sp;
  652. colorCommand.uniformMap = uniformMap;
  653. colorCommand.boundingVolume = bv;
  654. colorCommand.cull = false;
  655. colorCommand.pass = Pass.TERRAIN_CLASSIFICATION;
  656. var colorDerivedCommand = DrawCommand.shallowClone(colorCommand, colorCommand.derivedCommands.tileset);
  657. colorDerivedCommand.pass = Pass.CESIUM_3D_TILE_CLASSIFICATION;
  658. colorCommand.derivedCommands.tileset = colorDerivedCommand;
  659. }
  660. primitive._commandsDirty = true;
  661. }
  662. function createColorCommandsIgnoreShow(primitive, frameState) {
  663. if (primitive.classificationType === ClassificationType.TERRAIN ||
  664. !frameState.invertClassification ||
  665. (defined(primitive._commandsIgnoreShow) && !primitive._commandsDirty)) {
  666. return;
  667. }
  668. var commands = primitive._commands;
  669. var commandsIgnoreShow = primitive._commandsIgnoreShow;
  670. var spStencil = primitive._spStencil;
  671. var commandsLength = commands.length;
  672. var length = commandsIgnoreShow.length = commandsLength / 3 * 2;
  673. var commandIndex = 0;
  674. for (var j = 0; j < length; j += 2) {
  675. var commandIgnoreShow = commandsIgnoreShow[j] = DrawCommand.shallowClone(commands[commandIndex], commandsIgnoreShow[j]);
  676. commandIgnoreShow.shaderProgram = spStencil;
  677. commandIgnoreShow.pass = Pass.CESIUM_3D_TILE_CLASSIFICATION_IGNORE_SHOW;
  678. commandIgnoreShow = commandsIgnoreShow[j + 1] = DrawCommand.shallowClone(commands[commandIndex + 1], commandsIgnoreShow[j + 1]);
  679. commandIgnoreShow.shaderProgram = spStencil;
  680. commandIgnoreShow.pass = Pass.CESIUM_3D_TILE_CLASSIFICATION_IGNORE_SHOW;
  681. commandIndex += 3;
  682. }
  683. primitive._commandsDirty = false;
  684. }
  685. function createPickCommands(primitive) {
  686. if (!primitive._pickCommandsDirty) {
  687. return;
  688. }
  689. var length = primitive._indexOffsets.length;
  690. var pickCommands = primitive._pickCommands;
  691. pickCommands.length = length * 3;
  692. var vertexArray = primitive._va;
  693. var spStencil = primitive._spStencil;
  694. var spPick = primitive._spPick;
  695. var modelMatrix = defaultValue(primitive._modelMatrix, Matrix4.IDENTITY);
  696. var uniformMap = primitive._uniformMap;
  697. for (var j = 0; j < length; ++j) {
  698. var offset = primitive._indexOffsets[j];
  699. var count = primitive._indexCounts[j];
  700. var bv = defined(primitive._boundingVolumes) ? primitive._boundingVolumes[j] : primitive.boundingVolume;
  701. var stencilPreloadCommand = pickCommands[j * 3];
  702. if (!defined(stencilPreloadCommand)) {
  703. stencilPreloadCommand = pickCommands[j * 3] = new DrawCommand({
  704. owner : primitive,
  705. pickOnly : true
  706. });
  707. }
  708. stencilPreloadCommand.vertexArray = vertexArray;
  709. stencilPreloadCommand.modelMatrix = modelMatrix;
  710. stencilPreloadCommand.offset = offset;
  711. stencilPreloadCommand.count = count;
  712. stencilPreloadCommand.renderState = primitive._rsStencilPreloadPass;
  713. stencilPreloadCommand.shaderProgram = spStencil;
  714. stencilPreloadCommand.uniformMap = uniformMap;
  715. stencilPreloadCommand.boundingVolume = bv;
  716. stencilPreloadCommand.pass = Pass.TERRAIN_CLASSIFICATION;
  717. var stencilPreloadDerivedCommand = DrawCommand.shallowClone(stencilPreloadCommand, stencilPreloadCommand.derivedCommands.tileset);
  718. stencilPreloadDerivedCommand.renderState = primitive._rsStencilPreloadPass3DTiles;
  719. stencilPreloadDerivedCommand.pass = Pass.CESIUM_3D_TILE_CLASSIFICATION;
  720. stencilPreloadCommand.derivedCommands.tileset = stencilPreloadDerivedCommand;
  721. var stencilDepthCommand = pickCommands[j * 3 + 1];
  722. if (!defined(stencilDepthCommand)) {
  723. stencilDepthCommand = pickCommands[j * 3 + 1] = new DrawCommand({
  724. owner : primitive,
  725. pickOnly : true
  726. });
  727. }
  728. stencilDepthCommand.vertexArray = vertexArray;
  729. stencilDepthCommand.modelMatrix = modelMatrix;
  730. stencilDepthCommand.offset = offset;
  731. stencilDepthCommand.count = count;
  732. stencilDepthCommand.renderState = primitive._rsStencilDepthPass;
  733. stencilDepthCommand.shaderProgram = spStencil;
  734. stencilDepthCommand.uniformMap = uniformMap;
  735. stencilDepthCommand.boundingVolume = bv;
  736. stencilDepthCommand.pass = Pass.TERRAIN_CLASSIFICATION;
  737. var stencilDepthDerivedCommand = DrawCommand.shallowClone(stencilDepthCommand, stencilDepthCommand.derivedCommands.tileset);
  738. stencilDepthDerivedCommand.renderState = primitive._rsStencilDepthPass3DTiles;
  739. stencilDepthDerivedCommand.pass = Pass.CESIUM_3D_TILE_CLASSIFICATION;
  740. stencilDepthCommand.derivedCommands.tileset = stencilDepthDerivedCommand;
  741. var colorCommand = pickCommands[j * 3 + 2];
  742. if (!defined(colorCommand)) {
  743. colorCommand = pickCommands[j * 3 + 2] = new DrawCommand({
  744. owner : primitive,
  745. pickOnly : true
  746. });
  747. }
  748. colorCommand.vertexArray = vertexArray;
  749. colorCommand.modelMatrix = modelMatrix;
  750. colorCommand.offset = offset;
  751. colorCommand.count = count;
  752. colorCommand.renderState = primitive._rsPickPass;
  753. colorCommand.shaderProgram = spPick;
  754. colorCommand.uniformMap = uniformMap;
  755. colorCommand.boundingVolume = bv;
  756. colorCommand.pass = Pass.TERRAIN_CLASSIFICATION;
  757. var colorDerivedCommand = DrawCommand.shallowClone(colorCommand, colorCommand.derivedCommands.tileset);
  758. colorDerivedCommand.pass = Pass.CESIUM_3D_TILE_CLASSIFICATION;
  759. colorCommand.derivedCommands.tileset = colorDerivedCommand;
  760. }
  761. primitive._pickCommandsDirty = false;
  762. }
  763. /**
  764. * Creates features for each mesh and places it at the batch id index of features.
  765. *
  766. * @param {Vector3DTileContent} content The vector tile content.
  767. * @param {Cesium3DTileFeature[]} features An array of features where the polygon features will be placed.
  768. */
  769. Vector3DTilePrimitive.prototype.createFeatures = function(content, features) {
  770. var batchIds = this._batchIds;
  771. var length = batchIds.length;
  772. for (var i = 0; i < length; ++i) {
  773. var batchId = batchIds[i];
  774. features[batchId] = new Cesium3DTileFeature(content, batchId);
  775. }
  776. };
  777. /**
  778. * Colors the entire tile when enabled is true. The resulting color will be (mesh batch table color * color).
  779. *
  780. * @param {Boolean} enabled Whether to enable debug coloring.
  781. * @param {Color} color The debug color.
  782. */
  783. Vector3DTilePrimitive.prototype.applyDebugSettings = function(enabled, color) {
  784. this._highlightColor = enabled ? color : this._constantColor;
  785. };
  786. function clearStyle(polygons, features) {
  787. polygons._updatingAllCommands = true;
  788. var batchIds = polygons._batchIds;
  789. var length = batchIds.length;
  790. var i;
  791. for (i = 0; i < length; ++i) {
  792. var batchId = batchIds[i];
  793. var feature = features[batchId];
  794. feature.show = true;
  795. feature.color = Color.WHITE;
  796. }
  797. var batchedIndices = polygons._batchedIndices;
  798. length = batchedIndices.length;
  799. for (i = 0; i < length; ++i) {
  800. batchedIndices[i].color = Color.clone(Color.WHITE);
  801. }
  802. polygons._updatingAllCommands = false;
  803. polygons._batchDirty = true;
  804. }
  805. var scratchColor = new Color();
  806. var DEFAULT_COLOR_VALUE = Color.WHITE;
  807. var DEFAULT_SHOW_VALUE = true;
  808. var complexExpressionReg = /\$/;
  809. /**
  810. * Apply a style to the content.
  811. *
  812. * @param {Cesium3DTileStyle} style The style.
  813. * @param {Cesium3DTileFeature[]} features The array of features.
  814. */
  815. Vector3DTilePrimitive.prototype.applyStyle = function(style, features) {
  816. if (!defined(style)) {
  817. clearStyle(this, features);
  818. return;
  819. }
  820. var colorExpression = style.color;
  821. var isSimpleStyle = colorExpression instanceof Expression && !complexExpressionReg.test(colorExpression.expression);
  822. this._updatingAllCommands = isSimpleStyle;
  823. var batchIds = this._batchIds;
  824. var length = batchIds.length;
  825. var i;
  826. for (i = 0; i < length; ++i) {
  827. var batchId = batchIds[i];
  828. var feature = features[batchId];
  829. feature.color = defined(style.color) ? style.color.evaluateColor(feature, scratchColor) : DEFAULT_COLOR_VALUE;
  830. feature.show = defined(style.show) ? style.show.evaluate(feature) : DEFAULT_SHOW_VALUE;
  831. }
  832. if (isSimpleStyle) {
  833. var batchedIndices = this._batchedIndices;
  834. length = batchedIndices.length;
  835. for (i = 0; i < length; ++i) {
  836. batchedIndices[i].color = Color.clone(Color.WHITE);
  837. }
  838. this._updatingAllCommands = false;
  839. this._batchDirty = true;
  840. }
  841. };
  842. /**
  843. * Call when updating the color of a mesh with batchId changes color. The meshes will need to be re-batched
  844. * on the next update.
  845. *
  846. * @param {Number} batchId The batch id of the meshes whose color has changed.
  847. * @param {Color} color The new polygon color.
  848. */
  849. Vector3DTilePrimitive.prototype.updateCommands = function(batchId, color) {
  850. if (this._updatingAllCommands) {
  851. return;
  852. }
  853. var batchIdLookUp = this._batchIdLookUp;
  854. var index = batchIdLookUp[batchId];
  855. if (!defined(index)) {
  856. return;
  857. }
  858. var indexOffsets = this._indexOffsets;
  859. var indexCounts = this._indexCounts;
  860. var offset = indexOffsets[index];
  861. var count = indexCounts[index];
  862. var batchedIndices = this._batchedIndices;
  863. var length = batchedIndices.length;
  864. var i;
  865. for (i = 0; i < length; ++i) {
  866. var batchedOffset = batchedIndices[i].offset;
  867. var batchedCount = batchedIndices[i].count;
  868. if (offset >= batchedOffset && offset < batchedOffset + batchedCount) {
  869. break;
  870. }
  871. }
  872. batchedIndices.push(new Vector3DTileBatch({
  873. color : Color.clone(color),
  874. offset : offset,
  875. count : count,
  876. batchIds : [batchId]
  877. }));
  878. var startIds = [];
  879. var endIds = [];
  880. var batchIds = batchedIndices[i].batchIds;
  881. var batchIdsLength = batchIds.length;
  882. for (var j = 0; j < batchIdsLength; ++j) {
  883. var id = batchIds[j];
  884. if (id === batchId) {
  885. continue;
  886. }
  887. var offsetIndex = batchIdLookUp[id];
  888. if (indexOffsets[offsetIndex] < offset) {
  889. startIds.push(id);
  890. } else {
  891. endIds.push(id);
  892. }
  893. }
  894. if (endIds.length !== 0) {
  895. batchedIndices.push(new Vector3DTileBatch({
  896. color : Color.clone(batchedIndices[i].color),
  897. offset : offset + count,
  898. count : batchedIndices[i].offset + batchedIndices[i].count - (offset + count),
  899. batchIds : endIds
  900. }));
  901. }
  902. if (startIds.length !== 0) {
  903. batchedIndices[i].count = offset - batchedIndices[i].offset;
  904. batchedIndices[i].batchIds = startIds;
  905. } else {
  906. batchedIndices.splice(i, 1);
  907. }
  908. this._batchDirty = true;
  909. };
  910. function queueCommands(primitive, frameState, commands, commandsIgnoreShow) {
  911. var classificationType = primitive.classificationType;
  912. var queueTerrainCommands = (classificationType !== ClassificationType.CESIUM_3D_TILE);
  913. var queue3DTilesCommands = (classificationType !== ClassificationType.TERRAIN);
  914. var commandList = frameState.commandList;
  915. var commandLength = commands.length;
  916. var command;
  917. var i;
  918. for (i = 0; i < commandLength; ++i) {
  919. if (queueTerrainCommands) {
  920. command = commands[i];
  921. command.pass = Pass.TERRAIN_CLASSIFICATION;
  922. commandList.push(command);
  923. }
  924. if (queue3DTilesCommands) {
  925. command = commands[i].derivedCommands.tileset;
  926. command.pass = Pass.CESIUM_3D_TILE_CLASSIFICATION;
  927. commandList.push(command);
  928. }
  929. }
  930. if (!frameState.invertClassification || !defined(commandsIgnoreShow)) {
  931. return;
  932. }
  933. commandLength = commandsIgnoreShow.length;
  934. for (i = 0; i < commandLength; ++i) {
  935. commandList.push(commandsIgnoreShow[i]);
  936. }
  937. }
  938. function queueWireframeCommands(frameState, commands) {
  939. var commandList = frameState.commandList;
  940. var commandLength = commands.length;
  941. for (var i = 0; i < commandLength; i += 3) {
  942. var command = commands[i + 2];
  943. command.pass = Pass.OPAQUE;
  944. commandList.push(command);
  945. }
  946. }
  947. function updateWireframe(primitive) {
  948. var earlyExit = primitive.debugWireframe === primitive._debugWireframe;
  949. earlyExit = earlyExit && !(primitive.debugWireframe && primitive._wireframeDirty);
  950. if (earlyExit) {
  951. return;
  952. }
  953. if (!defined(primitive._rsWireframe)) {
  954. primitive._rsWireframe = RenderState.fromCache({});
  955. }
  956. var rs;
  957. var type;
  958. if (primitive.debugWireframe) {
  959. rs = primitive._rsWireframe;
  960. type = PrimitiveType.LINES;
  961. } else {
  962. rs = primitive._rsColorPass;
  963. type = PrimitiveType.TRIANGLES;
  964. }
  965. var commands = primitive._commands;
  966. var commandLength = commands.length;
  967. for (var i = 0; i < commandLength; i += 3) {
  968. var command = commands[i + 2];
  969. command.renderState = rs;
  970. command.primitiveType = type;
  971. }
  972. primitive._debugWireframe = primitive.debugWireframe;
  973. primitive._wireframeDirty = false;
  974. }
  975. /**
  976. * Updates the batches and queues the commands for rendering.
  977. *
  978. * @param {FrameState} frameState The current frame state.
  979. */
  980. Vector3DTilePrimitive.prototype.update = function(frameState) {
  981. var context = frameState.context;
  982. createVertexArray(this, context);
  983. createShaders(this, context);
  984. createRenderStates(this);
  985. createUniformMap(this, context);
  986. var passes = frameState.passes;
  987. if (passes.render) {
  988. createColorCommands(this, context);
  989. createColorCommandsIgnoreShow(this, frameState);
  990. updateWireframe(this);
  991. if (this._debugWireframe) {
  992. queueWireframeCommands(frameState, this._commands);
  993. } else {
  994. queueCommands(this, frameState, this._commands, this._commandsIgnoreShow);
  995. }
  996. }
  997. if (passes.pick) {
  998. createPickCommands(this);
  999. queueCommands(this, frameState, this._pickCommands);
  1000. }
  1001. };
  1002. /**
  1003. * Returns true if this object was destroyed; otherwise, false.
  1004. * <p>
  1005. * If this object was destroyed, it should not be used; calling any function other than
  1006. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  1007. * </p>
  1008. *
  1009. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  1010. */
  1011. Vector3DTilePrimitive.prototype.isDestroyed = function() {
  1012. return false;
  1013. };
  1014. /**
  1015. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  1016. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  1017. * <p>
  1018. * Once an object is destroyed, it should not be used; calling any function other than
  1019. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  1020. * assign the return value (<code>undefined</code>) to the object as done in the example.
  1021. * </p>
  1022. *
  1023. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  1024. */
  1025. Vector3DTilePrimitive.prototype.destroy = function() {
  1026. this._va = this._va && this._va.destroy();
  1027. this._sp = this._sp && this._sp.destroy();
  1028. this._spPick = this._spPick && this._spPick.destroy();
  1029. this._vaSwap = this._vaSwap && this._vaSwap.destroy();
  1030. return destroyObject(this);
  1031. };
  1032. export default Vector3DTilePrimitive;