Vector3DTilePolylines.js 20 KB

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