GroundPolylinePrimitive.js 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759
  1. import ApproximateTerrainHeights from '../Core/ApproximateTerrainHeights.js';
  2. import ComponentDatatype from '../Core/ComponentDatatype.js';
  3. import defaultValue from '../Core/defaultValue.js';
  4. import defined from '../Core/defined.js';
  5. import defineProperties from '../Core/defineProperties.js';
  6. import destroyObject from '../Core/destroyObject.js';
  7. import DeveloperError from '../Core/DeveloperError.js';
  8. import GeometryInstance from '../Core/GeometryInstance.js';
  9. import GeometryInstanceAttribute from '../Core/GeometryInstanceAttribute.js';
  10. import GroundPolylineGeometry from '../Core/GroundPolylineGeometry.js';
  11. import isArray from '../Core/isArray.js';
  12. import DrawCommand from '../Renderer/DrawCommand.js';
  13. import Pass from '../Renderer/Pass.js';
  14. import RenderState from '../Renderer/RenderState.js';
  15. import ShaderProgram from '../Renderer/ShaderProgram.js';
  16. import ShaderSource from '../Renderer/ShaderSource.js';
  17. import PolylineShadowVolumeFS from '../Shaders/PolylineShadowVolumeFS.js';
  18. import PolylineShadowVolumeMorphFS from '../Shaders/PolylineShadowVolumeMorphFS.js';
  19. import PolylineShadowVolumeMorphVS from '../Shaders/PolylineShadowVolumeMorphVS.js';
  20. import PolylineShadowVolumeVS from '../Shaders/PolylineShadowVolumeVS.js';
  21. import when from '../ThirdParty/when.js';
  22. import BlendingState from './BlendingState.js';
  23. import ClassificationType from './ClassificationType.js';
  24. import CullFace from './CullFace.js';
  25. import PolylineColorAppearance from './PolylineColorAppearance.js';
  26. import PolylineMaterialAppearance from './PolylineMaterialAppearance.js';
  27. import Primitive from './Primitive.js';
  28. import SceneMode from './SceneMode.js';
  29. import StencilConstants from './StencilConstants.js';
  30. import StencilFunction from './StencilFunction.js';
  31. import StencilOperation from './StencilOperation.js';
  32. /**
  33. * A GroundPolylinePrimitive represents a polyline draped over the terrain or 3D Tiles in the {@link Scene}.
  34. * <p>
  35. * Only to be used with GeometryInstances containing {@link GroundPolylineGeometry}.
  36. * </p>
  37. *
  38. * @alias GroundPolylinePrimitive
  39. * @constructor
  40. *
  41. * @param {Object} [options] Object with the following properties:
  42. * @param {Array|GeometryInstance} [options.geometryInstances] GeometryInstances containing GroundPolylineGeometry
  43. * @param {Appearance} [options.appearance] The Appearance used to render the polyline. Defaults to a white color {@link Material} on a {@link PolylineMaterialAppearance}.
  44. * @param {Boolean} [options.show=true] Determines if this primitive will be shown.
  45. * @param {Boolean} [options.interleave=false] When <code>true</code>, geometry vertex attributes are interleaved, which can slightly improve rendering performance but increases load time.
  46. * @param {Boolean} [options.releaseGeometryInstances=true] When <code>true</code>, the primitive does not keep a reference to the input <code>geometryInstances</code> to save memory.
  47. * @param {Boolean} [options.allowPicking=true] When <code>true</code>, each geometry instance will only be pickable with {@link Scene#pick}. When <code>false</code>, GPU memory is saved.
  48. * @param {Boolean} [options.asynchronous=true] Determines if the primitive will be created asynchronously or block until ready. If false initializeTerrainHeights() must be called first.
  49. * @param {ClassificationType} [options.classificationType=ClassificationType.BOTH] Determines whether terrain, 3D Tiles or both will be classified.
  50. * @param {Boolean} [options.debugShowBoundingVolume=false] For debugging only. Determines if this primitive's commands' bounding spheres are shown.
  51. * @param {Boolean} [options.debugShowShadowVolume=false] For debugging only. Determines if the shadow volume for each geometry in the primitive is drawn. Must be <code>true</code> on creation to have effect.
  52. *
  53. * @example
  54. * // 1. Draw a polyline on terrain with a basic color material
  55. *
  56. * var instance = new Cesium.GeometryInstance({
  57. * geometry : new Cesium.GroundPolylineGeometry({
  58. * positions : Cesium.Cartesian3.fromDegreesArray([
  59. * -112.1340164450331, 36.05494287836128,
  60. * -112.08821010582645, 36.097804071380715
  61. * ]),
  62. * width : 4.0
  63. * }),
  64. * id : 'object returned when this instance is picked and to get/set per-instance attributes'
  65. * });
  66. *
  67. * scene.groundPrimitives.add(new Cesium.GroundPolylinePrimitive({
  68. * geometryInstances : instance,
  69. * appearance : new Cesium.PolylineMaterialAppearance()
  70. * }));
  71. *
  72. * // 2. Draw a looped polyline on terrain with per-instance color and a distance display condition.
  73. * // Distance display conditions for polylines on terrain are based on an approximate terrain height
  74. * // instead of true terrain height.
  75. *
  76. * var instance = new Cesium.GeometryInstance({
  77. * geometry : new Cesium.GroundPolylineGeometry({
  78. * positions : Cesium.Cartesian3.fromDegreesArray([
  79. * -112.1340164450331, 36.05494287836128,
  80. * -112.08821010582645, 36.097804071380715,
  81. * -112.13296079730024, 36.168769146801104
  82. * ]),
  83. * loop : true,
  84. * width : 4.0
  85. * }),
  86. * attributes : {
  87. * color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromCssColorString('green').withAlpha(0.7)),
  88. * distanceDisplayCondition : new Cesium.DistanceDisplayConditionGeometryInstanceAttribute(1000, 30000)
  89. * },
  90. * id : 'object returned when this instance is picked and to get/set per-instance attributes'
  91. * });
  92. *
  93. * scene.groundPrimitives.add(new Cesium.GroundPolylinePrimitive({
  94. * geometryInstances : instance,
  95. * appearance : new Cesium.PolylineColorAppearance()
  96. * }));
  97. */
  98. function GroundPolylinePrimitive(options) {
  99. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  100. /**
  101. * The geometry instances rendered with this primitive. This may
  102. * be <code>undefined</code> if <code>options.releaseGeometryInstances</code>
  103. * is <code>true</code> when the primitive is constructed.
  104. * <p>
  105. * Changing this property after the primitive is rendered has no effect.
  106. * </p>
  107. *
  108. * @readonly
  109. * @type {Array|GeometryInstance}
  110. *
  111. * @default undefined
  112. */
  113. this.geometryInstances = options.geometryInstances;
  114. this._hasPerInstanceColors = true;
  115. var appearance = options.appearance;
  116. if (!defined(appearance)) {
  117. appearance = new PolylineMaterialAppearance();
  118. }
  119. /**
  120. * The {@link Appearance} used to shade this primitive. Each geometry
  121. * instance is shaded with the same appearance. Some appearances, like
  122. * {@link PolylineColorAppearance} allow giving each instance unique
  123. * properties.
  124. *
  125. * @type Appearance
  126. *
  127. * @default undefined
  128. */
  129. this.appearance = appearance;
  130. /**
  131. * Determines if the primitive will be shown. This affects all geometry
  132. * instances in the primitive.
  133. *
  134. * @type {Boolean}
  135. *
  136. * @default true
  137. */
  138. this.show = defaultValue(options.show, true);
  139. /**
  140. * Determines whether terrain, 3D Tiles or both will be classified.
  141. *
  142. * @type {ClassificationType}
  143. *
  144. * @default ClassificationType.BOTH
  145. */
  146. this.classificationType = defaultValue(options.classificationType, ClassificationType.BOTH);
  147. /**
  148. * This property is for debugging only; it is not for production use nor is it optimized.
  149. * <p>
  150. * Draws the bounding sphere for each draw command in the primitive.
  151. * </p>
  152. *
  153. * @type {Boolean}
  154. *
  155. * @default false
  156. */
  157. this.debugShowBoundingVolume = defaultValue(options.debugShowBoundingVolume, false);
  158. // Shadow volume is shown by removing a discard in the shader, so this isn't toggleable.
  159. this._debugShowShadowVolume = defaultValue(options.debugShowShadowVolume, false);
  160. this._primitiveOptions = {
  161. geometryInstances : undefined,
  162. appearance : undefined,
  163. vertexCacheOptimize : false,
  164. interleave : defaultValue(options.interleave, false),
  165. releaseGeometryInstances : defaultValue(options.releaseGeometryInstances, true),
  166. allowPicking : defaultValue(options.allowPicking, true),
  167. asynchronous : defaultValue(options.asynchronous, true),
  168. compressVertices : false,
  169. _createShaderProgramFunction : undefined,
  170. _createCommandsFunction : undefined,
  171. _updateAndQueueCommandsFunction : undefined
  172. };
  173. // Used when inserting in an OrderedPrimitiveCollection
  174. this._zIndex = undefined;
  175. this._ready = false;
  176. this._readyPromise = when.defer();
  177. this._primitive = undefined;
  178. this._sp = undefined;
  179. this._sp2D = undefined;
  180. this._spMorph = undefined;
  181. this._renderState = getRenderState(false);
  182. this._renderState3DTiles = getRenderState(true);
  183. this._renderStateMorph = RenderState.fromCache({
  184. cull : {
  185. enabled : true,
  186. face : CullFace.FRONT // Geometry is "inverted," so cull front when materials on volume instead of on terrain (morph)
  187. },
  188. depthTest : {
  189. enabled : true
  190. },
  191. blending : BlendingState.ALPHA_BLEND,
  192. depthMask : false
  193. });
  194. }
  195. defineProperties(GroundPolylinePrimitive.prototype, {
  196. /**
  197. * Determines if geometry vertex attributes are interleaved, which can slightly improve rendering performance.
  198. *
  199. * @memberof GroundPolylinePrimitive.prototype
  200. *
  201. * @type {Boolean}
  202. * @readonly
  203. *
  204. * @default false
  205. */
  206. interleave : {
  207. get : function() {
  208. return this._primitiveOptions.interleave;
  209. }
  210. },
  211. /**
  212. * When <code>true</code>, the primitive does not keep a reference to the input <code>geometryInstances</code> to save memory.
  213. *
  214. * @memberof GroundPolylinePrimitive.prototype
  215. *
  216. * @type {Boolean}
  217. * @readonly
  218. *
  219. * @default true
  220. */
  221. releaseGeometryInstances : {
  222. get : function() {
  223. return this._primitiveOptions.releaseGeometryInstances;
  224. }
  225. },
  226. /**
  227. * When <code>true</code>, each geometry instance will only be pickable with {@link Scene#pick}. When <code>false</code>, GPU memory is saved.
  228. *
  229. * @memberof GroundPolylinePrimitive.prototype
  230. *
  231. * @type {Boolean}
  232. * @readonly
  233. *
  234. * @default true
  235. */
  236. allowPicking : {
  237. get : function() {
  238. return this._primitiveOptions.allowPicking;
  239. }
  240. },
  241. /**
  242. * Determines if the geometry instances will be created and batched on a web worker.
  243. *
  244. * @memberof GroundPolylinePrimitive.prototype
  245. *
  246. * @type {Boolean}
  247. * @readonly
  248. *
  249. * @default true
  250. */
  251. asynchronous : {
  252. get : function() {
  253. return this._primitiveOptions.asynchronous;
  254. }
  255. },
  256. /**
  257. * Determines if the primitive is complete and ready to render. If this property is
  258. * true, the primitive will be rendered the next time that {@link GroundPolylinePrimitive#update}
  259. * is called.
  260. *
  261. * @memberof GroundPolylinePrimitive.prototype
  262. *
  263. * @type {Boolean}
  264. * @readonly
  265. */
  266. ready : {
  267. get : function() {
  268. return this._ready;
  269. }
  270. },
  271. /**
  272. * Gets a promise that resolves when the primitive is ready to render.
  273. * @memberof GroundPolylinePrimitive.prototype
  274. * @type {Promise.<GroundPolylinePrimitive>}
  275. * @readonly
  276. */
  277. readyPromise : {
  278. get : function() {
  279. return this._readyPromise.promise;
  280. }
  281. },
  282. /**
  283. * This property is for debugging only; it is not for production use nor is it optimized.
  284. * <p>
  285. * If true, draws the shadow volume for each geometry in the primitive.
  286. * </p>
  287. *
  288. * @memberof GroundPolylinePrimitive.prototype
  289. *
  290. * @type {Boolean}
  291. * @readonly
  292. *
  293. * @default false
  294. */
  295. debugShowShadowVolume : {
  296. get : function() {
  297. return this._debugShowShadowVolume;
  298. }
  299. }
  300. });
  301. /**
  302. * Initializes the minimum and maximum terrain heights. This only needs to be called if you are creating the
  303. * GroundPolylinePrimitive synchronously.
  304. *
  305. * @returns {Promise} A promise that will resolve once the terrain heights have been loaded.
  306. */
  307. GroundPolylinePrimitive.initializeTerrainHeights = function() {
  308. return ApproximateTerrainHeights.initialize();
  309. };
  310. function createShaderProgram(groundPolylinePrimitive, frameState, appearance) {
  311. var context = frameState.context;
  312. var primitive = groundPolylinePrimitive._primitive;
  313. var attributeLocations = primitive._attributeLocations;
  314. var vs = primitive._batchTable.getVertexShaderCallback()(PolylineShadowVolumeVS);
  315. vs = Primitive._appendShowToShader(primitive, vs);
  316. vs = Primitive._appendDistanceDisplayConditionToShader(primitive, vs);
  317. vs = Primitive._modifyShaderPosition(groundPolylinePrimitive, vs, frameState.scene3DOnly);
  318. var vsMorph = primitive._batchTable.getVertexShaderCallback()(PolylineShadowVolumeMorphVS);
  319. vsMorph = Primitive._appendShowToShader(primitive, vsMorph);
  320. vsMorph = Primitive._appendDistanceDisplayConditionToShader(primitive, vsMorph);
  321. vsMorph = Primitive._modifyShaderPosition(groundPolylinePrimitive, vsMorph, frameState.scene3DOnly);
  322. // Access pick color from fragment shader.
  323. // Helps with varying budget.
  324. var fs = primitive._batchTable.getVertexShaderCallback()(PolylineShadowVolumeFS);
  325. // Tesselation on these volumes tends to be low,
  326. // which causes problems when interpolating log depth from vertices.
  327. // So force computing and writing log depth in the fragment shader.
  328. // Re-enable at far distances to avoid z-fighting.
  329. var vsDefines = ['ENABLE_GL_POSITION_LOG_DEPTH_AT_HEIGHT', 'GLOBE_MINIMUM_ALTITUDE ' + frameState.mapProjection.ellipsoid.minimumRadius.toFixed(1)];
  330. var colorDefine = '';
  331. var materialShaderSource = '';
  332. if (defined(appearance.material)) {
  333. materialShaderSource = defined(appearance.material) ? appearance.material.shaderSource : '';
  334. // Check for use of v_width and v_polylineAngle in material shader
  335. // to determine whether these varyings should be active in the vertex shader.
  336. if (materialShaderSource.search(/varying\s+float\s+v_polylineAngle;/g) !== -1) {
  337. vsDefines.push('ANGLE_VARYING');
  338. }
  339. if (materialShaderSource.search(/varying\s+float\s+v_width;/g) !== -1) {
  340. vsDefines.push('WIDTH_VARYING');
  341. }
  342. } else {
  343. colorDefine = 'PER_INSTANCE_COLOR';
  344. }
  345. vsDefines.push(colorDefine);
  346. var fsDefines = groundPolylinePrimitive.debugShowShadowVolume ? ['DEBUG_SHOW_VOLUME', colorDefine] : [colorDefine];
  347. var vsColor3D = new ShaderSource({
  348. defines : vsDefines,
  349. sources : [vs]
  350. });
  351. var fsColor3D = new ShaderSource({
  352. defines : fsDefines,
  353. sources : [materialShaderSource, fs]
  354. });
  355. groundPolylinePrimitive._sp = ShaderProgram.replaceCache({
  356. context : context,
  357. shaderProgram : primitive._sp,
  358. vertexShaderSource : vsColor3D,
  359. fragmentShaderSource : fsColor3D,
  360. attributeLocations : attributeLocations
  361. });
  362. // Derive 2D/CV
  363. var colorProgram2D = context.shaderCache.getDerivedShaderProgram(groundPolylinePrimitive._sp, '2dColor');
  364. if (!defined(colorProgram2D)) {
  365. var vsColor2D = new ShaderSource({
  366. defines : vsDefines.concat(['COLUMBUS_VIEW_2D']),
  367. sources : [vs]
  368. });
  369. colorProgram2D = context.shaderCache.createDerivedShaderProgram(groundPolylinePrimitive._sp, '2dColor', {
  370. context : context,
  371. shaderProgram : groundPolylinePrimitive._sp2D,
  372. vertexShaderSource : vsColor2D,
  373. fragmentShaderSource : fsColor3D,
  374. attributeLocations : attributeLocations
  375. });
  376. }
  377. groundPolylinePrimitive._sp2D = colorProgram2D;
  378. // Derive Morph
  379. var colorProgramMorph = context.shaderCache.getDerivedShaderProgram(groundPolylinePrimitive._sp, 'MorphColor');
  380. if (!defined(colorProgramMorph)) {
  381. var vsColorMorph = new ShaderSource({
  382. defines : vsDefines.concat(['MAX_TERRAIN_HEIGHT ' + ApproximateTerrainHeights._defaultMaxTerrainHeight.toFixed(1)]),
  383. sources : [vsMorph]
  384. });
  385. fs = primitive._batchTable.getVertexShaderCallback()(PolylineShadowVolumeMorphFS);
  386. var fsColorMorph = new ShaderSource({
  387. defines : fsDefines,
  388. sources : [materialShaderSource, fs]
  389. });
  390. colorProgramMorph = context.shaderCache.createDerivedShaderProgram(groundPolylinePrimitive._sp, 'MorphColor', {
  391. context : context,
  392. shaderProgram : groundPolylinePrimitive._spMorph,
  393. vertexShaderSource : vsColorMorph,
  394. fragmentShaderSource : fsColorMorph,
  395. attributeLocations : attributeLocations
  396. });
  397. }
  398. groundPolylinePrimitive._spMorph = colorProgramMorph;
  399. }
  400. function getRenderState(mask3DTiles) {
  401. return RenderState.fromCache({
  402. cull : {
  403. enabled : true // prevent double-draw. Geometry is "inverted" (reversed winding order) so we're drawing backfaces.
  404. },
  405. blending : BlendingState.ALPHA_BLEND,
  406. depthMask : false,
  407. stencilTest : {
  408. enabled : mask3DTiles,
  409. frontFunction : StencilFunction.EQUAL,
  410. frontOperation : {
  411. fail : StencilOperation.KEEP,
  412. zFail : StencilOperation.KEEP,
  413. zPass : StencilOperation.KEEP
  414. },
  415. backFunction : StencilFunction.EQUAL,
  416. backOperation : {
  417. fail : StencilOperation.KEEP,
  418. zFail : StencilOperation.KEEP,
  419. zPass : StencilOperation.KEEP
  420. },
  421. reference : StencilConstants.CESIUM_3D_TILE_MASK,
  422. mask : StencilConstants.CESIUM_3D_TILE_MASK
  423. }
  424. });
  425. }
  426. function createCommands(groundPolylinePrimitive, appearance, material, translucent, colorCommands, pickCommands) {
  427. var primitive = groundPolylinePrimitive._primitive;
  428. var length = primitive._va.length;
  429. colorCommands.length = length;
  430. pickCommands.length = length;
  431. var isPolylineColorAppearance = appearance instanceof PolylineColorAppearance;
  432. var materialUniforms = isPolylineColorAppearance ? {} : material._uniforms;
  433. var uniformMap = primitive._batchTable.getUniformMapCallback()(materialUniforms);
  434. for (var i = 0; i < length; i++) {
  435. var vertexArray = primitive._va[i];
  436. var command = colorCommands[i];
  437. if (!defined(command)) {
  438. command = colorCommands[i] = new DrawCommand({
  439. owner : groundPolylinePrimitive,
  440. primitiveType : primitive._primitiveType
  441. });
  442. }
  443. command.vertexArray = vertexArray;
  444. command.renderState = groundPolylinePrimitive._renderState;
  445. command.shaderProgram = groundPolylinePrimitive._sp;
  446. command.uniformMap = uniformMap;
  447. command.pass = Pass.TERRAIN_CLASSIFICATION;
  448. command.pickId = 'czm_batchTable_pickColor(v_endPlaneNormalEcAndBatchId.w)';
  449. var derivedTilesetCommand = DrawCommand.shallowClone(command, command.derivedCommands.tileset);
  450. derivedTilesetCommand.renderState = groundPolylinePrimitive._renderState3DTiles;
  451. derivedTilesetCommand.pass = Pass.CESIUM_3D_TILE_CLASSIFICATION;
  452. command.derivedCommands.tileset = derivedTilesetCommand;
  453. // derive for 2D
  454. var derived2DCommand = DrawCommand.shallowClone(command, command.derivedCommands.color2D);
  455. derived2DCommand.shaderProgram = groundPolylinePrimitive._sp2D;
  456. command.derivedCommands.color2D = derived2DCommand;
  457. var derived2DTilesetCommand = DrawCommand.shallowClone(derivedTilesetCommand, derivedTilesetCommand.derivedCommands.color2D);
  458. derived2DTilesetCommand.shaderProgram = groundPolylinePrimitive._sp2D;
  459. derivedTilesetCommand.derivedCommands.color2D = derived2DTilesetCommand;
  460. // derive for Morph
  461. var derivedMorphCommand = DrawCommand.shallowClone(command, command.derivedCommands.colorMorph);
  462. derivedMorphCommand.renderState = groundPolylinePrimitive._renderStateMorph;
  463. derivedMorphCommand.shaderProgram = groundPolylinePrimitive._spMorph;
  464. derivedMorphCommand.pickId = 'czm_batchTable_pickColor(v_batchId)';
  465. command.derivedCommands.colorMorph = derivedMorphCommand;
  466. }
  467. }
  468. function updateAndQueueCommand(groundPolylinePrimitive, command, frameState, modelMatrix, cull, boundingVolume, debugShowBoundingVolume) {
  469. // Use derived appearance command for morph and 2D
  470. if (frameState.mode === SceneMode.MORPHING) {
  471. command = command.derivedCommands.colorMorph;
  472. } else if (frameState.mode !== SceneMode.SCENE3D) {
  473. command = command.derivedCommands.color2D;
  474. }
  475. command.modelMatrix = modelMatrix;
  476. command.boundingVolume = boundingVolume;
  477. command.cull = cull;
  478. command.debugShowBoundingVolume = debugShowBoundingVolume;
  479. frameState.commandList.push(command);
  480. }
  481. function updateAndQueueCommands(groundPolylinePrimitive, frameState, colorCommands, pickCommands, modelMatrix, cull, debugShowBoundingVolume) {
  482. var primitive = groundPolylinePrimitive._primitive;
  483. Primitive._updateBoundingVolumes(primitive, frameState, modelMatrix); // Expected to be identity - GroundPrimitives don't support other model matrices
  484. var boundingSpheres;
  485. if (frameState.mode === SceneMode.SCENE3D) {
  486. boundingSpheres = primitive._boundingSphereWC;
  487. } else if (frameState.mode === SceneMode.COLUMBUS_VIEW) {
  488. boundingSpheres = primitive._boundingSphereCV;
  489. } else if (frameState.mode === SceneMode.SCENE2D && defined(primitive._boundingSphere2D)) {
  490. boundingSpheres = primitive._boundingSphere2D;
  491. } else if (defined(primitive._boundingSphereMorph)) {
  492. boundingSpheres = primitive._boundingSphereMorph;
  493. }
  494. var morphing = frameState.mode === SceneMode.MORPHING;
  495. var classificationType = groundPolylinePrimitive.classificationType;
  496. var queueTerrainCommands = (classificationType !== ClassificationType.CESIUM_3D_TILE);
  497. var queue3DTilesCommands = (classificationType !== ClassificationType.TERRAIN) && !morphing;
  498. var command;
  499. var passes = frameState.passes;
  500. if (passes.render || (passes.pick && primitive.allowPicking)) {
  501. var colorLength = colorCommands.length;
  502. for (var j = 0; j < colorLength; ++j) {
  503. var boundingVolume = boundingSpheres[j];
  504. if (queueTerrainCommands) {
  505. command = colorCommands[j];
  506. updateAndQueueCommand(groundPolylinePrimitive, command, frameState, modelMatrix, cull, boundingVolume, debugShowBoundingVolume);
  507. }
  508. if (queue3DTilesCommands) {
  509. command = colorCommands[j].derivedCommands.tileset;
  510. updateAndQueueCommand(groundPolylinePrimitive, command, frameState, modelMatrix, cull, boundingVolume, debugShowBoundingVolume);
  511. }
  512. }
  513. }
  514. }
  515. /**
  516. * Called when {@link Viewer} or {@link CesiumWidget} render the scene to
  517. * get the draw commands needed to render this primitive.
  518. * <p>
  519. * Do not call this function directly. This is documented just to
  520. * list the exceptions that may be propagated when the scene is rendered:
  521. * </p>
  522. *
  523. * @exception {DeveloperError} For synchronous GroundPolylinePrimitives, you must call GroundPolylinePrimitives.initializeTerrainHeights() and wait for the returned promise to resolve.
  524. * @exception {DeveloperError} All GeometryInstances must have color attributes to use PolylineColorAppearance with GroundPolylinePrimitive.
  525. */
  526. GroundPolylinePrimitive.prototype.update = function(frameState) {
  527. if (!defined(this._primitive) && !defined(this.geometryInstances)) {
  528. return;
  529. }
  530. if (!ApproximateTerrainHeights.initialized) {
  531. //>>includeStart('debug', pragmas.debug);
  532. if (!this.asynchronous) {
  533. throw new DeveloperError('For synchronous GroundPolylinePrimitives, you must call GroundPolylinePrimitives.initializeTerrainHeights() and wait for the returned promise to resolve.');
  534. }
  535. //>>includeEnd('debug');
  536. GroundPolylinePrimitive.initializeTerrainHeights();
  537. return;
  538. }
  539. var i;
  540. var that = this;
  541. var primitiveOptions = this._primitiveOptions;
  542. if (!defined(this._primitive)) {
  543. var geometryInstances = isArray(this.geometryInstances) ? this.geometryInstances : [this.geometryInstances];
  544. var geometryInstancesLength = geometryInstances.length;
  545. var groundInstances = new Array(geometryInstancesLength);
  546. var attributes;
  547. // Check if each instance has a color attribute.
  548. for (i = 0; i < geometryInstancesLength; ++i) {
  549. attributes = geometryInstances[i].attributes;
  550. if (!defined(attributes) || !defined(attributes.color)) {
  551. this._hasPerInstanceColors = false;
  552. break;
  553. }
  554. }
  555. for (i = 0; i < geometryInstancesLength; ++i) {
  556. var geometryInstance = geometryInstances[i];
  557. attributes = {};
  558. var instanceAttributes = geometryInstance.attributes;
  559. for (var attributeKey in instanceAttributes) {
  560. if (instanceAttributes.hasOwnProperty(attributeKey)) {
  561. attributes[attributeKey] = instanceAttributes[attributeKey];
  562. }
  563. }
  564. // Automatically create line width attribute if not already given
  565. if (!defined(attributes.width)) {
  566. attributes.width = new GeometryInstanceAttribute({
  567. componentDatatype : ComponentDatatype.UNSIGNED_BYTE,
  568. componentsPerAttribute : 1.0,
  569. value : [geometryInstance.geometry.width]
  570. });
  571. }
  572. // Update each geometry for framestate.scene3DOnly = true and projection
  573. geometryInstance.geometry._scene3DOnly = frameState.scene3DOnly;
  574. GroundPolylineGeometry.setProjectionAndEllipsoid(geometryInstance.geometry, frameState.mapProjection);
  575. groundInstances[i] = new GeometryInstance({
  576. geometry : geometryInstance.geometry,
  577. attributes : attributes,
  578. id : geometryInstance.id,
  579. pickPrimitive : that
  580. });
  581. }
  582. primitiveOptions.geometryInstances = groundInstances;
  583. primitiveOptions.appearance = this.appearance;
  584. primitiveOptions._createShaderProgramFunction = function(primitive, frameState, appearance) {
  585. createShaderProgram(that, frameState, appearance);
  586. };
  587. primitiveOptions._createCommandsFunction = function(primitive, appearance, material, translucent, twoPasses, colorCommands, pickCommands) {
  588. createCommands(that, appearance, material, translucent, colorCommands, pickCommands);
  589. };
  590. primitiveOptions._updateAndQueueCommandsFunction = function(primitive, frameState, colorCommands, pickCommands, modelMatrix, cull, debugShowBoundingVolume, twoPasses) {
  591. updateAndQueueCommands(that, frameState, colorCommands, pickCommands, modelMatrix, cull, debugShowBoundingVolume);
  592. };
  593. this._primitive = new Primitive(primitiveOptions);
  594. this._primitive.readyPromise.then(function(primitive) {
  595. that._ready = true;
  596. if (that.releaseGeometryInstances) {
  597. that.geometryInstances = undefined;
  598. }
  599. var error = primitive._error;
  600. if (!defined(error)) {
  601. that._readyPromise.resolve(that);
  602. } else {
  603. that._readyPromise.reject(error);
  604. }
  605. });
  606. }
  607. if (this.appearance instanceof PolylineColorAppearance && !this._hasPerInstanceColors) {
  608. throw new DeveloperError('All GeometryInstances must have color attributes to use PolylineColorAppearance with GroundPolylinePrimitive.');
  609. }
  610. this._primitive.appearance = this.appearance;
  611. this._primitive.show = this.show;
  612. this._primitive.debugShowBoundingVolume = this.debugShowBoundingVolume;
  613. this._primitive.update(frameState);
  614. };
  615. /**
  616. * Returns the modifiable per-instance attributes for a {@link GeometryInstance}.
  617. *
  618. * @param {*} id The id of the {@link GeometryInstance}.
  619. * @returns {Object} The typed array in the attribute's format or undefined if the is no instance with id.
  620. *
  621. * @exception {DeveloperError} must call update before calling getGeometryInstanceAttributes.
  622. *
  623. * @example
  624. * var attributes = primitive.getGeometryInstanceAttributes('an id');
  625. * attributes.color = Cesium.ColorGeometryInstanceAttribute.toValue(Cesium.Color.AQUA);
  626. * attributes.show = Cesium.ShowGeometryInstanceAttribute.toValue(true);
  627. */
  628. GroundPolylinePrimitive.prototype.getGeometryInstanceAttributes = function(id) {
  629. //>>includeStart('debug', pragmas.debug);
  630. if (!defined(this._primitive)) {
  631. throw new DeveloperError('must call update before calling getGeometryInstanceAttributes');
  632. }
  633. //>>includeEnd('debug');
  634. return this._primitive.getGeometryInstanceAttributes(id);
  635. };
  636. /**
  637. * Checks if the given Scene supports GroundPolylinePrimitives.
  638. * GroundPolylinePrimitives require support for the WEBGL_depth_texture extension.
  639. *
  640. * @param {Scene} scene The current scene.
  641. * @returns {Boolean} Whether or not the current scene supports GroundPolylinePrimitives.
  642. */
  643. GroundPolylinePrimitive.isSupported = function(scene) {
  644. return scene.frameState.context.depthTexture;
  645. };
  646. /**
  647. * Returns true if this object was destroyed; otherwise, false.
  648. * <p>
  649. * If this object was destroyed, it should not be used; calling any function other than
  650. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  651. * </p>
  652. *
  653. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  654. *
  655. * @see GroundPolylinePrimitive#destroy
  656. */
  657. GroundPolylinePrimitive.prototype.isDestroyed = function() {
  658. return false;
  659. };
  660. /**
  661. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  662. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  663. * <p>
  664. * Once an object is destroyed, it should not be used; calling any function other than
  665. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  666. * assign the return value (<code>undefined</code>) to the object as done in the example.
  667. * </p>
  668. *
  669. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  670. *
  671. * @example
  672. * e = e && e.destroy();
  673. *
  674. * @see GroundPolylinePrimitive#isDestroyed
  675. */
  676. GroundPolylinePrimitive.prototype.destroy = function() {
  677. this._primitive = this._primitive && this._primitive.destroy();
  678. this._sp = this._sp && this._sp.destroy();
  679. // Derived programs, destroyed above if they existed.
  680. this._sp2D = undefined;
  681. this._spMorph = undefined;
  682. return destroyObject(this);
  683. };
  684. export default GroundPolylinePrimitive;