Vector3DTilePolylines.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. import arraySlice from "../Core/arraySlice.js";
  2. import Cartesian3 from "../Core/Cartesian3.js";
  3. import Color from "../Core/Color.js";
  4. import ComponentDatatype from "../Core/ComponentDatatype.js";
  5. import defaultValue from "../Core/defaultValue.js";
  6. import defined from "../Core/defined.js";
  7. import destroyObject from "../Core/destroyObject.js";
  8. import Ellipsoid from "../Core/Ellipsoid.js";
  9. import FeatureDetection from "../Core/FeatureDetection.js";
  10. import IndexDatatype from "../Core/IndexDatatype.js";
  11. import Matrix4 from "../Core/Matrix4.js";
  12. import Rectangle from "../Core/Rectangle.js";
  13. import TaskProcessor from "../Core/TaskProcessor.js";
  14. import Buffer from "../Renderer/Buffer.js";
  15. import BufferUsage from "../Renderer/BufferUsage.js";
  16. import DrawCommand from "../Renderer/DrawCommand.js";
  17. import Pass from "../Renderer/Pass.js";
  18. import RenderState from "../Renderer/RenderState.js";
  19. import ShaderProgram from "../Renderer/ShaderProgram.js";
  20. import ShaderSource from "../Renderer/ShaderSource.js";
  21. import VertexArray from "../Renderer/VertexArray.js";
  22. import PolylineCommon from "../Shaders/PolylineCommon.js";
  23. import Vector3DTilePolylinesVS from "../Shaders/Vector3DTilePolylinesVS.js";
  24. import when from "../ThirdParty/when.js";
  25. import BlendingState from "./BlendingState.js";
  26. import Cesium3DTileFeature from "./Cesium3DTileFeature.js";
  27. /**
  28. * Creates a batch of polylines that have been subdivided to be draped on terrain.
  29. *
  30. * @alias Vector3DTilePolylines
  31. * @constructor
  32. *
  33. * @param {Object} options An object with following properties:
  34. * @param {Uint16Array} options.positions The positions of the polylines
  35. * @param {Uint32Array} options.counts The number or positions in the each polyline.
  36. * @param {Uint16Array} options.widths The width of each polyline.
  37. * @param {Number} options.minimumHeight The minimum height of the terrain covered by the tile.
  38. * @param {Number} options.maximumHeight The maximum height of the terrain covered by the tile.
  39. * @param {Rectangle} options.rectangle The rectangle containing the tile.
  40. * @param {Cartesian3} [options.center=Cartesian3.ZERO] The RTC center.
  41. * @param {Cesium3DTileBatchTable} options.batchTable The batch table for the tile containing the batched polylines.
  42. * @param {Uint16Array} options.batchIds The batch ids for each polyline.
  43. * @param {BoundingSphere} options.boundingVolume The bounding volume for the entire batch of polylines.
  44. *
  45. * @private
  46. */
  47. function Vector3DTilePolylines(options) {
  48. // these arrays are all released after the first update.
  49. this._positions = options.positions;
  50. this._widths = options.widths;
  51. this._counts = options.counts;
  52. this._batchIds = options.batchIds;
  53. this._ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84);
  54. this._minimumHeight = options.minimumHeight;
  55. this._maximumHeight = options.maximumHeight;
  56. this._center = options.center;
  57. this._rectangle = options.rectangle;
  58. this._boundingVolume = options.boundingVolume;
  59. this._batchTable = options.batchTable;
  60. this._va = undefined;
  61. this._sp = undefined;
  62. this._rs = undefined;
  63. this._uniformMap = undefined;
  64. this._command = undefined;
  65. this._transferrableBatchIds = undefined;
  66. this._packedBuffer = undefined;
  67. this._currentPositions = undefined;
  68. this._previousPositions = undefined;
  69. this._nextPositions = undefined;
  70. this._expandAndWidth = undefined;
  71. this._vertexBatchIds = undefined;
  72. this._indices = undefined;
  73. this._constantColor = Color.clone(Color.WHITE);
  74. this._highlightColor = this._constantColor;
  75. this._trianglesLength = 0;
  76. this._geometryByteLength = 0;
  77. this._ready = false;
  78. this._readyPromise = when.defer();
  79. this._verticesPromise = undefined;
  80. }
  81. Object.defineProperties(Vector3DTilePolylines.prototype, {
  82. /**
  83. * Gets the number of triangles.
  84. *
  85. * @memberof Vector3DTilePolylines.prototype
  86. *
  87. * @type {Number}
  88. * @readonly
  89. */
  90. trianglesLength: {
  91. get: function () {
  92. return this._trianglesLength;
  93. },
  94. },
  95. /**
  96. * Gets the geometry memory in bytes.
  97. *
  98. * @memberof Vector3DTilePolylines.prototype
  99. *
  100. * @type {Number}
  101. * @readonly
  102. */
  103. geometryByteLength: {
  104. get: function () {
  105. return this._geometryByteLength;
  106. },
  107. },
  108. /**
  109. * Gets a promise that resolves when the primitive is ready to render.
  110. * @memberof Vector3DTilePolylines.prototype
  111. * @type {Promise<void>}
  112. * @readonly
  113. */
  114. readyPromise: {
  115. get: function () {
  116. return this._readyPromise.promise;
  117. },
  118. },
  119. });
  120. function packBuffer(polylines) {
  121. var rectangle = polylines._rectangle;
  122. var minimumHeight = polylines._minimumHeight;
  123. var maximumHeight = polylines._maximumHeight;
  124. var ellipsoid = polylines._ellipsoid;
  125. var center = polylines._center;
  126. var packedLength =
  127. 2 +
  128. Rectangle.packedLength +
  129. Ellipsoid.packedLength +
  130. Cartesian3.packedLength;
  131. var packedBuffer = new Float64Array(packedLength);
  132. var offset = 0;
  133. packedBuffer[offset++] = minimumHeight;
  134. packedBuffer[offset++] = maximumHeight;
  135. Rectangle.pack(rectangle, packedBuffer, offset);
  136. offset += Rectangle.packedLength;
  137. Ellipsoid.pack(ellipsoid, packedBuffer, offset);
  138. offset += Ellipsoid.packedLength;
  139. Cartesian3.pack(center, packedBuffer, offset);
  140. return packedBuffer;
  141. }
  142. var createVerticesTaskProcessor = new TaskProcessor(
  143. "createVectorTilePolylines"
  144. );
  145. var attributeLocations = {
  146. previousPosition: 0,
  147. currentPosition: 1,
  148. nextPosition: 2,
  149. expandAndWidth: 3,
  150. a_batchId: 4,
  151. };
  152. function createVertexArray(polylines, context) {
  153. if (defined(polylines._va)) {
  154. return;
  155. }
  156. if (!defined(polylines._verticesPromise)) {
  157. var positions = polylines._positions;
  158. var widths = polylines._widths;
  159. var counts = polylines._counts;
  160. var batchIds = polylines._transferrableBatchIds;
  161. var packedBuffer = polylines._packedBuffer;
  162. if (!defined(packedBuffer)) {
  163. // Copy because they may be the views on the same buffer.
  164. positions = polylines._positions = arraySlice(positions);
  165. widths = polylines._widths = arraySlice(widths);
  166. counts = polylines._counts = arraySlice(counts);
  167. batchIds = polylines._transferrableBatchIds = arraySlice(
  168. polylines._batchIds
  169. );
  170. packedBuffer = polylines._packedBuffer = packBuffer(polylines);
  171. }
  172. var transferrableObjects = [
  173. positions.buffer,
  174. widths.buffer,
  175. counts.buffer,
  176. batchIds.buffer,
  177. packedBuffer.buffer,
  178. ];
  179. var parameters = {
  180. positions: positions.buffer,
  181. widths: widths.buffer,
  182. counts: counts.buffer,
  183. batchIds: batchIds.buffer,
  184. packedBuffer: packedBuffer.buffer,
  185. };
  186. var verticesPromise = (polylines._verticesPromise = createVerticesTaskProcessor.scheduleTask(
  187. parameters,
  188. transferrableObjects
  189. ));
  190. if (!defined(verticesPromise)) {
  191. // Postponed
  192. return;
  193. }
  194. when(verticesPromise, function (result) {
  195. polylines._currentPositions = new Float32Array(result.currentPositions);
  196. polylines._previousPositions = new Float32Array(result.previousPositions);
  197. polylines._nextPositions = new Float32Array(result.nextPositions);
  198. polylines._expandAndWidth = new Float32Array(result.expandAndWidth);
  199. polylines._vertexBatchIds = new Uint16Array(result.batchIds);
  200. var indexDatatype = result.indexDatatype;
  201. polylines._indices =
  202. indexDatatype === IndexDatatype.UNSIGNED_SHORT
  203. ? new Uint16Array(result.indices)
  204. : new Uint32Array(result.indices);
  205. polylines._ready = true;
  206. });
  207. }
  208. if (polylines._ready && !defined(polylines._va)) {
  209. var curPositions = polylines._currentPositions;
  210. var prevPositions = polylines._previousPositions;
  211. var nextPositions = polylines._nextPositions;
  212. var expandAndWidth = polylines._expandAndWidth;
  213. var vertexBatchIds = polylines._vertexBatchIds;
  214. var indices = polylines._indices;
  215. var byteLength =
  216. prevPositions.byteLength +
  217. curPositions.byteLength +
  218. nextPositions.byteLength;
  219. byteLength +=
  220. expandAndWidth.byteLength +
  221. vertexBatchIds.byteLength +
  222. indices.byteLength;
  223. polylines._trianglesLength = indices.length / 3;
  224. polylines._geometryByteLength = byteLength;
  225. var prevPositionBuffer = Buffer.createVertexBuffer({
  226. context: context,
  227. typedArray: prevPositions,
  228. usage: BufferUsage.STATIC_DRAW,
  229. });
  230. var curPositionBuffer = Buffer.createVertexBuffer({
  231. context: context,
  232. typedArray: curPositions,
  233. usage: BufferUsage.STATIC_DRAW,
  234. });
  235. var nextPositionBuffer = Buffer.createVertexBuffer({
  236. context: context,
  237. typedArray: nextPositions,
  238. usage: BufferUsage.STATIC_DRAW,
  239. });
  240. var expandAndWidthBuffer = Buffer.createVertexBuffer({
  241. context: context,
  242. typedArray: expandAndWidth,
  243. usage: BufferUsage.STATIC_DRAW,
  244. });
  245. var idBuffer = Buffer.createVertexBuffer({
  246. context: context,
  247. typedArray: vertexBatchIds,
  248. usage: BufferUsage.STATIC_DRAW,
  249. });
  250. var indexBuffer = Buffer.createIndexBuffer({
  251. context: context,
  252. typedArray: indices,
  253. usage: BufferUsage.STATIC_DRAW,
  254. indexDatatype:
  255. indices.BYTES_PER_ELEMENT === 2
  256. ? IndexDatatype.UNSIGNED_SHORT
  257. : IndexDatatype.UNSIGNED_INT,
  258. });
  259. var vertexAttributes = [
  260. {
  261. index: attributeLocations.previousPosition,
  262. vertexBuffer: prevPositionBuffer,
  263. componentDatatype: ComponentDatatype.FLOAT,
  264. componentsPerAttribute: 3,
  265. },
  266. {
  267. index: attributeLocations.currentPosition,
  268. vertexBuffer: curPositionBuffer,
  269. componentDatatype: ComponentDatatype.FLOAT,
  270. componentsPerAttribute: 3,
  271. },
  272. {
  273. index: attributeLocations.nextPosition,
  274. vertexBuffer: nextPositionBuffer,
  275. componentDatatype: ComponentDatatype.FLOAT,
  276. componentsPerAttribute: 3,
  277. },
  278. {
  279. index: attributeLocations.expandAndWidth,
  280. vertexBuffer: expandAndWidthBuffer,
  281. componentDatatype: ComponentDatatype.FLOAT,
  282. componentsPerAttribute: 2,
  283. },
  284. {
  285. index: attributeLocations.a_batchId,
  286. vertexBuffer: idBuffer,
  287. componentDatatype: ComponentDatatype.UNSIGNED_SHORT,
  288. componentsPerAttribute: 1,
  289. },
  290. ];
  291. polylines._va = new VertexArray({
  292. context: context,
  293. attributes: vertexAttributes,
  294. indexBuffer: indexBuffer,
  295. });
  296. polylines._positions = undefined;
  297. polylines._widths = undefined;
  298. polylines._counts = undefined;
  299. polylines._ellipsoid = undefined;
  300. polylines._minimumHeight = undefined;
  301. polylines._maximumHeight = undefined;
  302. polylines._rectangle = undefined;
  303. polylines._transferrableBatchIds = undefined;
  304. polylines._packedBuffer = undefined;
  305. polylines._currentPositions = undefined;
  306. polylines._previousPositions = undefined;
  307. polylines._nextPositions = undefined;
  308. polylines._expandAndWidth = undefined;
  309. polylines._vertexBatchIds = undefined;
  310. polylines._indices = undefined;
  311. polylines._readyPromise.resolve();
  312. }
  313. }
  314. var modifiedModelViewScratch = new Matrix4();
  315. var rtcScratch = new Cartesian3();
  316. function createUniformMap(primitive, context) {
  317. if (defined(primitive._uniformMap)) {
  318. return;
  319. }
  320. primitive._uniformMap = {
  321. u_modifiedModelView: function () {
  322. var viewMatrix = context.uniformState.view;
  323. Matrix4.clone(viewMatrix, modifiedModelViewScratch);
  324. Matrix4.multiplyByPoint(
  325. modifiedModelViewScratch,
  326. primitive._center,
  327. rtcScratch
  328. );
  329. Matrix4.setTranslation(
  330. modifiedModelViewScratch,
  331. rtcScratch,
  332. modifiedModelViewScratch
  333. );
  334. return modifiedModelViewScratch;
  335. },
  336. u_highlightColor: function () {
  337. return primitive._highlightColor;
  338. },
  339. };
  340. }
  341. function createRenderStates(primitive) {
  342. if (defined(primitive._rs)) {
  343. return;
  344. }
  345. var polygonOffset = {
  346. enabled: true,
  347. factor: -5.0,
  348. units: -5.0,
  349. };
  350. primitive._rs = RenderState.fromCache({
  351. blending: BlendingState.ALPHA_BLEND,
  352. depthMask: false,
  353. depthTest: {
  354. enabled: true,
  355. },
  356. polygonOffset: polygonOffset,
  357. });
  358. }
  359. var PolylineFS =
  360. "uniform vec4 u_highlightColor; \n" +
  361. "void main()\n" +
  362. "{\n" +
  363. " gl_FragColor = u_highlightColor;\n" +
  364. "}\n";
  365. function createShaders(primitive, context) {
  366. if (defined(primitive._sp)) {
  367. return;
  368. }
  369. var batchTable = primitive._batchTable;
  370. var vsSource = batchTable.getVertexShaderCallback(
  371. false,
  372. "a_batchId",
  373. undefined
  374. )(Vector3DTilePolylinesVS);
  375. var fsSource = batchTable.getFragmentShaderCallback()(
  376. PolylineFS,
  377. false,
  378. undefined
  379. );
  380. var vs = new ShaderSource({
  381. defines: [
  382. "VECTOR_TILE",
  383. !FeatureDetection.isInternetExplorer() ? "CLIP_POLYLINE" : "",
  384. ],
  385. sources: [PolylineCommon, vsSource],
  386. });
  387. var fs = new ShaderSource({
  388. defines: ["VECTOR_TILE"],
  389. sources: [fsSource],
  390. });
  391. primitive._sp = ShaderProgram.fromCache({
  392. context: context,
  393. vertexShaderSource: vs,
  394. fragmentShaderSource: fs,
  395. attributeLocations: attributeLocations,
  396. });
  397. }
  398. function queueCommands(primitive, frameState) {
  399. if (!defined(primitive._command)) {
  400. var uniformMap = primitive._batchTable.getUniformMapCallback()(
  401. primitive._uniformMap
  402. );
  403. primitive._command = new DrawCommand({
  404. owner: primitive,
  405. vertexArray: primitive._va,
  406. renderState: primitive._rs,
  407. shaderProgram: primitive._sp,
  408. uniformMap: uniformMap,
  409. boundingVolume: primitive._boundingVolume,
  410. pass: Pass.TRANSLUCENT,
  411. pickId: primitive._batchTable.getPickId(),
  412. });
  413. }
  414. frameState.commandList.push(primitive._command);
  415. }
  416. /**
  417. * Creates features for each polyline and places it at the batch id index of features.
  418. *
  419. * @param {Vector3DTileContent} content The vector tile content.
  420. * @param {Cesium3DTileFeature[]} features An array of features where the polygon features will be placed.
  421. */
  422. Vector3DTilePolylines.prototype.createFeatures = function (content, features) {
  423. var batchIds = this._batchIds;
  424. var length = batchIds.length;
  425. for (var i = 0; i < length; ++i) {
  426. var batchId = batchIds[i];
  427. features[batchId] = new Cesium3DTileFeature(content, batchId);
  428. }
  429. };
  430. /**
  431. * Colors the entire tile when enabled is true. The resulting color will be (polyline batch table color * color).
  432. *
  433. * @param {Boolean} enabled Whether to enable debug coloring.
  434. * @param {Color} color The debug color.
  435. */
  436. Vector3DTilePolylines.prototype.applyDebugSettings = function (enabled, color) {
  437. this._highlightColor = enabled ? color : this._constantColor;
  438. };
  439. function clearStyle(polygons, features) {
  440. var batchIds = polygons._batchIds;
  441. var length = batchIds.length;
  442. for (var i = 0; i < length; ++i) {
  443. var batchId = batchIds[i];
  444. var feature = features[batchId];
  445. feature.show = true;
  446. feature.color = Color.WHITE;
  447. }
  448. }
  449. var scratchColor = new Color();
  450. var DEFAULT_COLOR_VALUE = Color.WHITE;
  451. var DEFAULT_SHOW_VALUE = true;
  452. /**
  453. * Apply a style to the content.
  454. *
  455. * @param {Cesium3DTileStyle} style The style.
  456. * @param {Cesium3DTileFeature[]} features The array of features.
  457. */
  458. Vector3DTilePolylines.prototype.applyStyle = function (style, features) {
  459. if (!defined(style)) {
  460. clearStyle(this, features);
  461. return;
  462. }
  463. var batchIds = this._batchIds;
  464. var length = batchIds.length;
  465. for (var i = 0; i < length; ++i) {
  466. var batchId = batchIds[i];
  467. var feature = features[batchId];
  468. feature.color = defined(style.color)
  469. ? style.color.evaluateColor(feature, scratchColor)
  470. : DEFAULT_COLOR_VALUE;
  471. feature.show = defined(style.show)
  472. ? style.show.evaluate(feature)
  473. : DEFAULT_SHOW_VALUE;
  474. }
  475. };
  476. /**
  477. * Updates the batches and queues the commands for rendering.
  478. *
  479. * @param {FrameState} frameState The current frame state.
  480. */
  481. Vector3DTilePolylines.prototype.update = function (frameState) {
  482. var context = frameState.context;
  483. createVertexArray(this, context);
  484. createUniformMap(this, context);
  485. createShaders(this, context);
  486. createRenderStates(this);
  487. if (!this._ready) {
  488. return;
  489. }
  490. var passes = frameState.passes;
  491. if (passes.render || passes.pick) {
  492. queueCommands(this, frameState);
  493. }
  494. };
  495. /**
  496. * Returns true if this object was destroyed; otherwise, false.
  497. * <p>
  498. * If this object was destroyed, it should not be used; calling any function other than
  499. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  500. * </p>
  501. *
  502. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  503. */
  504. Vector3DTilePolylines.prototype.isDestroyed = function () {
  505. return false;
  506. };
  507. /**
  508. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  509. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  510. * <p>
  511. * Once an object is destroyed, it should not be used; calling any function other than
  512. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  513. * assign the return value (<code>undefined</code>) to the object as done in the example.
  514. * </p>
  515. *
  516. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  517. */
  518. Vector3DTilePolylines.prototype.destroy = function () {
  519. this._va = this._va && this._va.destroy();
  520. this._sp = this._sp && this._sp.destroy();
  521. return destroyObject(this);
  522. };
  523. export default Vector3DTilePolylines;