智慧水务管理系统 - 精河县供水工程综合管理平台

ClassificationPrimitive.js 44KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387
  1. import ColorGeometryInstanceAttribute from "../Core/ColorGeometryInstanceAttribute.js";
  2. import combine from "../Core/combine.js";
  3. import Frozen from "../Core/Frozen.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 DrawCommand from "../Renderer/DrawCommand.js";
  9. import Pass from "../Renderer/Pass.js";
  10. import RenderState from "../Renderer/RenderState.js";
  11. import ShaderProgram from "../Renderer/ShaderProgram.js";
  12. import ShaderSource from "../Renderer/ShaderSource.js";
  13. import ShadowVolumeAppearanceVS from "../Shaders/ShadowVolumeAppearanceVS.js";
  14. import ShadowVolumeFS from "../Shaders/ShadowVolumeFS.js";
  15. import BlendingState from "./BlendingState.js";
  16. import ClassificationType from "./ClassificationType.js";
  17. import DepthFunction from "./DepthFunction.js";
  18. import PerInstanceColorAppearance from "./PerInstanceColorAppearance.js";
  19. import Primitive from "./Primitive.js";
  20. import SceneMode from "./SceneMode.js";
  21. import ShadowVolumeAppearance from "./ShadowVolumeAppearance.js";
  22. import StencilConstants from "./StencilConstants.js";
  23. import StencilFunction from "./StencilFunction.js";
  24. import StencilOperation from "./StencilOperation.js";
  25. /**
  26. * A classification primitive represents a volume enclosing geometry in the {@link Scene} to be highlighted.
  27. * <p>
  28. * A primitive combines geometry instances with an {@link Appearance} that describes the full shading, including
  29. * {@link Material} and {@link RenderState}. Roughly, the geometry instance defines the structure and placement,
  30. * and the appearance defines the visual characteristics. Decoupling geometry and appearance allows us to mix
  31. * and match most of them and add a new geometry or appearance independently of each other.
  32. * Only {@link PerInstanceColorAppearance} with the same color across all instances is supported at this time when using
  33. * ClassificationPrimitive directly.
  34. * For full {@link Appearance} support when classifying terrain or 3D Tiles use {@link GroundPrimitive} instead.
  35. * </p>
  36. * <p>
  37. * For correct rendering, this feature requires the EXT_frag_depth WebGL extension. For hardware that do not support this extension, there
  38. * will be rendering artifacts for some viewing angles.
  39. * </p>
  40. * <p>
  41. * Valid geometries are {@link BoxGeometry}, {@link CylinderGeometry}, {@link EllipsoidGeometry}, {@link PolylineVolumeGeometry}, and {@link SphereGeometry}.
  42. * </p>
  43. * <p>
  44. * Geometries that follow the surface of the ellipsoid, such as {@link CircleGeometry}, {@link CorridorGeometry}, {@link EllipseGeometry}, {@link PolygonGeometry}, and {@link RectangleGeometry},
  45. * are also valid if they are extruded volumes; otherwise, they will not be rendered.
  46. * </p>
  47. *
  48. * @alias ClassificationPrimitive
  49. * @constructor
  50. *
  51. * @param {object} [options] Object with the following properties:
  52. * @param {Array|GeometryInstance} [options.geometryInstances] The geometry instances to render. This can either be a single instance or an array of length one.
  53. * @param {Appearance} [options.appearance] The appearance used to render the primitive. Defaults to PerInstanceColorAppearance when GeometryInstances have a color attribute.
  54. * @param {boolean} [options.show=true] Determines if this primitive will be shown.
  55. * @param {boolean} [options.vertexCacheOptimize=false] When <code>true</code>, geometry vertices are optimized for the pre and post-vertex-shader caches.
  56. * @param {boolean} [options.interleave=false] When <code>true</code>, geometry vertex attributes are interleaved, which can slightly improve rendering performance but increases load time.
  57. * @param {boolean} [options.compressVertices=true] When <code>true</code>, the geometry vertices are compressed, which will save memory.
  58. * @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.
  59. * @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.
  60. * @param {boolean} [options.asynchronous=true] Determines if the primitive will be created asynchronously or block until ready. If false initializeTerrainHeights() must be called first.
  61. * @param {ClassificationType} [options.classificationType=ClassificationType.BOTH] Determines whether terrain, 3D Tiles or both will be classified.
  62. * @param {boolean} [options.debugShowBoundingVolume=false] For debugging only. Determines if this primitive's commands' bounding spheres are shown.
  63. * @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
  64. * creation for the volumes to be created before the geometry is released or options.releaseGeometryInstance must be <code>false</code>.
  65. *
  66. * @see Primitive
  67. * @see GroundPrimitive
  68. * @see GeometryInstance
  69. * @see Appearance
  70. */
  71. function ClassificationPrimitive(options) {
  72. options = options ?? Frozen.EMPTY_OBJECT;
  73. const geometryInstances = options.geometryInstances;
  74. /**
  75. * The geometry instance rendered with this primitive. This may
  76. * be <code>undefined</code> if <code>options.releaseGeometryInstances</code>
  77. * is <code>true</code> when the primitive is constructed.
  78. * <p>
  79. * Changing this property after the primitive is rendered has no effect.
  80. * </p>
  81. * <p>
  82. * Because of the rendering technique used, all geometry instances must be the same color.
  83. * If there is an instance with a differing color, a <code>DeveloperError</code> will be thrown
  84. * on the first attempt to render.
  85. * </p>
  86. *
  87. * @readonly
  88. * @type {Array|GeometryInstance}
  89. *
  90. * @default undefined
  91. */
  92. this.geometryInstances = geometryInstances;
  93. /**
  94. * Determines if the primitive will be shown. This affects all geometry
  95. * instances in the primitive.
  96. *
  97. * @type {boolean}
  98. *
  99. * @default true
  100. */
  101. this.show = options.show ?? true;
  102. /**
  103. * Determines whether terrain, 3D Tiles or both will be classified.
  104. *
  105. * @type {ClassificationType}
  106. *
  107. * @default ClassificationType.BOTH
  108. */
  109. this.classificationType =
  110. options.classificationType ?? ClassificationType.BOTH;
  111. /**
  112. * This property is for debugging only; it is not for production use nor is it optimized.
  113. * <p>
  114. * Draws the bounding sphere for each draw command in the primitive.
  115. * </p>
  116. *
  117. * @type {boolean}
  118. *
  119. * @default false
  120. */
  121. this.debugShowBoundingVolume = options.debugShowBoundingVolume ?? false;
  122. /**
  123. * This property is for debugging only; it is not for production use nor is it optimized.
  124. * <p>
  125. * Draws the shadow volume for each geometry in the primitive.
  126. * </p>
  127. *
  128. * @type {boolean}
  129. *
  130. * @default false
  131. */
  132. this.debugShowShadowVolume = options.debugShowShadowVolume ?? false;
  133. this._debugShowShadowVolume = false;
  134. // These are used by GroundPrimitive to augment the shader and uniform map.
  135. this._extruded = options._extruded ?? false;
  136. this._uniformMap = options._uniformMap;
  137. this._sp = undefined;
  138. this._spStencil = undefined;
  139. this._spPick = undefined;
  140. this._spColor = undefined;
  141. this._spPick2D = undefined; // only derived if necessary
  142. this._spColor2D = undefined; // only derived if necessary
  143. this._rsStencilDepthPass = undefined;
  144. this._rsStencilDepthPass3DTiles = undefined;
  145. this._rsColorPass = undefined;
  146. this._rsPickPass = undefined;
  147. this._commandsIgnoreShow = [];
  148. this._ready = false;
  149. this._primitive = undefined;
  150. this._pickPrimitive = options._pickPrimitive;
  151. // Set in update
  152. this._hasSphericalExtentsAttribute = false;
  153. this._hasPlanarExtentsAttributes = false;
  154. this._hasPerColorAttribute = false;
  155. this.appearance = options.appearance;
  156. this._createBoundingVolumeFunction = options._createBoundingVolumeFunction;
  157. this._updateAndQueueCommandsFunction =
  158. options._updateAndQueueCommandsFunction;
  159. this._usePickOffsets = false;
  160. this._primitiveOptions = {
  161. geometryInstances: undefined,
  162. appearance: undefined,
  163. vertexCacheOptimize: options.vertexCacheOptimize ?? false,
  164. interleave: options.interleave ?? false,
  165. releaseGeometryInstances: options.releaseGeometryInstances ?? true,
  166. allowPicking: options.allowPicking ?? true,
  167. asynchronous: options.asynchronous ?? true,
  168. compressVertices: options.compressVertices ?? true,
  169. _createBoundingVolumeFunction: undefined,
  170. _createRenderStatesFunction: undefined,
  171. _createShaderProgramFunction: undefined,
  172. _createCommandsFunction: undefined,
  173. _updateAndQueueCommandsFunction: undefined,
  174. _createPickOffsets: true,
  175. };
  176. }
  177. Object.defineProperties(ClassificationPrimitive.prototype, {
  178. /**
  179. * When <code>true</code>, geometry vertices are optimized for the pre and post-vertex-shader caches.
  180. *
  181. * @memberof ClassificationPrimitive.prototype
  182. *
  183. * @type {boolean}
  184. * @readonly
  185. *
  186. * @default true
  187. */
  188. vertexCacheOptimize: {
  189. get: function () {
  190. return this._primitiveOptions.vertexCacheOptimize;
  191. },
  192. },
  193. /**
  194. * Determines if geometry vertex attributes are interleaved, which can slightly improve rendering performance.
  195. *
  196. * @memberof ClassificationPrimitive.prototype
  197. *
  198. * @type {boolean}
  199. * @readonly
  200. *
  201. * @default false
  202. */
  203. interleave: {
  204. get: function () {
  205. return this._primitiveOptions.interleave;
  206. },
  207. },
  208. /**
  209. * When <code>true</code>, the primitive does not keep a reference to the input <code>geometryInstances</code> to save memory.
  210. *
  211. * @memberof ClassificationPrimitive.prototype
  212. *
  213. * @type {boolean}
  214. * @readonly
  215. *
  216. * @default true
  217. */
  218. releaseGeometryInstances: {
  219. get: function () {
  220. return this._primitiveOptions.releaseGeometryInstances;
  221. },
  222. },
  223. /**
  224. * When <code>true</code>, each geometry instance will only be pickable with {@link Scene#pick}. When <code>false</code>, GPU memory is saved.
  225. *
  226. * @memberof ClassificationPrimitive.prototype
  227. *
  228. * @type {boolean}
  229. * @readonly
  230. *
  231. * @default true
  232. */
  233. allowPicking: {
  234. get: function () {
  235. return this._primitiveOptions.allowPicking;
  236. },
  237. },
  238. /**
  239. * Determines if the geometry instances will be created and batched on a web worker.
  240. *
  241. * @memberof ClassificationPrimitive.prototype
  242. *
  243. * @type {boolean}
  244. * @readonly
  245. *
  246. * @default true
  247. */
  248. asynchronous: {
  249. get: function () {
  250. return this._primitiveOptions.asynchronous;
  251. },
  252. },
  253. /**
  254. * When <code>true</code>, geometry vertices are compressed, which will save memory.
  255. *
  256. * @memberof ClassificationPrimitive.prototype
  257. *
  258. * @type {boolean}
  259. * @readonly
  260. *
  261. * @default true
  262. */
  263. compressVertices: {
  264. get: function () {
  265. return this._primitiveOptions.compressVertices;
  266. },
  267. },
  268. /**
  269. * Determines if the primitive is complete and ready to render. If this property is
  270. * true, the primitive will be rendered the next time that {@link ClassificationPrimitive#update}
  271. * is called.
  272. *
  273. * @memberof ClassificationPrimitive.prototype
  274. *
  275. * @type {boolean}
  276. * @readonly
  277. */
  278. ready: {
  279. get: function () {
  280. return this._ready;
  281. },
  282. },
  283. /**
  284. * Returns true if the ClassificationPrimitive needs a separate shader and commands for 2D.
  285. * This is because texture coordinates on ClassificationPrimitives are computed differently,
  286. * and are used for culling when multiple GeometryInstances are batched in one ClassificationPrimitive.
  287. * @memberof ClassificationPrimitive.prototype
  288. * @type {boolean}
  289. * @readonly
  290. * @private
  291. */
  292. _needs2DShader: {
  293. get: function () {
  294. return (
  295. this._hasPlanarExtentsAttributes || this._hasSphericalExtentsAttribute
  296. );
  297. },
  298. },
  299. });
  300. /**
  301. * Determines if ClassificationPrimitive rendering is supported.
  302. *
  303. * @param {Scene} scene The scene.
  304. * @returns {boolean} <code>true</code> if ClassificationPrimitives are supported; otherwise, returns <code>false</code>
  305. */
  306. ClassificationPrimitive.isSupported = function (scene) {
  307. return scene.context.stencilBuffer;
  308. };
  309. function getStencilDepthRenderState(enableStencil, mask3DTiles) {
  310. const stencilFunction = mask3DTiles
  311. ? StencilFunction.EQUAL
  312. : StencilFunction.ALWAYS;
  313. return {
  314. colorMask: {
  315. red: false,
  316. green: false,
  317. blue: false,
  318. alpha: false,
  319. },
  320. stencilTest: {
  321. enabled: enableStencil,
  322. frontFunction: stencilFunction,
  323. frontOperation: {
  324. fail: StencilOperation.KEEP,
  325. zFail: StencilOperation.DECREMENT_WRAP,
  326. zPass: StencilOperation.KEEP,
  327. },
  328. backFunction: stencilFunction,
  329. backOperation: {
  330. fail: StencilOperation.KEEP,
  331. zFail: StencilOperation.INCREMENT_WRAP,
  332. zPass: StencilOperation.KEEP,
  333. },
  334. reference: StencilConstants.CESIUM_3D_TILE_MASK,
  335. mask: StencilConstants.CESIUM_3D_TILE_MASK,
  336. },
  337. stencilMask: StencilConstants.CLASSIFICATION_MASK,
  338. depthTest: {
  339. enabled: true,
  340. func: DepthFunction.LESS_OR_EQUAL,
  341. },
  342. depthMask: false,
  343. };
  344. }
  345. function getColorRenderState(enableStencil) {
  346. return {
  347. stencilTest: {
  348. enabled: enableStencil,
  349. frontFunction: StencilFunction.NOT_EQUAL,
  350. frontOperation: {
  351. fail: StencilOperation.ZERO,
  352. zFail: StencilOperation.ZERO,
  353. zPass: StencilOperation.ZERO,
  354. },
  355. backFunction: StencilFunction.NOT_EQUAL,
  356. backOperation: {
  357. fail: StencilOperation.ZERO,
  358. zFail: StencilOperation.ZERO,
  359. zPass: StencilOperation.ZERO,
  360. },
  361. reference: 0,
  362. mask: StencilConstants.CLASSIFICATION_MASK,
  363. },
  364. stencilMask: StencilConstants.CLASSIFICATION_MASK,
  365. depthTest: {
  366. enabled: false,
  367. },
  368. depthMask: false,
  369. blending: BlendingState.PRE_MULTIPLIED_ALPHA_BLEND,
  370. };
  371. }
  372. const pickRenderState = {
  373. stencilTest: {
  374. enabled: true,
  375. frontFunction: StencilFunction.NOT_EQUAL,
  376. frontOperation: {
  377. fail: StencilOperation.ZERO,
  378. zFail: StencilOperation.ZERO,
  379. zPass: StencilOperation.ZERO,
  380. },
  381. backFunction: StencilFunction.NOT_EQUAL,
  382. backOperation: {
  383. fail: StencilOperation.ZERO,
  384. zFail: StencilOperation.ZERO,
  385. zPass: StencilOperation.ZERO,
  386. },
  387. reference: 0,
  388. mask: StencilConstants.CLASSIFICATION_MASK,
  389. },
  390. stencilMask: StencilConstants.CLASSIFICATION_MASK,
  391. depthTest: {
  392. enabled: false,
  393. },
  394. depthMask: false,
  395. };
  396. function createRenderStates(
  397. classificationPrimitive,
  398. context,
  399. appearance,
  400. twoPasses,
  401. ) {
  402. if (defined(classificationPrimitive._rsStencilDepthPass)) {
  403. return;
  404. }
  405. const stencilEnabled = !classificationPrimitive.debugShowShadowVolume;
  406. classificationPrimitive._rsStencilDepthPass = RenderState.fromCache(
  407. getStencilDepthRenderState(stencilEnabled, false),
  408. );
  409. classificationPrimitive._rsStencilDepthPass3DTiles = RenderState.fromCache(
  410. getStencilDepthRenderState(stencilEnabled, true),
  411. );
  412. classificationPrimitive._rsColorPass = RenderState.fromCache(
  413. getColorRenderState(stencilEnabled, false),
  414. );
  415. classificationPrimitive._rsPickPass = RenderState.fromCache(pickRenderState);
  416. }
  417. function modifyForEncodedNormals(primitive, vertexShaderSource) {
  418. if (!primitive.compressVertices) {
  419. return vertexShaderSource;
  420. }
  421. if (vertexShaderSource.search(/in\s+vec3\s+extrudeDirection;/g) !== -1) {
  422. const attributeName = "compressedAttributes";
  423. //only shadow volumes use extrudeDirection, and shadow volumes use vertexFormat: POSITION_ONLY so we don't need to check other attributes
  424. const attributeDecl = `in vec2 ${attributeName};`;
  425. const globalDecl = "vec3 extrudeDirection;\n";
  426. const decode = ` extrudeDirection = czm_octDecode(${attributeName}, 65535.0);\n`;
  427. let modifiedVS = vertexShaderSource;
  428. modifiedVS = modifiedVS.replace(/in\s+vec3\s+extrudeDirection;/g, "");
  429. modifiedVS = ShaderSource.replaceMain(
  430. modifiedVS,
  431. "czm_non_compressed_main",
  432. );
  433. const compressedMain =
  434. `${"void main() \n" + "{ \n"}${decode} czm_non_compressed_main(); \n` +
  435. `}`;
  436. return [attributeDecl, globalDecl, modifiedVS, compressedMain].join("\n");
  437. }
  438. }
  439. function createShaderProgram(classificationPrimitive, frameState) {
  440. const context = frameState.context;
  441. const primitive = classificationPrimitive._primitive;
  442. let vs = ShadowVolumeAppearanceVS;
  443. vs =
  444. classificationPrimitive._primitive._batchTable.getVertexShaderCallback()(
  445. vs,
  446. );
  447. vs = Primitive._appendDistanceDisplayConditionToShader(primitive, vs);
  448. vs = Primitive._modifyShaderPosition(
  449. classificationPrimitive,
  450. vs,
  451. frameState.scene3DOnly,
  452. );
  453. vs = Primitive._updateColorAttribute(primitive, vs);
  454. const planarExtents = classificationPrimitive._hasPlanarExtentsAttributes;
  455. const cullFragmentsUsingExtents =
  456. planarExtents || classificationPrimitive._hasSphericalExtentsAttribute;
  457. if (classificationPrimitive._extruded) {
  458. vs = modifyForEncodedNormals(primitive, vs);
  459. }
  460. const extrudedDefine = classificationPrimitive._extruded
  461. ? "EXTRUDED_GEOMETRY"
  462. : "";
  463. let vsSource = new ShaderSource({
  464. defines: [extrudedDefine],
  465. sources: [vs],
  466. });
  467. const fsSource = new ShaderSource({
  468. sources: [ShadowVolumeFS],
  469. });
  470. const attributeLocations =
  471. classificationPrimitive._primitive._attributeLocations;
  472. const shadowVolumeAppearance = new ShadowVolumeAppearance(
  473. cullFragmentsUsingExtents,
  474. planarExtents,
  475. classificationPrimitive.appearance,
  476. );
  477. classificationPrimitive._spStencil = ShaderProgram.replaceCache({
  478. context: context,
  479. shaderProgram: classificationPrimitive._spStencil,
  480. vertexShaderSource: vsSource,
  481. fragmentShaderSource: fsSource,
  482. attributeLocations: attributeLocations,
  483. });
  484. if (classificationPrimitive._primitive.allowPicking) {
  485. let vsPick = ShaderSource.createPickVertexShaderSource(vs);
  486. vsPick = Primitive._appendShowToShader(primitive, vsPick);
  487. vsPick = Primitive._updatePickColorAttribute(vsPick);
  488. const pickFS3D = shadowVolumeAppearance.createPickFragmentShader(false);
  489. const pickVS3D = shadowVolumeAppearance.createPickVertexShader(
  490. [extrudedDefine],
  491. vsPick,
  492. false,
  493. frameState.mapProjection,
  494. );
  495. classificationPrimitive._spPick = ShaderProgram.replaceCache({
  496. context: context,
  497. shaderProgram: classificationPrimitive._spPick,
  498. vertexShaderSource: pickVS3D,
  499. fragmentShaderSource: pickFS3D,
  500. attributeLocations: attributeLocations,
  501. });
  502. // Derive a 2D pick shader if the primitive uses texture coordinate-based fragment culling,
  503. // since texture coordinates are computed differently in 2D.
  504. if (cullFragmentsUsingExtents) {
  505. let pickProgram2D = context.shaderCache.getDerivedShaderProgram(
  506. classificationPrimitive._spPick,
  507. "2dPick",
  508. );
  509. if (!defined(pickProgram2D)) {
  510. const pickFS2D = shadowVolumeAppearance.createPickFragmentShader(true);
  511. const pickVS2D = shadowVolumeAppearance.createPickVertexShader(
  512. [extrudedDefine],
  513. vsPick,
  514. true,
  515. frameState.mapProjection,
  516. );
  517. pickProgram2D = context.shaderCache.createDerivedShaderProgram(
  518. classificationPrimitive._spPick,
  519. "2dPick",
  520. {
  521. vertexShaderSource: pickVS2D,
  522. fragmentShaderSource: pickFS2D,
  523. attributeLocations: attributeLocations,
  524. },
  525. );
  526. }
  527. classificationPrimitive._spPick2D = pickProgram2D;
  528. }
  529. } else {
  530. classificationPrimitive._spPick = ShaderProgram.fromCache({
  531. context: context,
  532. vertexShaderSource: vsSource,
  533. fragmentShaderSource: fsSource,
  534. attributeLocations: attributeLocations,
  535. });
  536. }
  537. vs = Primitive._appendShowToShader(primitive, vs);
  538. vsSource = new ShaderSource({
  539. defines: [extrudedDefine],
  540. sources: [vs],
  541. });
  542. classificationPrimitive._sp = ShaderProgram.replaceCache({
  543. context: context,
  544. shaderProgram: classificationPrimitive._sp,
  545. vertexShaderSource: vsSource,
  546. fragmentShaderSource: fsSource,
  547. attributeLocations: attributeLocations,
  548. });
  549. // Create a fragment shader that computes only required material hookups using screen space techniques
  550. const fsColorSource = shadowVolumeAppearance.createFragmentShader(false);
  551. const vsColorSource = shadowVolumeAppearance.createVertexShader(
  552. [extrudedDefine],
  553. vs,
  554. false,
  555. frameState.mapProjection,
  556. );
  557. classificationPrimitive._spColor = ShaderProgram.replaceCache({
  558. context: context,
  559. shaderProgram: classificationPrimitive._spColor,
  560. vertexShaderSource: vsColorSource,
  561. fragmentShaderSource: fsColorSource,
  562. attributeLocations: attributeLocations,
  563. });
  564. // Derive a 2D shader if the primitive uses texture coordinate-based fragment culling,
  565. // since texture coordinates are computed differently in 2D.
  566. // Any material that uses texture coordinates will also equip texture coordinate-based fragment culling.
  567. if (cullFragmentsUsingExtents) {
  568. let colorProgram2D = context.shaderCache.getDerivedShaderProgram(
  569. classificationPrimitive._spColor,
  570. "2dColor",
  571. );
  572. if (!defined(colorProgram2D)) {
  573. const fsColorSource2D = shadowVolumeAppearance.createFragmentShader(true);
  574. const vsColorSource2D = shadowVolumeAppearance.createVertexShader(
  575. [extrudedDefine],
  576. vs,
  577. true,
  578. frameState.mapProjection,
  579. );
  580. colorProgram2D = context.shaderCache.createDerivedShaderProgram(
  581. classificationPrimitive._spColor,
  582. "2dColor",
  583. {
  584. vertexShaderSource: vsColorSource2D,
  585. fragmentShaderSource: fsColorSource2D,
  586. attributeLocations: attributeLocations,
  587. },
  588. );
  589. }
  590. classificationPrimitive._spColor2D = colorProgram2D;
  591. }
  592. }
  593. function createColorCommands(classificationPrimitive, colorCommands) {
  594. const primitive = classificationPrimitive._primitive;
  595. let length = primitive._va.length * 2; // each geometry (pack of vertex attributes) needs 2 commands: front/back stencils and fill
  596. colorCommands.length = length;
  597. let i;
  598. let command;
  599. let derivedCommand;
  600. let vaIndex = 0;
  601. let uniformMap = primitive._batchTable.getUniformMapCallback()(
  602. classificationPrimitive._uniformMap,
  603. );
  604. const needs2DShader = classificationPrimitive._needs2DShader;
  605. for (i = 0; i < length; i += 2) {
  606. const vertexArray = primitive._va[vaIndex++];
  607. // Stencil depth command
  608. command = colorCommands[i];
  609. if (!defined(command)) {
  610. command = colorCommands[i] = new DrawCommand({
  611. owner: classificationPrimitive,
  612. primitiveType: primitive._primitiveType,
  613. });
  614. }
  615. command.vertexArray = vertexArray;
  616. command.renderState = classificationPrimitive._rsStencilDepthPass;
  617. command.shaderProgram = classificationPrimitive._sp;
  618. command.uniformMap = uniformMap;
  619. command.pass = Pass.TERRAIN_CLASSIFICATION;
  620. derivedCommand = DrawCommand.shallowClone(
  621. command,
  622. command.derivedCommands.tileset,
  623. );
  624. derivedCommand.renderState =
  625. classificationPrimitive._rsStencilDepthPass3DTiles;
  626. derivedCommand.pass = Pass.CESIUM_3D_TILE_CLASSIFICATION;
  627. command.derivedCommands.tileset = derivedCommand;
  628. // Color command
  629. command = colorCommands[i + 1];
  630. if (!defined(command)) {
  631. command = colorCommands[i + 1] = new DrawCommand({
  632. owner: classificationPrimitive,
  633. primitiveType: primitive._primitiveType,
  634. });
  635. }
  636. command.vertexArray = vertexArray;
  637. command.renderState = classificationPrimitive._rsColorPass;
  638. command.shaderProgram = classificationPrimitive._spColor;
  639. command.pass = Pass.TERRAIN_CLASSIFICATION;
  640. const appearance = classificationPrimitive.appearance;
  641. const material = appearance.material;
  642. if (defined(material)) {
  643. uniformMap = combine(uniformMap, material._uniforms);
  644. }
  645. command.uniformMap = uniformMap;
  646. derivedCommand = DrawCommand.shallowClone(
  647. command,
  648. command.derivedCommands.tileset,
  649. );
  650. derivedCommand.pass = Pass.CESIUM_3D_TILE_CLASSIFICATION;
  651. command.derivedCommands.tileset = derivedCommand;
  652. // Derive for 2D if texture coordinates are ever computed
  653. if (needs2DShader) {
  654. // First derive from the terrain command
  655. let derived2DCommand = DrawCommand.shallowClone(
  656. command,
  657. command.derivedCommands.appearance2D,
  658. );
  659. derived2DCommand.shaderProgram = classificationPrimitive._spColor2D;
  660. command.derivedCommands.appearance2D = derived2DCommand;
  661. // Then derive from the 3D Tiles command
  662. derived2DCommand = DrawCommand.shallowClone(
  663. derivedCommand,
  664. derivedCommand.derivedCommands.appearance2D,
  665. );
  666. derived2DCommand.shaderProgram = classificationPrimitive._spColor2D;
  667. derivedCommand.derivedCommands.appearance2D = derived2DCommand;
  668. }
  669. }
  670. const commandsIgnoreShow = classificationPrimitive._commandsIgnoreShow;
  671. const spStencil = classificationPrimitive._spStencil;
  672. let commandIndex = 0;
  673. length = commandsIgnoreShow.length = length / 2;
  674. for (let j = 0; j < length; ++j) {
  675. const commandIgnoreShow = (commandsIgnoreShow[j] = DrawCommand.shallowClone(
  676. colorCommands[commandIndex],
  677. commandsIgnoreShow[j],
  678. ));
  679. commandIgnoreShow.shaderProgram = spStencil;
  680. commandIgnoreShow.pass = Pass.CESIUM_3D_TILE_CLASSIFICATION_IGNORE_SHOW;
  681. commandIndex += 2;
  682. }
  683. }
  684. function createPickCommands(classificationPrimitive, pickCommands) {
  685. const usePickOffsets = classificationPrimitive._usePickOffsets;
  686. const primitive = classificationPrimitive._primitive;
  687. let length = primitive._va.length * 2; // each geometry (pack of vertex attributes) needs 2 commands: front/back stencils and fill
  688. // Fallback for batching same-color geometry instances
  689. let pickOffsets;
  690. let pickIndex = 0;
  691. let pickOffset;
  692. if (usePickOffsets) {
  693. pickOffsets = primitive._pickOffsets;
  694. length = pickOffsets.length * 2;
  695. }
  696. pickCommands.length = length;
  697. let j;
  698. let command;
  699. let derivedCommand;
  700. let vaIndex = 0;
  701. const uniformMap = primitive._batchTable.getUniformMapCallback()(
  702. classificationPrimitive._uniformMap,
  703. );
  704. const needs2DShader = classificationPrimitive._needs2DShader;
  705. for (j = 0; j < length; j += 2) {
  706. let vertexArray = primitive._va[vaIndex++];
  707. if (usePickOffsets) {
  708. pickOffset = pickOffsets[pickIndex++];
  709. vertexArray = primitive._va[pickOffset.index];
  710. }
  711. // Stencil depth command
  712. command = pickCommands[j];
  713. if (!defined(command)) {
  714. command = pickCommands[j] = new DrawCommand({
  715. owner: classificationPrimitive,
  716. primitiveType: primitive._primitiveType,
  717. pickOnly: true,
  718. });
  719. }
  720. command.vertexArray = vertexArray;
  721. command.renderState = classificationPrimitive._rsStencilDepthPass;
  722. command.shaderProgram = classificationPrimitive._sp;
  723. command.uniformMap = uniformMap;
  724. command.pass = Pass.TERRAIN_CLASSIFICATION;
  725. if (usePickOffsets) {
  726. command.offset = pickOffset.offset;
  727. command.count = pickOffset.count;
  728. }
  729. // Derive for 3D Tiles classification
  730. derivedCommand = DrawCommand.shallowClone(
  731. command,
  732. command.derivedCommands.tileset,
  733. );
  734. derivedCommand.renderState =
  735. classificationPrimitive._rsStencilDepthPass3DTiles;
  736. derivedCommand.pass = Pass.CESIUM_3D_TILE_CLASSIFICATION;
  737. command.derivedCommands.tileset = derivedCommand;
  738. // Pick color command
  739. command = pickCommands[j + 1];
  740. if (!defined(command)) {
  741. command = pickCommands[j + 1] = new DrawCommand({
  742. owner: classificationPrimitive,
  743. primitiveType: primitive._primitiveType,
  744. pickOnly: true,
  745. });
  746. }
  747. command.vertexArray = vertexArray;
  748. command.renderState = classificationPrimitive._rsPickPass;
  749. command.shaderProgram = classificationPrimitive._spPick;
  750. command.uniformMap = uniformMap;
  751. command.pass = Pass.TERRAIN_CLASSIFICATION;
  752. if (usePickOffsets) {
  753. command.offset = pickOffset.offset;
  754. command.count = pickOffset.count;
  755. }
  756. derivedCommand = DrawCommand.shallowClone(
  757. command,
  758. command.derivedCommands.tileset,
  759. );
  760. derivedCommand.pass = Pass.CESIUM_3D_TILE_CLASSIFICATION;
  761. command.derivedCommands.tileset = derivedCommand;
  762. // Derive for 2D if texture coordinates are ever computed
  763. if (needs2DShader) {
  764. // First derive from the terrain command
  765. let derived2DCommand = DrawCommand.shallowClone(
  766. command,
  767. command.derivedCommands.pick2D,
  768. );
  769. derived2DCommand.shaderProgram = classificationPrimitive._spPick2D;
  770. command.derivedCommands.pick2D = derived2DCommand;
  771. // Then derive from the 3D Tiles command
  772. derived2DCommand = DrawCommand.shallowClone(
  773. derivedCommand,
  774. derivedCommand.derivedCommands.pick2D,
  775. );
  776. derived2DCommand.shaderProgram = classificationPrimitive._spPick2D;
  777. derivedCommand.derivedCommands.pick2D = derived2DCommand;
  778. }
  779. }
  780. }
  781. function createCommands(
  782. classificationPrimitive,
  783. appearance,
  784. material,
  785. translucent,
  786. twoPasses,
  787. colorCommands,
  788. pickCommands,
  789. ) {
  790. createColorCommands(classificationPrimitive, colorCommands);
  791. createPickCommands(classificationPrimitive, pickCommands);
  792. }
  793. function boundingVolumeIndex(commandIndex, length) {
  794. return Math.floor((commandIndex % length) / 2);
  795. }
  796. function updateAndQueueRenderCommand(
  797. command,
  798. frameState,
  799. modelMatrix,
  800. cull,
  801. boundingVolume,
  802. debugShowBoundingVolume,
  803. ) {
  804. command.modelMatrix = modelMatrix;
  805. command.boundingVolume = boundingVolume;
  806. command.cull = cull;
  807. command.debugShowBoundingVolume = debugShowBoundingVolume;
  808. frameState.commandList.push(command);
  809. }
  810. function updateAndQueuePickCommand(
  811. command,
  812. frameState,
  813. modelMatrix,
  814. cull,
  815. boundingVolume,
  816. ) {
  817. command.modelMatrix = modelMatrix;
  818. command.boundingVolume = boundingVolume;
  819. command.cull = cull;
  820. frameState.commandList.push(command);
  821. }
  822. function updateAndQueueCommands(
  823. classificationPrimitive,
  824. frameState,
  825. colorCommands,
  826. pickCommands,
  827. modelMatrix,
  828. cull,
  829. debugShowBoundingVolume,
  830. twoPasses,
  831. ) {
  832. const primitive = classificationPrimitive._primitive;
  833. Primitive._updateBoundingVolumes(primitive, frameState, modelMatrix);
  834. let boundingVolumes;
  835. if (frameState.mode === SceneMode.SCENE3D) {
  836. boundingVolumes = primitive._boundingSphereWC;
  837. } else if (frameState.mode === SceneMode.COLUMBUS_VIEW) {
  838. boundingVolumes = primitive._boundingSphereCV;
  839. } else if (
  840. frameState.mode === SceneMode.SCENE2D &&
  841. defined(primitive._boundingSphere2D)
  842. ) {
  843. boundingVolumes = primitive._boundingSphere2D;
  844. } else if (defined(primitive._boundingSphereMorph)) {
  845. boundingVolumes = primitive._boundingSphereMorph;
  846. }
  847. const classificationType = classificationPrimitive.classificationType;
  848. const queueTerrainCommands =
  849. classificationType !== ClassificationType.CESIUM_3D_TILE;
  850. const queue3DTilesCommands =
  851. classificationType !== ClassificationType.TERRAIN;
  852. const passes = frameState.passes;
  853. let i;
  854. let boundingVolume;
  855. let command;
  856. if (passes.render) {
  857. const colorLength = colorCommands.length;
  858. for (i = 0; i < colorLength; ++i) {
  859. boundingVolume = boundingVolumes[boundingVolumeIndex(i, colorLength)];
  860. if (queueTerrainCommands) {
  861. command = colorCommands[i];
  862. updateAndQueueRenderCommand(
  863. command,
  864. frameState,
  865. modelMatrix,
  866. cull,
  867. boundingVolume,
  868. debugShowBoundingVolume,
  869. );
  870. }
  871. if (queue3DTilesCommands) {
  872. command = colorCommands[i].derivedCommands.tileset;
  873. updateAndQueueRenderCommand(
  874. command,
  875. frameState,
  876. modelMatrix,
  877. cull,
  878. boundingVolume,
  879. debugShowBoundingVolume,
  880. );
  881. }
  882. }
  883. if (frameState.invertClassification) {
  884. const ignoreShowCommands = classificationPrimitive._commandsIgnoreShow;
  885. const ignoreShowCommandsLength = ignoreShowCommands.length;
  886. for (i = 0; i < ignoreShowCommandsLength; ++i) {
  887. boundingVolume = boundingVolumes[i];
  888. command = ignoreShowCommands[i];
  889. updateAndQueueRenderCommand(
  890. command,
  891. frameState,
  892. modelMatrix,
  893. cull,
  894. boundingVolume,
  895. debugShowBoundingVolume,
  896. );
  897. }
  898. }
  899. }
  900. if (passes.pick) {
  901. const pickLength = pickCommands.length;
  902. const pickOffsets = primitive._pickOffsets;
  903. for (i = 0; i < pickLength; ++i) {
  904. const pickOffset = pickOffsets[boundingVolumeIndex(i, pickLength)];
  905. boundingVolume = boundingVolumes[pickOffset.index];
  906. if (queueTerrainCommands) {
  907. command = pickCommands[i];
  908. updateAndQueuePickCommand(
  909. command,
  910. frameState,
  911. modelMatrix,
  912. cull,
  913. boundingVolume,
  914. );
  915. }
  916. if (queue3DTilesCommands) {
  917. command = pickCommands[i].derivedCommands.tileset;
  918. updateAndQueuePickCommand(
  919. command,
  920. frameState,
  921. modelMatrix,
  922. cull,
  923. boundingVolume,
  924. );
  925. }
  926. }
  927. }
  928. }
  929. /**
  930. * Called when {@link Viewer} or {@link CesiumWidget} render the scene to
  931. * get the draw commands needed to render this primitive.
  932. * <p>
  933. * Do not call this function directly. This is documented just to
  934. * list the exceptions that may be propagated when the scene is rendered:
  935. * </p>
  936. *
  937. * @exception {DeveloperError} All instance geometries must have the same primitiveType.
  938. * @exception {DeveloperError} Appearance and material have a uniform with the same name.
  939. * @exception {DeveloperError} Not all of the geometry instances have the same color attribute.
  940. */
  941. ClassificationPrimitive.prototype.update = function (frameState) {
  942. if (!defined(this._primitive) && !defined(this.geometryInstances)) {
  943. return;
  944. }
  945. let appearance = this.appearance;
  946. if (defined(appearance) && defined(appearance.material)) {
  947. appearance.material.update(frameState.context);
  948. }
  949. const that = this;
  950. const primitiveOptions = this._primitiveOptions;
  951. if (!defined(this._primitive)) {
  952. const instances = Array.isArray(this.geometryInstances)
  953. ? this.geometryInstances
  954. : [this.geometryInstances];
  955. const length = instances.length;
  956. let i;
  957. let instance;
  958. let attributes;
  959. let hasPerColorAttribute = false;
  960. let allColorsSame = true;
  961. let firstColor;
  962. let hasSphericalExtentsAttribute = false;
  963. let hasPlanarExtentsAttributes = false;
  964. if (length > 0) {
  965. attributes = instances[0].attributes;
  966. // Not expecting these to be set by users, should only be set via GroundPrimitive.
  967. // So don't check for mismatch.
  968. hasSphericalExtentsAttribute =
  969. ShadowVolumeAppearance.hasAttributesForSphericalExtents(attributes);
  970. hasPlanarExtentsAttributes =
  971. ShadowVolumeAppearance.hasAttributesForTextureCoordinatePlanes(
  972. attributes,
  973. );
  974. firstColor = attributes.color;
  975. }
  976. for (i = 0; i < length; i++) {
  977. instance = instances[i];
  978. const color = instance.attributes.color;
  979. if (defined(color)) {
  980. hasPerColorAttribute = true;
  981. }
  982. //>>includeStart('debug', pragmas.debug);
  983. else if (hasPerColorAttribute) {
  984. throw new DeveloperError(
  985. "All GeometryInstances must have color attributes to use per-instance color.",
  986. );
  987. }
  988. //>>includeEnd('debug');
  989. allColorsSame =
  990. allColorsSame &&
  991. defined(color) &&
  992. ColorGeometryInstanceAttribute.equals(firstColor, color);
  993. }
  994. // If no attributes exist for computing spherical extents or fragment culling,
  995. // throw if the colors aren't all the same.
  996. if (
  997. !allColorsSame &&
  998. !hasSphericalExtentsAttribute &&
  999. !hasPlanarExtentsAttributes
  1000. ) {
  1001. throw new DeveloperError(
  1002. "All GeometryInstances must have the same color attribute except via GroundPrimitives",
  1003. );
  1004. }
  1005. // default to a color appearance
  1006. if (hasPerColorAttribute && !defined(appearance)) {
  1007. appearance = new PerInstanceColorAppearance({
  1008. flat: true,
  1009. });
  1010. this.appearance = appearance;
  1011. }
  1012. //>>includeStart('debug', pragmas.debug);
  1013. if (
  1014. !hasPerColorAttribute &&
  1015. appearance instanceof PerInstanceColorAppearance
  1016. ) {
  1017. throw new DeveloperError(
  1018. "PerInstanceColorAppearance requires color GeometryInstanceAttributes on all GeometryInstances",
  1019. );
  1020. }
  1021. if (
  1022. defined(appearance.material) &&
  1023. !hasSphericalExtentsAttribute &&
  1024. !hasPlanarExtentsAttributes
  1025. ) {
  1026. throw new DeveloperError(
  1027. "Materials on ClassificationPrimitives are not supported except via GroundPrimitives",
  1028. );
  1029. }
  1030. //>>includeEnd('debug');
  1031. this._usePickOffsets =
  1032. !hasSphericalExtentsAttribute && !hasPlanarExtentsAttributes;
  1033. this._hasSphericalExtentsAttribute = hasSphericalExtentsAttribute;
  1034. this._hasPlanarExtentsAttributes = hasPlanarExtentsAttributes;
  1035. this._hasPerColorAttribute = hasPerColorAttribute;
  1036. const geometryInstances = new Array(length);
  1037. for (i = 0; i < length; ++i) {
  1038. instance = instances[i];
  1039. geometryInstances[i] = new GeometryInstance({
  1040. geometry: instance.geometry,
  1041. attributes: instance.attributes,
  1042. modelMatrix: instance.modelMatrix,
  1043. id: instance.id,
  1044. pickPrimitive: this._pickPrimitive ?? that,
  1045. });
  1046. }
  1047. primitiveOptions.appearance = appearance;
  1048. primitiveOptions.geometryInstances = geometryInstances;
  1049. if (defined(this._createBoundingVolumeFunction)) {
  1050. primitiveOptions._createBoundingVolumeFunction = function (
  1051. frameState,
  1052. geometry,
  1053. ) {
  1054. that._createBoundingVolumeFunction(frameState, geometry);
  1055. };
  1056. }
  1057. primitiveOptions._createRenderStatesFunction = function (
  1058. primitive,
  1059. context,
  1060. appearance,
  1061. twoPasses,
  1062. ) {
  1063. createRenderStates(that, context);
  1064. };
  1065. primitiveOptions._createShaderProgramFunction = function (
  1066. primitive,
  1067. frameState,
  1068. appearance,
  1069. ) {
  1070. createShaderProgram(that, frameState);
  1071. };
  1072. primitiveOptions._createCommandsFunction = function (
  1073. primitive,
  1074. appearance,
  1075. material,
  1076. translucent,
  1077. twoPasses,
  1078. colorCommands,
  1079. pickCommands,
  1080. ) {
  1081. createCommands(
  1082. that,
  1083. undefined,
  1084. undefined,
  1085. true,
  1086. false,
  1087. colorCommands,
  1088. pickCommands,
  1089. );
  1090. };
  1091. if (defined(this._updateAndQueueCommandsFunction)) {
  1092. primitiveOptions._updateAndQueueCommandsFunction = function (
  1093. primitive,
  1094. frameState,
  1095. colorCommands,
  1096. pickCommands,
  1097. modelMatrix,
  1098. cull,
  1099. debugShowBoundingVolume,
  1100. twoPasses,
  1101. ) {
  1102. that._updateAndQueueCommandsFunction(
  1103. primitive,
  1104. frameState,
  1105. colorCommands,
  1106. pickCommands,
  1107. modelMatrix,
  1108. cull,
  1109. debugShowBoundingVolume,
  1110. twoPasses,
  1111. );
  1112. };
  1113. } else {
  1114. primitiveOptions._updateAndQueueCommandsFunction = function (
  1115. primitive,
  1116. frameState,
  1117. colorCommands,
  1118. pickCommands,
  1119. modelMatrix,
  1120. cull,
  1121. debugShowBoundingVolume,
  1122. twoPasses,
  1123. ) {
  1124. updateAndQueueCommands(
  1125. that,
  1126. frameState,
  1127. colorCommands,
  1128. pickCommands,
  1129. modelMatrix,
  1130. cull,
  1131. debugShowBoundingVolume,
  1132. twoPasses,
  1133. );
  1134. };
  1135. }
  1136. this._primitive = new Primitive(primitiveOptions);
  1137. }
  1138. if (
  1139. this.debugShowShadowVolume &&
  1140. !this._debugShowShadowVolume &&
  1141. this._ready
  1142. ) {
  1143. this._debugShowShadowVolume = true;
  1144. this._rsStencilDepthPass = RenderState.fromCache(
  1145. getStencilDepthRenderState(false, false),
  1146. );
  1147. this._rsStencilDepthPass3DTiles = RenderState.fromCache(
  1148. getStencilDepthRenderState(false, true),
  1149. );
  1150. this._rsColorPass = RenderState.fromCache(getColorRenderState(false));
  1151. } else if (!this.debugShowShadowVolume && this._debugShowShadowVolume) {
  1152. this._debugShowShadowVolume = false;
  1153. this._rsStencilDepthPass = RenderState.fromCache(
  1154. getStencilDepthRenderState(true, false),
  1155. );
  1156. this._rsStencilDepthPass3DTiles = RenderState.fromCache(
  1157. getStencilDepthRenderState(true, true),
  1158. );
  1159. this._rsColorPass = RenderState.fromCache(getColorRenderState(true));
  1160. }
  1161. // Update primitive appearance
  1162. if (this._primitive.appearance !== appearance) {
  1163. //>>includeStart('debug', pragmas.debug);
  1164. // Check if the appearance is supported by the geometry attributes
  1165. if (
  1166. !this._hasSphericalExtentsAttribute &&
  1167. !this._hasPlanarExtentsAttributes &&
  1168. defined(appearance.material)
  1169. ) {
  1170. throw new DeveloperError(
  1171. "Materials on ClassificationPrimitives are not supported except via GroundPrimitive",
  1172. );
  1173. }
  1174. if (
  1175. !this._hasPerColorAttribute &&
  1176. appearance instanceof PerInstanceColorAppearance
  1177. ) {
  1178. throw new DeveloperError(
  1179. "PerInstanceColorAppearance requires color GeometryInstanceAttribute",
  1180. );
  1181. }
  1182. //>>includeEnd('debug');
  1183. this._primitive.appearance = appearance;
  1184. }
  1185. this._primitive.show = this.show;
  1186. this._primitive.debugShowBoundingVolume = this.debugShowBoundingVolume;
  1187. this._primitive.update(frameState);
  1188. frameState.afterRender.push(() => {
  1189. if (defined(this._primitive) && this._primitive.ready) {
  1190. this._ready = true;
  1191. if (this.releaseGeometryInstances) {
  1192. this.geometryInstances = undefined;
  1193. }
  1194. }
  1195. });
  1196. };
  1197. /**
  1198. * Returns the modifiable per-instance attributes for a {@link GeometryInstance}.
  1199. *
  1200. * @param {*} id The id of the {@link GeometryInstance}.
  1201. * @returns {object} The typed array in the attribute's format or undefined if the is no instance with id.
  1202. *
  1203. * @exception {DeveloperError} must call update before calling getGeometryInstanceAttributes.
  1204. *
  1205. * @example
  1206. * const attributes = primitive.getGeometryInstanceAttributes('an id');
  1207. * attributes.color = Cesium.ColorGeometryInstanceAttribute.toValue(Cesium.Color.AQUA);
  1208. * attributes.show = Cesium.ShowGeometryInstanceAttribute.toValue(true);
  1209. */
  1210. ClassificationPrimitive.prototype.getGeometryInstanceAttributes = function (
  1211. id,
  1212. ) {
  1213. //>>includeStart('debug', pragmas.debug);
  1214. if (!defined(this._primitive)) {
  1215. throw new DeveloperError(
  1216. "must call update before calling getGeometryInstanceAttributes",
  1217. );
  1218. }
  1219. //>>includeEnd('debug');
  1220. return this._primitive.getGeometryInstanceAttributes(id);
  1221. };
  1222. /**
  1223. * Returns true if this object was destroyed; otherwise, false.
  1224. * <p>
  1225. * If this object was destroyed, it should not be used; calling any function other than
  1226. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  1227. * </p>
  1228. *
  1229. * @returns {boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  1230. *
  1231. * @see ClassificationPrimitive#destroy
  1232. */
  1233. ClassificationPrimitive.prototype.isDestroyed = function () {
  1234. return false;
  1235. };
  1236. /**
  1237. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  1238. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  1239. * <p>
  1240. * Once an object is destroyed, it should not be used; calling any function other than
  1241. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  1242. * assign the return value (<code>undefined</code>) to the object as done in the example.
  1243. * </p>
  1244. *
  1245. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  1246. *
  1247. * @example
  1248. * e = e && e.destroy();
  1249. *
  1250. * @see ClassificationPrimitive#isDestroyed
  1251. */
  1252. ClassificationPrimitive.prototype.destroy = function () {
  1253. this._primitive = this._primitive && this._primitive.destroy();
  1254. this._sp = this._sp && this._sp.destroy();
  1255. this._spPick = this._spPick && this._spPick.destroy();
  1256. this._spColor = this._spColor && this._spColor.destroy();
  1257. // Derived programs, destroyed above if they existed.
  1258. this._spPick2D = undefined;
  1259. this._spColor2D = undefined;
  1260. return destroyObject(this);
  1261. };
  1262. export default ClassificationPrimitive;