GroundPolylinePrimitive.js 29 KB

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