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

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412
  1. import BoundingSphere from "../Core/BoundingSphere.js";
  2. import Cartesian3 from "../Core/Cartesian3.js";
  3. import Cartesian4 from "../Core/Cartesian4.js";
  4. import Check from "../Core/Check.js";
  5. import clone from "../Core/clone.js";
  6. import Color from "../Core/Color.js";
  7. import combine from "../Core/combine.js";
  8. import ComponentDatatype from "../Core/ComponentDatatype.js";
  9. import defined from "../Core/defined.js";
  10. import destroyObject from "../Core/destroyObject.js";
  11. import CesiumMath from "../Core/Math.js";
  12. import Matrix4 from "../Core/Matrix4.js";
  13. import oneTimeWarning from "../Core/oneTimeWarning.js";
  14. import OrthographicFrustum from "../Core/OrthographicFrustum.js";
  15. import PrimitiveType from "../Core/PrimitiveType.js";
  16. import RuntimeError from "../Core/RuntimeError.js";
  17. import Transforms from "../Core/Transforms.js";
  18. import Buffer from "../Renderer/Buffer.js";
  19. import BufferUsage from "../Renderer/BufferUsage.js";
  20. import DrawCommand from "../Renderer/DrawCommand.js";
  21. import Pass from "../Renderer/Pass.js";
  22. import RenderState from "../Renderer/RenderState.js";
  23. import ShaderProgram from "../Renderer/ShaderProgram.js";
  24. import VertexArray from "../Renderer/VertexArray.js";
  25. import MersenneTwister from "mersenne-twister";
  26. import BlendingState from "./BlendingState.js";
  27. import Cesium3DTileBatchTable from "./Cesium3DTileBatchTable.js";
  28. import DracoLoader from "./DracoLoader.js";
  29. import getClipAndStyleCode from "./getClipAndStyleCode.js";
  30. import getClippingFunction from "./getClippingFunction.js";
  31. import PntsParser from "./PntsParser.js";
  32. import SceneMode from "./SceneMode.js";
  33. import ShadowMode from "./ShadowMode.js";
  34. import SplitDirection from "./SplitDirection.js";
  35. import Splitter from "./Splitter.js";
  36. import StencilConstants from "./StencilConstants.js";
  37. const DecodingState = {
  38. NEEDS_DECODE: 0,
  39. DECODING: 1,
  40. READY: 2,
  41. FAILED: 3,
  42. };
  43. /**
  44. * Represents the contents of a
  45. * {@link https://github.com/CesiumGS/3d-tiles/tree/main/specification/TileFormats/PointCloud|Point Cloud}
  46. * tile. Used internally by {@link TimeDynamicPointCloud}.
  47. *
  48. * @alias PointCloud
  49. * @constructor
  50. *
  51. * @see TimeDynamicPointCloud
  52. *
  53. * @private
  54. */
  55. function PointCloud(options) {
  56. //>>includeStart('debug', pragmas.debug);
  57. Check.typeOf.object("options", options);
  58. Check.typeOf.object("options.arrayBuffer", options.arrayBuffer);
  59. //>>includeEnd('debug');
  60. // Hold onto the payload until the render resources are created
  61. this._parsedContent = undefined;
  62. this._drawCommand = undefined;
  63. this._isTranslucent = false;
  64. this._styleTranslucent = false;
  65. this._constantColor = Color.clone(Color.DARKGRAY);
  66. this._highlightColor = Color.clone(Color.WHITE);
  67. this._pointSize = 1.0;
  68. this._rtcCenter = undefined;
  69. this._quantizedVolumeScale = undefined;
  70. this._quantizedVolumeOffset = undefined;
  71. // These values are used to regenerate the shader when the style changes
  72. this._styleableShaderAttributes = undefined;
  73. this._isQuantized = false;
  74. this._isOctEncoded16P = false;
  75. this._isRGB565 = false;
  76. this._hasColors = false;
  77. this._hasNormals = false;
  78. this._hasBatchIds = false;
  79. // Draco
  80. this._decodingState = DecodingState.READY;
  81. this._dequantizeInShader = true;
  82. this._isQuantizedDraco = false;
  83. this._isOctEncodedDraco = false;
  84. this._quantizedRange = 0.0;
  85. this._octEncodedRange = 0.0;
  86. // Use per-point normals to hide back-facing points.
  87. this.backFaceCulling = false;
  88. this._backFaceCulling = false;
  89. // Whether to enable normal shading
  90. this.normalShading = true;
  91. this._normalShading = true;
  92. this._opaqueRenderState = undefined;
  93. this._translucentRenderState = undefined;
  94. this._mode = undefined;
  95. this._ready = false;
  96. this._pointsLength = 0;
  97. this._geometryByteLength = 0;
  98. this._vertexShaderLoaded = options.vertexShaderLoaded;
  99. this._fragmentShaderLoaded = options.fragmentShaderLoaded;
  100. this._uniformMapLoaded = options.uniformMapLoaded;
  101. this._batchTableLoaded = options.batchTableLoaded;
  102. this._pickIdLoaded = options.pickIdLoaded;
  103. this._opaquePass = options.opaquePass ?? Pass.OPAQUE;
  104. this._cull = options.cull ?? true;
  105. this.style = undefined;
  106. this._style = undefined;
  107. this.styleDirty = false;
  108. this.modelMatrix = Matrix4.clone(Matrix4.IDENTITY);
  109. this._modelMatrix = Matrix4.clone(Matrix4.IDENTITY);
  110. this.time = 0.0; // For styling
  111. this.shadows = ShadowMode.ENABLED;
  112. this._boundingSphere = undefined;
  113. this.clippingPlanes = undefined;
  114. this.isClipped = false;
  115. this.clippingPlanesDirty = false;
  116. // If defined, use this matrix to position the clipping planes instead of the modelMatrix.
  117. // This is so that when point clouds are part of a tileset they all get clipped relative
  118. // to the root tile.
  119. this.clippingPlanesOriginMatrix = undefined;
  120. this.attenuation = false;
  121. this._attenuation = false;
  122. // Options for geometric error based attenuation
  123. this.geometricError = 0.0;
  124. this.geometricErrorScale = 1.0;
  125. this.maximumAttenuation = this._pointSize;
  126. /**
  127. * The {@link SplitDirection} to apply to this point cloud.
  128. *
  129. * @type {SplitDirection}
  130. * @default {@link SplitDirection.NONE}
  131. */
  132. this.splitDirection = options.splitDirection ?? SplitDirection.NONE;
  133. this._splittingEnabled = false;
  134. this._error = undefined;
  135. initialize(this, options);
  136. }
  137. Object.defineProperties(PointCloud.prototype, {
  138. pointsLength: {
  139. get: function () {
  140. return this._pointsLength;
  141. },
  142. },
  143. geometryByteLength: {
  144. get: function () {
  145. return this._geometryByteLength;
  146. },
  147. },
  148. ready: {
  149. get: function () {
  150. return this._ready;
  151. },
  152. },
  153. color: {
  154. get: function () {
  155. return Color.clone(this._highlightColor);
  156. },
  157. set: function (value) {
  158. this._highlightColor = Color.clone(value, this._highlightColor);
  159. },
  160. },
  161. boundingSphere: {
  162. get: function () {
  163. if (defined(this._drawCommand)) {
  164. return this._drawCommand.boundingVolume;
  165. }
  166. return undefined;
  167. },
  168. set: function (value) {
  169. this._boundingSphere = BoundingSphere.clone(value, this._boundingSphere);
  170. },
  171. },
  172. });
  173. function initialize(pointCloud, options) {
  174. const parsedContent = PntsParser.parse(
  175. options.arrayBuffer,
  176. options.byteOffset,
  177. );
  178. pointCloud._parsedContent = parsedContent;
  179. pointCloud._rtcCenter = parsedContent.rtcCenter;
  180. pointCloud._hasNormals = parsedContent.hasNormals;
  181. pointCloud._hasColors = parsedContent.hasColors;
  182. pointCloud._hasBatchIds = parsedContent.hasBatchIds;
  183. pointCloud._isTranslucent = parsedContent.isTranslucent;
  184. // If points are not batched and there are per-point properties, use the
  185. // properties as metadata for styling purposes.
  186. if (!parsedContent.hasBatchIds && defined(parsedContent.batchTableBinary)) {
  187. parsedContent.styleableProperties =
  188. Cesium3DTileBatchTable.getBinaryProperties(
  189. parsedContent.pointsLength,
  190. parsedContent.batchTableJson,
  191. parsedContent.batchTableBinary,
  192. );
  193. }
  194. if (defined(parsedContent.draco)) {
  195. const draco = parsedContent.draco;
  196. pointCloud._decodingState = DecodingState.NEEDS_DECODE;
  197. draco.dequantizeInShader = pointCloud._dequantizeInShader;
  198. }
  199. const positions = parsedContent.positions;
  200. if (defined(positions)) {
  201. pointCloud._isQuantized = positions.isQuantized;
  202. pointCloud._quantizedVolumeScale = positions.quantizedVolumeScale;
  203. pointCloud._quantizedVolumeOffset = positions.quantizedVolumeOffset;
  204. pointCloud._quantizedRange = positions.quantizedRange;
  205. }
  206. const normals = parsedContent.normals;
  207. if (defined(normals)) {
  208. pointCloud._isOctEncoded16P = normals.octEncoded;
  209. }
  210. const colors = parsedContent.colors;
  211. if (defined(colors)) {
  212. if (defined(colors.constantColor)) {
  213. pointCloud._constantColor = Color.clone(
  214. colors.constantColor,
  215. pointCloud._constantColor,
  216. );
  217. // Constant colors are handled as a uniform rather than a vertex
  218. // attribute.
  219. pointCloud._hasColors = false;
  220. }
  221. pointCloud._isRGB565 = colors.isRGB565;
  222. }
  223. // PntsParser parses BATCH_ID as _FEATURE_ID_0 for EXT_mesh_features.
  224. // These properties aren't used but rename them to BATCH_ID to avoid
  225. // confusion when debugging.
  226. const batchIds = parsedContent.batchIds;
  227. if (defined(parsedContent.batchIds)) {
  228. batchIds.name = "BATCH_ID";
  229. batchIds.semantic = "BATCH_ID";
  230. batchIds.setIndex = undefined;
  231. }
  232. if (parsedContent.hasBatchIds) {
  233. pointCloud._batchTableLoaded(
  234. parsedContent.batchLength,
  235. parsedContent.batchTableJson,
  236. parsedContent.batchTableBinary,
  237. );
  238. }
  239. pointCloud._pointsLength = parsedContent.pointsLength;
  240. }
  241. const scratchMin = new Cartesian3();
  242. const scratchMax = new Cartesian3();
  243. const scratchPosition = new Cartesian3();
  244. // Use MersenneTwister directly to avoid interfering with CesiumMath.nextRandomNumber()
  245. // See https://github.com/CesiumGS/cesium/issues/9730
  246. let randomNumberGenerator;
  247. let randomValues;
  248. function getRandomValues(samplesLength) {
  249. // Use same random values across all runs
  250. if (!defined(randomValues)) {
  251. // Use MersenneTwister directly to avoid interfering with CesiumMath.nextRandomNumber()
  252. // See https://github.com/CesiumGS/cesium/issues/9730
  253. randomNumberGenerator = new MersenneTwister(0);
  254. randomValues = new Array(samplesLength);
  255. for (let i = 0; i < samplesLength; ++i) {
  256. randomValues[i] = randomNumberGenerator.random();
  257. }
  258. }
  259. return randomValues;
  260. }
  261. function computeApproximateBoundingSphereFromPositions(positions) {
  262. const maximumSamplesLength = 20;
  263. const pointsLength = positions.length / 3;
  264. const samplesLength = Math.min(pointsLength, maximumSamplesLength);
  265. const randomValues = getRandomValues(maximumSamplesLength);
  266. const maxValue = Number.MAX_VALUE;
  267. const minValue = -Number.MAX_VALUE;
  268. const min = Cartesian3.fromElements(maxValue, maxValue, maxValue, scratchMin);
  269. const max = Cartesian3.fromElements(minValue, minValue, minValue, scratchMax);
  270. for (let i = 0; i < samplesLength; ++i) {
  271. const index = Math.floor(randomValues[i] * pointsLength);
  272. const position = Cartesian3.unpack(positions, index * 3, scratchPosition);
  273. Cartesian3.minimumByComponent(min, position, min);
  274. Cartesian3.maximumByComponent(max, position, max);
  275. }
  276. const boundingSphere = BoundingSphere.fromCornerPoints(min, max);
  277. boundingSphere.radius += CesiumMath.EPSILON2; // To avoid radius of zero
  278. return boundingSphere;
  279. }
  280. function prepareVertexAttribute(typedArray, name) {
  281. // WebGL does not support UNSIGNED_INT, INT, or DOUBLE vertex attributes. Convert these to FLOAT.
  282. const componentDatatype = ComponentDatatype.fromTypedArray(typedArray);
  283. if (
  284. componentDatatype === ComponentDatatype.INT ||
  285. componentDatatype === ComponentDatatype.UNSIGNED_INT ||
  286. componentDatatype === ComponentDatatype.DOUBLE
  287. ) {
  288. oneTimeWarning(
  289. "Cast pnts property to floats",
  290. `Point cloud property "${name}" will be cast to a float array because INT, UNSIGNED_INT, and DOUBLE are not valid WebGL vertex attribute types. Some precision may be lost.`,
  291. );
  292. return new Float32Array(typedArray);
  293. }
  294. return typedArray;
  295. }
  296. const scratchPointSizeAndTimeAndGeometricErrorAndDepthMultiplier =
  297. new Cartesian4();
  298. const scratchQuantizedVolumeScaleAndOctEncodedRange = new Cartesian4();
  299. const scratchColor = new Color();
  300. const positionLocation = 0;
  301. const colorLocation = 1;
  302. const normalLocation = 2;
  303. const batchIdLocation = 3;
  304. const numberOfAttributes = 4;
  305. const scratchClippingPlanesMatrix = new Matrix4();
  306. const scratchInverseTransposeClippingPlanesMatrix = new Matrix4();
  307. function createResources(pointCloud, frameState) {
  308. const context = frameState.context;
  309. const parsedContent = pointCloud._parsedContent;
  310. const pointsLength = pointCloud._pointsLength;
  311. const positions = parsedContent.positions;
  312. const colors = parsedContent.colors;
  313. const normals = parsedContent.normals;
  314. const batchIds = parsedContent.batchIds;
  315. const styleableProperties = parsedContent.styleableProperties;
  316. const hasStyleableProperties = defined(styleableProperties);
  317. const isQuantized = pointCloud._isQuantized;
  318. const isQuantizedDraco = pointCloud._isQuantizedDraco;
  319. const isOctEncoded16P = pointCloud._isOctEncoded16P;
  320. const isOctEncodedDraco = pointCloud._isOctEncodedDraco;
  321. const quantizedRange = pointCloud._quantizedRange;
  322. const octEncodedRange = pointCloud._octEncodedRange;
  323. const isRGB565 = pointCloud._isRGB565;
  324. const isTranslucent = pointCloud._isTranslucent;
  325. const hasColors = pointCloud._hasColors;
  326. const hasNormals = pointCloud._hasNormals;
  327. const hasBatchIds = pointCloud._hasBatchIds;
  328. let componentsPerAttribute;
  329. let componentDatatype;
  330. const styleableVertexAttributes = [];
  331. const styleableShaderAttributes = {};
  332. pointCloud._styleableShaderAttributes = styleableShaderAttributes;
  333. if (hasStyleableProperties) {
  334. let attributeLocation = numberOfAttributes;
  335. for (const name in styleableProperties) {
  336. if (styleableProperties.hasOwnProperty(name)) {
  337. const property = styleableProperties[name];
  338. const typedArray = prepareVertexAttribute(property.typedArray, name);
  339. componentsPerAttribute = property.componentCount;
  340. componentDatatype = ComponentDatatype.fromTypedArray(typedArray);
  341. const vertexBuffer = Buffer.createVertexBuffer({
  342. context: context,
  343. typedArray: typedArray,
  344. usage: BufferUsage.STATIC_DRAW,
  345. });
  346. pointCloud._geometryByteLength += vertexBuffer.sizeInBytes;
  347. const vertexAttribute = {
  348. index: attributeLocation,
  349. vertexBuffer: vertexBuffer,
  350. componentsPerAttribute: componentsPerAttribute,
  351. componentDatatype: componentDatatype,
  352. normalize: false,
  353. offsetInBytes: 0,
  354. strideInBytes: 0,
  355. };
  356. styleableVertexAttributes.push(vertexAttribute);
  357. styleableShaderAttributes[name] = {
  358. location: attributeLocation,
  359. componentCount: componentsPerAttribute,
  360. };
  361. ++attributeLocation;
  362. }
  363. }
  364. }
  365. const positionsVertexBuffer = Buffer.createVertexBuffer({
  366. context: context,
  367. typedArray: positions.typedArray,
  368. usage: BufferUsage.STATIC_DRAW,
  369. });
  370. pointCloud._geometryByteLength += positionsVertexBuffer.sizeInBytes;
  371. let colorsVertexBuffer;
  372. if (hasColors) {
  373. colorsVertexBuffer = Buffer.createVertexBuffer({
  374. context: context,
  375. typedArray: colors.typedArray,
  376. usage: BufferUsage.STATIC_DRAW,
  377. });
  378. pointCloud._geometryByteLength += colorsVertexBuffer.sizeInBytes;
  379. }
  380. let normalsVertexBuffer;
  381. if (hasNormals) {
  382. normalsVertexBuffer = Buffer.createVertexBuffer({
  383. context: context,
  384. typedArray: normals.typedArray,
  385. usage: BufferUsage.STATIC_DRAW,
  386. });
  387. pointCloud._geometryByteLength += normalsVertexBuffer.sizeInBytes;
  388. }
  389. let batchIdsVertexBuffer;
  390. if (hasBatchIds) {
  391. batchIds.typedArray = prepareVertexAttribute(
  392. batchIds.typedArray,
  393. "batchIds",
  394. );
  395. batchIdsVertexBuffer = Buffer.createVertexBuffer({
  396. context: context,
  397. typedArray: batchIds.typedArray,
  398. usage: BufferUsage.STATIC_DRAW,
  399. });
  400. pointCloud._geometryByteLength += batchIdsVertexBuffer.sizeInBytes;
  401. }
  402. let attributes = [];
  403. if (isQuantized) {
  404. componentDatatype = ComponentDatatype.UNSIGNED_SHORT;
  405. } else if (isQuantizedDraco) {
  406. componentDatatype =
  407. quantizedRange <= 255
  408. ? ComponentDatatype.UNSIGNED_BYTE
  409. : ComponentDatatype.UNSIGNED_SHORT;
  410. } else {
  411. componentDatatype = ComponentDatatype.FLOAT;
  412. }
  413. attributes.push({
  414. index: positionLocation,
  415. vertexBuffer: positionsVertexBuffer,
  416. componentsPerAttribute: 3,
  417. componentDatatype: componentDatatype,
  418. normalize: false,
  419. offsetInBytes: 0,
  420. strideInBytes: 0,
  421. });
  422. if (pointCloud._cull) {
  423. if (isQuantized || isQuantizedDraco) {
  424. pointCloud._boundingSphere = BoundingSphere.fromCornerPoints(
  425. Cartesian3.ZERO,
  426. pointCloud._quantizedVolumeScale,
  427. );
  428. } else {
  429. pointCloud._boundingSphere =
  430. computeApproximateBoundingSphereFromPositions(positions.typedArray);
  431. }
  432. }
  433. if (hasColors) {
  434. if (isRGB565) {
  435. attributes.push({
  436. index: colorLocation,
  437. vertexBuffer: colorsVertexBuffer,
  438. componentsPerAttribute: 1,
  439. componentDatatype: ComponentDatatype.UNSIGNED_SHORT,
  440. normalize: false,
  441. offsetInBytes: 0,
  442. strideInBytes: 0,
  443. });
  444. } else {
  445. const colorComponentsPerAttribute = isTranslucent ? 4 : 3;
  446. attributes.push({
  447. index: colorLocation,
  448. vertexBuffer: colorsVertexBuffer,
  449. componentsPerAttribute: colorComponentsPerAttribute,
  450. componentDatatype: ComponentDatatype.UNSIGNED_BYTE,
  451. normalize: true,
  452. offsetInBytes: 0,
  453. strideInBytes: 0,
  454. });
  455. }
  456. }
  457. if (hasNormals) {
  458. if (isOctEncoded16P) {
  459. componentsPerAttribute = 2;
  460. componentDatatype = ComponentDatatype.UNSIGNED_BYTE;
  461. } else if (isOctEncodedDraco) {
  462. componentsPerAttribute = 2;
  463. componentDatatype =
  464. octEncodedRange <= 255
  465. ? ComponentDatatype.UNSIGNED_BYTE
  466. : ComponentDatatype.UNSIGNED_SHORT;
  467. } else {
  468. componentsPerAttribute = 3;
  469. componentDatatype = ComponentDatatype.FLOAT;
  470. }
  471. attributes.push({
  472. index: normalLocation,
  473. vertexBuffer: normalsVertexBuffer,
  474. componentsPerAttribute: componentsPerAttribute,
  475. componentDatatype: componentDatatype,
  476. normalize: false,
  477. offsetInBytes: 0,
  478. strideInBytes: 0,
  479. });
  480. }
  481. if (hasBatchIds) {
  482. attributes.push({
  483. index: batchIdLocation,
  484. vertexBuffer: batchIdsVertexBuffer,
  485. componentsPerAttribute: 1,
  486. componentDatatype: ComponentDatatype.fromTypedArray(batchIds.typedArray),
  487. normalize: false,
  488. offsetInBytes: 0,
  489. strideInBytes: 0,
  490. });
  491. }
  492. if (hasStyleableProperties) {
  493. attributes = attributes.concat(styleableVertexAttributes);
  494. }
  495. const vertexArray = new VertexArray({
  496. context: context,
  497. attributes: attributes,
  498. });
  499. const opaqueRenderState = {
  500. depthTest: {
  501. enabled: true,
  502. },
  503. };
  504. const translucentRenderState = {
  505. depthTest: {
  506. enabled: true,
  507. },
  508. depthMask: false,
  509. blending: BlendingState.ALPHA_BLEND,
  510. };
  511. if (pointCloud._opaquePass === Pass.CESIUM_3D_TILE) {
  512. opaqueRenderState.stencilTest = StencilConstants.setCesium3DTileBit();
  513. opaqueRenderState.stencilMask = StencilConstants.CESIUM_3D_TILE_MASK;
  514. translucentRenderState.stencilTest = StencilConstants.setCesium3DTileBit();
  515. translucentRenderState.stencilMask = StencilConstants.CESIUM_3D_TILE_MASK;
  516. }
  517. pointCloud._opaqueRenderState = RenderState.fromCache(opaqueRenderState);
  518. pointCloud._translucentRenderState = RenderState.fromCache(
  519. translucentRenderState,
  520. );
  521. pointCloud._drawCommand = new DrawCommand({
  522. boundingVolume: new BoundingSphere(),
  523. cull: pointCloud._cull,
  524. modelMatrix: new Matrix4(),
  525. primitiveType: PrimitiveType.POINTS,
  526. vertexArray: vertexArray,
  527. count: pointsLength,
  528. shaderProgram: undefined, // Updated in createShaders
  529. uniformMap: undefined, // Updated in createShaders
  530. renderState: isTranslucent
  531. ? pointCloud._translucentRenderState
  532. : pointCloud._opaqueRenderState,
  533. pass: isTranslucent ? Pass.TRANSLUCENT : pointCloud._opaquePass,
  534. owner: pointCloud,
  535. castShadows: false,
  536. receiveShadows: false,
  537. pickId: pointCloud._pickIdLoaded(),
  538. });
  539. }
  540. function createUniformMap(pointCloud, frameState) {
  541. const context = frameState.context;
  542. const isQuantized = pointCloud._isQuantized;
  543. const isQuantizedDraco = pointCloud._isQuantizedDraco;
  544. const isOctEncodedDraco = pointCloud._isOctEncodedDraco;
  545. let uniformMap = {
  546. u_pointSizeAndTimeAndGeometricErrorAndDepthMultiplier: function () {
  547. const scratch =
  548. scratchPointSizeAndTimeAndGeometricErrorAndDepthMultiplier;
  549. scratch.x = pointCloud._attenuation
  550. ? pointCloud.maximumAttenuation
  551. : pointCloud._pointSize;
  552. scratch.x *= frameState.pixelRatio;
  553. scratch.y = pointCloud.time;
  554. if (pointCloud._attenuation) {
  555. const frustum = frameState.camera.frustum;
  556. let depthMultiplier;
  557. // Attenuation is maximumAttenuation in 2D/ortho
  558. if (
  559. frameState.mode === SceneMode.SCENE2D ||
  560. frustum instanceof OrthographicFrustum
  561. ) {
  562. depthMultiplier = Number.POSITIVE_INFINITY;
  563. } else {
  564. depthMultiplier =
  565. context.drawingBufferHeight /
  566. frameState.camera.frustum.sseDenominator;
  567. }
  568. scratch.z = pointCloud.geometricError * pointCloud.geometricErrorScale;
  569. scratch.w = depthMultiplier;
  570. }
  571. return scratch;
  572. },
  573. u_highlightColor: function () {
  574. return pointCloud._highlightColor;
  575. },
  576. u_constantColor: function () {
  577. return pointCloud._constantColor;
  578. },
  579. u_clippingPlanes: function () {
  580. const clippingPlanes = pointCloud.clippingPlanes;
  581. const isClipped = pointCloud.isClipped;
  582. return isClipped ? clippingPlanes.texture : context.defaultTexture;
  583. },
  584. u_clippingPlanesEdgeStyle: function () {
  585. const clippingPlanes = pointCloud.clippingPlanes;
  586. if (!defined(clippingPlanes)) {
  587. return Color.TRANSPARENT;
  588. }
  589. const style = Color.clone(clippingPlanes.edgeColor, scratchColor);
  590. style.alpha = clippingPlanes.edgeWidth;
  591. return style;
  592. },
  593. u_clippingPlanesMatrix: function () {
  594. const clippingPlanes = pointCloud.clippingPlanes;
  595. if (!defined(clippingPlanes)) {
  596. return Matrix4.IDENTITY;
  597. }
  598. const clippingPlanesOriginMatrix =
  599. pointCloud.clippingPlanesOriginMatrix ?? pointCloud._modelMatrix;
  600. Matrix4.multiply(
  601. context.uniformState.view3D,
  602. clippingPlanesOriginMatrix,
  603. scratchClippingPlanesMatrix,
  604. );
  605. const transform = Matrix4.multiply(
  606. scratchClippingPlanesMatrix,
  607. clippingPlanes.modelMatrix,
  608. scratchClippingPlanesMatrix,
  609. );
  610. return Matrix4.inverseTranspose(
  611. transform,
  612. scratchInverseTransposeClippingPlanesMatrix,
  613. );
  614. },
  615. };
  616. Splitter.addUniforms(pointCloud, uniformMap);
  617. if (isQuantized || isQuantizedDraco || isOctEncodedDraco) {
  618. uniformMap = combine(uniformMap, {
  619. u_quantizedVolumeScaleAndOctEncodedRange: function () {
  620. const scratch = scratchQuantizedVolumeScaleAndOctEncodedRange;
  621. if (defined(pointCloud._quantizedVolumeScale)) {
  622. const scale = Cartesian3.clone(
  623. pointCloud._quantizedVolumeScale,
  624. scratch,
  625. );
  626. Cartesian3.divideByScalar(scale, pointCloud._quantizedRange, scratch);
  627. }
  628. scratch.w = pointCloud._octEncodedRange;
  629. return scratch;
  630. },
  631. });
  632. }
  633. if (defined(pointCloud._uniformMapLoaded)) {
  634. uniformMap = pointCloud._uniformMapLoaded(uniformMap);
  635. }
  636. pointCloud._drawCommand.uniformMap = uniformMap;
  637. }
  638. function getStyleablePropertyIds(source, propertyIds) {
  639. // Get all the property IDs used by this style
  640. const regex = /czm_3dtiles_property_(\d+)/g;
  641. let matches = regex.exec(source);
  642. while (matches !== null) {
  643. const id = parseInt(matches[1]);
  644. if (propertyIds.indexOf(id) === -1) {
  645. propertyIds.push(id);
  646. }
  647. matches = regex.exec(source);
  648. }
  649. }
  650. function getBuiltinPropertyNames(source, propertyNames) {
  651. // Get all the builtin property names used by this style, ignoring the function signature
  652. source = source.slice(source.indexOf("\n"));
  653. const regex = /czm_3dtiles_builtin_property_(\w+)/g;
  654. let matches = regex.exec(source);
  655. while (matches !== null) {
  656. const name = matches[1];
  657. if (propertyNames.indexOf(name) === -1) {
  658. propertyNames.push(name);
  659. }
  660. matches = regex.exec(source);
  661. }
  662. }
  663. function getVertexAttribute(vertexArray, index) {
  664. const numberOfAttributes = vertexArray.numberOfAttributes;
  665. for (let i = 0; i < numberOfAttributes; ++i) {
  666. const attribute = vertexArray.getAttribute(i);
  667. if (attribute.index === index) {
  668. return attribute;
  669. }
  670. }
  671. }
  672. const builtinVariableSubstitutionMap = {
  673. POSITION: "czm_3dtiles_builtin_property_POSITION",
  674. POSITION_ABSOLUTE: "czm_3dtiles_builtin_property_POSITION_ABSOLUTE",
  675. COLOR: "czm_3dtiles_builtin_property_COLOR",
  676. NORMAL: "czm_3dtiles_builtin_property_NORMAL",
  677. };
  678. function createShaders(pointCloud, frameState, style) {
  679. let i;
  680. let name;
  681. let attribute;
  682. const context = frameState.context;
  683. const hasStyle = defined(style);
  684. const isQuantized = pointCloud._isQuantized;
  685. const isQuantizedDraco = pointCloud._isQuantizedDraco;
  686. const isOctEncoded16P = pointCloud._isOctEncoded16P;
  687. const isOctEncodedDraco = pointCloud._isOctEncodedDraco;
  688. const isRGB565 = pointCloud._isRGB565;
  689. const isTranslucent = pointCloud._isTranslucent;
  690. const hasColors = pointCloud._hasColors;
  691. const hasNormals = pointCloud._hasNormals;
  692. const hasBatchIds = pointCloud._hasBatchIds;
  693. const backFaceCulling = pointCloud._backFaceCulling;
  694. const normalShading = pointCloud._normalShading;
  695. const vertexArray = pointCloud._drawCommand.vertexArray;
  696. const clippingPlanes = pointCloud.clippingPlanes;
  697. const attenuation = pointCloud._attenuation;
  698. let colorStyleFunction;
  699. let showStyleFunction;
  700. let pointSizeStyleFunction;
  701. let styleTranslucent = isTranslucent;
  702. const variableSubstitutionMap = clone(builtinVariableSubstitutionMap);
  703. const propertyIdToAttributeMap = {};
  704. const styleableShaderAttributes = pointCloud._styleableShaderAttributes;
  705. for (name in styleableShaderAttributes) {
  706. if (styleableShaderAttributes.hasOwnProperty(name)) {
  707. attribute = styleableShaderAttributes[name];
  708. variableSubstitutionMap[name] =
  709. `czm_3dtiles_property_${attribute.location}`;
  710. propertyIdToAttributeMap[attribute.location] = attribute;
  711. }
  712. }
  713. if (hasStyle) {
  714. const shaderState = {
  715. translucent: false,
  716. };
  717. const parameterList =
  718. "(" +
  719. "vec3 czm_3dtiles_builtin_property_POSITION, " +
  720. "vec3 czm_3dtiles_builtin_property_POSITION_ABSOLUTE, " +
  721. "vec4 czm_3dtiles_builtin_property_COLOR, " +
  722. "vec3 czm_3dtiles_builtin_property_NORMAL" +
  723. ")";
  724. colorStyleFunction = style.getColorShaderFunction(
  725. `getColorFromStyle${parameterList}`,
  726. variableSubstitutionMap,
  727. shaderState,
  728. );
  729. showStyleFunction = style.getShowShaderFunction(
  730. `getShowFromStyle${parameterList}`,
  731. variableSubstitutionMap,
  732. shaderState,
  733. );
  734. pointSizeStyleFunction = style.getPointSizeShaderFunction(
  735. `getPointSizeFromStyle${parameterList}`,
  736. variableSubstitutionMap,
  737. shaderState,
  738. );
  739. if (defined(colorStyleFunction) && shaderState.translucent) {
  740. styleTranslucent = true;
  741. }
  742. }
  743. pointCloud._styleTranslucent = styleTranslucent;
  744. const hasColorStyle = defined(colorStyleFunction);
  745. const hasShowStyle = defined(showStyleFunction);
  746. const hasPointSizeStyle = defined(pointSizeStyleFunction);
  747. const hasClippedContent = pointCloud.isClipped;
  748. // Get the properties in use by the style
  749. const styleablePropertyIds = [];
  750. const builtinPropertyNames = [];
  751. if (hasColorStyle) {
  752. getStyleablePropertyIds(colorStyleFunction, styleablePropertyIds);
  753. getBuiltinPropertyNames(colorStyleFunction, builtinPropertyNames);
  754. }
  755. if (hasShowStyle) {
  756. getStyleablePropertyIds(showStyleFunction, styleablePropertyIds);
  757. getBuiltinPropertyNames(showStyleFunction, builtinPropertyNames);
  758. }
  759. if (hasPointSizeStyle) {
  760. getStyleablePropertyIds(pointSizeStyleFunction, styleablePropertyIds);
  761. getBuiltinPropertyNames(pointSizeStyleFunction, builtinPropertyNames);
  762. }
  763. const usesColorSemantic = builtinPropertyNames.indexOf("COLOR") >= 0;
  764. const usesNormalSemantic = builtinPropertyNames.indexOf("NORMAL") >= 0;
  765. if (usesNormalSemantic && !hasNormals) {
  766. throw new RuntimeError(
  767. "Style references the NORMAL semantic but the point cloud does not have normals",
  768. );
  769. }
  770. // Disable vertex attributes that aren't used in the style, enable attributes that are
  771. for (name in styleableShaderAttributes) {
  772. if (styleableShaderAttributes.hasOwnProperty(name)) {
  773. attribute = styleableShaderAttributes[name];
  774. const enabled = styleablePropertyIds.indexOf(attribute.location) >= 0;
  775. const vertexAttribute = getVertexAttribute(
  776. vertexArray,
  777. attribute.location,
  778. );
  779. vertexAttribute.enabled = enabled;
  780. }
  781. }
  782. const usesColors = hasColors && (!hasColorStyle || usesColorSemantic);
  783. if (hasColors) {
  784. // Disable the color vertex attribute if the color style does not reference the color semantic
  785. const colorVertexAttribute = getVertexAttribute(vertexArray, colorLocation);
  786. colorVertexAttribute.enabled = usesColors;
  787. }
  788. const usesNormals =
  789. hasNormals && (normalShading || backFaceCulling || usesNormalSemantic);
  790. if (hasNormals) {
  791. // Disable the normal vertex attribute if normals are not used
  792. const normalVertexAttribute = getVertexAttribute(
  793. vertexArray,
  794. normalLocation,
  795. );
  796. normalVertexAttribute.enabled = usesNormals;
  797. }
  798. const attributeLocations = {
  799. a_position: positionLocation,
  800. };
  801. if (usesColors) {
  802. attributeLocations.a_color = colorLocation;
  803. }
  804. if (usesNormals) {
  805. attributeLocations.a_normal = normalLocation;
  806. }
  807. if (hasBatchIds) {
  808. attributeLocations.a_batchId = batchIdLocation;
  809. }
  810. let attributeDeclarations = "";
  811. const length = styleablePropertyIds.length;
  812. for (i = 0; i < length; ++i) {
  813. const propertyId = styleablePropertyIds[i];
  814. attribute = propertyIdToAttributeMap[propertyId];
  815. const componentCount = attribute.componentCount;
  816. const attributeName = `czm_3dtiles_property_${propertyId}`;
  817. let attributeType;
  818. if (componentCount === 1) {
  819. attributeType = "float";
  820. } else {
  821. attributeType = `vec${componentCount}`;
  822. }
  823. attributeDeclarations += `in ${attributeType} ${attributeName}; \n`;
  824. attributeLocations[attributeName] = attribute.location;
  825. }
  826. createUniformMap(pointCloud, frameState);
  827. let vs =
  828. "in vec3 a_position; \n" +
  829. "out vec4 v_color; \n" +
  830. "uniform vec4 u_pointSizeAndTimeAndGeometricErrorAndDepthMultiplier; \n" +
  831. "uniform vec4 u_constantColor; \n" +
  832. "uniform vec4 u_highlightColor; \n";
  833. // The time variable is named differently for compatibility with custom
  834. // shaders in Model.
  835. vs += "float u_pointSize; \n" + "float tiles3d_tileset_time; \n";
  836. if (attenuation) {
  837. vs += "float u_geometricError; \n" + "float u_depthMultiplier; \n";
  838. }
  839. vs += attributeDeclarations;
  840. if (usesColors) {
  841. if (isTranslucent) {
  842. vs += "in vec4 a_color; \n";
  843. } else if (isRGB565) {
  844. vs +=
  845. "in float a_color; \n" +
  846. "const float SHIFT_RIGHT_11 = 1.0 / 2048.0; \n" +
  847. "const float SHIFT_RIGHT_5 = 1.0 / 32.0; \n" +
  848. "const float SHIFT_LEFT_11 = 2048.0; \n" +
  849. "const float SHIFT_LEFT_5 = 32.0; \n" +
  850. "const float NORMALIZE_6 = 1.0 / 64.0; \n" +
  851. "const float NORMALIZE_5 = 1.0 / 32.0; \n";
  852. } else {
  853. vs += "in vec3 a_color; \n";
  854. }
  855. }
  856. if (usesNormals) {
  857. if (isOctEncoded16P || isOctEncodedDraco) {
  858. vs += "in vec2 a_normal; \n";
  859. } else {
  860. vs += "in vec3 a_normal; \n";
  861. }
  862. }
  863. if (hasBatchIds) {
  864. vs += "in float a_batchId; \n";
  865. }
  866. if (isQuantized || isQuantizedDraco || isOctEncodedDraco) {
  867. vs += "uniform vec4 u_quantizedVolumeScaleAndOctEncodedRange; \n";
  868. }
  869. if (hasColorStyle) {
  870. vs += colorStyleFunction;
  871. }
  872. if (hasShowStyle) {
  873. vs += showStyleFunction;
  874. }
  875. if (hasPointSizeStyle) {
  876. vs += pointSizeStyleFunction;
  877. }
  878. vs +=
  879. "void main() \n" +
  880. "{ \n" +
  881. " u_pointSize = u_pointSizeAndTimeAndGeometricErrorAndDepthMultiplier.x; \n" +
  882. " tiles3d_tileset_time = u_pointSizeAndTimeAndGeometricErrorAndDepthMultiplier.y; \n";
  883. if (attenuation) {
  884. vs +=
  885. " u_geometricError = u_pointSizeAndTimeAndGeometricErrorAndDepthMultiplier.z; \n" +
  886. " u_depthMultiplier = u_pointSizeAndTimeAndGeometricErrorAndDepthMultiplier.w; \n";
  887. }
  888. if (usesColors) {
  889. if (isTranslucent) {
  890. vs += " vec4 color = a_color; \n";
  891. } else if (isRGB565) {
  892. vs +=
  893. " float compressed = a_color; \n" +
  894. " float r = floor(compressed * SHIFT_RIGHT_11); \n" +
  895. " compressed -= r * SHIFT_LEFT_11; \n" +
  896. " float g = floor(compressed * SHIFT_RIGHT_5); \n" +
  897. " compressed -= g * SHIFT_LEFT_5; \n" +
  898. " float b = compressed; \n" +
  899. " vec3 rgb = vec3(r * NORMALIZE_5, g * NORMALIZE_6, b * NORMALIZE_5); \n" +
  900. " vec4 color = vec4(rgb, 1.0); \n";
  901. } else {
  902. vs += " vec4 color = vec4(a_color, 1.0); \n";
  903. }
  904. } else {
  905. vs += " vec4 color = u_constantColor; \n";
  906. }
  907. if (isQuantized || isQuantizedDraco) {
  908. vs +=
  909. " vec3 position = a_position * u_quantizedVolumeScaleAndOctEncodedRange.xyz; \n";
  910. } else {
  911. vs += " vec3 position = a_position; \n";
  912. }
  913. vs +=
  914. " vec3 position_absolute = vec3(czm_model * vec4(position, 1.0)); \n";
  915. if (usesNormals) {
  916. if (isOctEncoded16P) {
  917. vs += " vec3 normal = czm_octDecode(a_normal); \n";
  918. } else if (isOctEncodedDraco) {
  919. // Draco oct-encoding decodes to zxy order
  920. vs +=
  921. " vec3 normal = czm_octDecode(a_normal, u_quantizedVolumeScaleAndOctEncodedRange.w).zxy; \n";
  922. } else {
  923. vs += " vec3 normal = a_normal; \n";
  924. }
  925. vs += " vec3 normalEC = czm_normal * normal; \n";
  926. } else {
  927. vs += " vec3 normal = vec3(1.0); \n";
  928. }
  929. if (hasColorStyle) {
  930. vs +=
  931. " color = getColorFromStyle(position, position_absolute, color, normal); \n";
  932. }
  933. if (hasShowStyle) {
  934. vs +=
  935. " float show = float(getShowFromStyle(position, position_absolute, color, normal)); \n";
  936. }
  937. if (hasPointSizeStyle) {
  938. vs +=
  939. " gl_PointSize = getPointSizeFromStyle(position, position_absolute, color, normal) * czm_pixelRatio; \n";
  940. } else if (attenuation) {
  941. vs +=
  942. " vec4 positionEC = czm_modelView * vec4(position, 1.0); \n" +
  943. " float depth = -positionEC.z; \n" +
  944. // compute SSE for this point
  945. " gl_PointSize = min((u_geometricError / depth) * u_depthMultiplier, u_pointSize); \n";
  946. } else {
  947. vs += " gl_PointSize = u_pointSize; \n";
  948. }
  949. vs += " color = color * u_highlightColor; \n";
  950. if (usesNormals && normalShading) {
  951. vs +=
  952. " float diffuseStrength = czm_getLambertDiffuse(czm_lightDirectionEC, normalEC); \n" +
  953. " diffuseStrength = max(diffuseStrength, 0.4); \n" + // Apply some ambient lighting
  954. " color.xyz *= diffuseStrength * czm_lightColor; \n";
  955. }
  956. vs +=
  957. " v_color = color; \n" +
  958. " gl_Position = czm_modelViewProjection * vec4(position, 1.0); \n";
  959. if (usesNormals && backFaceCulling) {
  960. vs +=
  961. " float visible = step(-normalEC.z, 0.0); \n" +
  962. " gl_Position *= visible; \n" +
  963. " gl_PointSize *= visible; \n";
  964. }
  965. if (hasShowStyle) {
  966. vs +=
  967. " gl_Position.w *= float(show); \n" +
  968. " gl_PointSize *= float(show); \n";
  969. }
  970. vs += "} \n";
  971. let fs = "in vec4 v_color; \n";
  972. if (hasClippedContent) {
  973. fs +=
  974. "uniform highp sampler2D u_clippingPlanes; \n" +
  975. "uniform mat4 u_clippingPlanesMatrix; \n" +
  976. "uniform vec4 u_clippingPlanesEdgeStyle; \n";
  977. fs += "\n";
  978. fs += getClippingFunction(clippingPlanes, context);
  979. fs += "\n";
  980. }
  981. fs +=
  982. "void main() \n" +
  983. "{ \n" +
  984. " out_FragColor = czm_gammaCorrect(v_color); \n";
  985. if (hasClippedContent) {
  986. fs += getClipAndStyleCode(
  987. "u_clippingPlanes",
  988. "u_clippingPlanesMatrix",
  989. "u_clippingPlanesEdgeStyle",
  990. );
  991. }
  992. fs += "} \n";
  993. if (pointCloud.splitDirection !== SplitDirection.NONE) {
  994. fs = Splitter.modifyFragmentShader(fs);
  995. }
  996. if (defined(pointCloud._vertexShaderLoaded)) {
  997. vs = pointCloud._vertexShaderLoaded(vs);
  998. }
  999. if (defined(pointCloud._fragmentShaderLoaded)) {
  1000. fs = pointCloud._fragmentShaderLoaded(fs);
  1001. }
  1002. const drawCommand = pointCloud._drawCommand;
  1003. if (defined(drawCommand.shaderProgram)) {
  1004. // Destroy the old shader
  1005. drawCommand.shaderProgram.destroy();
  1006. }
  1007. drawCommand.shaderProgram = ShaderProgram.fromCache({
  1008. context: context,
  1009. vertexShaderSource: vs,
  1010. fragmentShaderSource: fs,
  1011. attributeLocations: attributeLocations,
  1012. });
  1013. try {
  1014. // Check if the shader compiles correctly. If not there is likely a syntax error with the style.
  1015. drawCommand.shaderProgram._bind();
  1016. } catch (error) {
  1017. // Rephrase the error.
  1018. throw new RuntimeError(
  1019. "Error generating style shader: this may be caused by a type mismatch, index out-of-bounds, or other syntax error.",
  1020. );
  1021. }
  1022. }
  1023. function decodeDraco(pointCloud, context) {
  1024. if (pointCloud._decodingState === DecodingState.READY) {
  1025. return false;
  1026. }
  1027. if (pointCloud._decodingState === DecodingState.NEEDS_DECODE) {
  1028. const parsedContent = pointCloud._parsedContent;
  1029. const draco = parsedContent.draco;
  1030. const decodePromise = DracoLoader.decodePointCloud(draco, context);
  1031. if (defined(decodePromise)) {
  1032. pointCloud._decodingState = DecodingState.DECODING;
  1033. decodePromise
  1034. .then(function (result) {
  1035. pointCloud._decodingState = DecodingState.READY;
  1036. const decodedPositions = defined(result.POSITION)
  1037. ? result.POSITION.array
  1038. : undefined;
  1039. const decodedRgb = defined(result.RGB) ? result.RGB.array : undefined;
  1040. const decodedRgba = defined(result.RGBA)
  1041. ? result.RGBA.array
  1042. : undefined;
  1043. const decodedNormals = defined(result.NORMAL)
  1044. ? result.NORMAL.array
  1045. : undefined;
  1046. const decodedBatchIds = defined(result.BATCH_ID)
  1047. ? result.BATCH_ID.array
  1048. : undefined;
  1049. const isQuantizedDraco =
  1050. defined(decodedPositions) &&
  1051. defined(result.POSITION.data.quantization);
  1052. const isOctEncodedDraco =
  1053. defined(decodedNormals) && defined(result.NORMAL.data.quantization);
  1054. if (isQuantizedDraco) {
  1055. // Draco quantization range == quantized volume scale - size in meters of the quantized volume
  1056. // Internal quantized range is the range of values of the quantized data, e.g. 255 for 8-bit, 1023 for 10-bit, etc
  1057. const quantization = result.POSITION.data.quantization;
  1058. const range = quantization.range;
  1059. pointCloud._quantizedVolumeScale = Cartesian3.fromElements(
  1060. range,
  1061. range,
  1062. range,
  1063. );
  1064. pointCloud._quantizedVolumeOffset = Cartesian3.unpack(
  1065. quantization.minValues,
  1066. );
  1067. pointCloud._quantizedRange =
  1068. (1 << quantization.quantizationBits) - 1.0;
  1069. pointCloud._isQuantizedDraco = true;
  1070. }
  1071. if (isOctEncodedDraco) {
  1072. pointCloud._octEncodedRange =
  1073. (1 << result.NORMAL.data.quantization.quantizationBits) - 1.0;
  1074. pointCloud._isOctEncodedDraco = true;
  1075. }
  1076. let styleableProperties = parsedContent.styleableProperties;
  1077. const batchTableProperties = draco.batchTableProperties;
  1078. for (const name in batchTableProperties) {
  1079. if (batchTableProperties.hasOwnProperty(name)) {
  1080. const property = result[name];
  1081. if (!defined(styleableProperties)) {
  1082. styleableProperties = {};
  1083. }
  1084. styleableProperties[name] = {
  1085. typedArray: property.array,
  1086. componentCount: property.data.componentsPerAttribute,
  1087. };
  1088. }
  1089. }
  1090. if (defined(decodedPositions)) {
  1091. parsedContent.positions = {
  1092. typedArray: decodedPositions,
  1093. };
  1094. }
  1095. const decodedColors = decodedRgba ?? decodedRgb;
  1096. if (defined(decodedColors)) {
  1097. parsedContent.colors = {
  1098. typedArray: decodedColors,
  1099. };
  1100. }
  1101. if (defined(decodedNormals)) {
  1102. parsedContent.normals = {
  1103. typedArray: decodedNormals,
  1104. };
  1105. }
  1106. if (defined(decodedBatchIds)) {
  1107. parsedContent.batchIds = {
  1108. typedArray: decodedBatchIds,
  1109. };
  1110. }
  1111. parsedContent.styleableProperties = styleableProperties;
  1112. })
  1113. .catch(function (error) {
  1114. pointCloud._decodingState = DecodingState.FAILED;
  1115. pointCloud._error = error;
  1116. });
  1117. }
  1118. }
  1119. return true;
  1120. }
  1121. const scratchComputedTranslation = new Cartesian4();
  1122. const scratchScale = new Cartesian3();
  1123. PointCloud.prototype.update = function (frameState) {
  1124. const context = frameState.context;
  1125. if (defined(this._error)) {
  1126. const error = this._error;
  1127. this._error = undefined;
  1128. throw error;
  1129. }
  1130. const decoding = decodeDraco(this, context);
  1131. if (decoding) {
  1132. return;
  1133. }
  1134. let shadersDirty = false;
  1135. let modelMatrixDirty = !Matrix4.equals(this._modelMatrix, this.modelMatrix);
  1136. if (this._mode !== frameState.mode) {
  1137. this._mode = frameState.mode;
  1138. modelMatrixDirty = true;
  1139. }
  1140. if (!defined(this._drawCommand)) {
  1141. createResources(this, frameState);
  1142. modelMatrixDirty = true;
  1143. shadersDirty = true;
  1144. this._ready = true;
  1145. this._parsedContent = undefined; // Unload
  1146. }
  1147. if (modelMatrixDirty) {
  1148. Matrix4.clone(this.modelMatrix, this._modelMatrix);
  1149. const modelMatrix = this._drawCommand.modelMatrix;
  1150. Matrix4.clone(this._modelMatrix, modelMatrix);
  1151. if (defined(this._rtcCenter)) {
  1152. Matrix4.multiplyByTranslation(modelMatrix, this._rtcCenter, modelMatrix);
  1153. }
  1154. if (defined(this._quantizedVolumeOffset)) {
  1155. Matrix4.multiplyByTranslation(
  1156. modelMatrix,
  1157. this._quantizedVolumeOffset,
  1158. modelMatrix,
  1159. );
  1160. }
  1161. if (frameState.mode !== SceneMode.SCENE3D) {
  1162. const projection = frameState.mapProjection;
  1163. const translation = Matrix4.getColumn(
  1164. modelMatrix,
  1165. 3,
  1166. scratchComputedTranslation,
  1167. );
  1168. if (!Cartesian4.equals(translation, Cartesian4.UNIT_W)) {
  1169. Transforms.basisTo2D(projection, modelMatrix, modelMatrix);
  1170. }
  1171. }
  1172. const boundingSphere = this._drawCommand.boundingVolume;
  1173. BoundingSphere.clone(this._boundingSphere, boundingSphere);
  1174. if (this._cull) {
  1175. const center = boundingSphere.center;
  1176. Matrix4.multiplyByPoint(modelMatrix, center, center);
  1177. const scale = Matrix4.getScale(modelMatrix, scratchScale);
  1178. boundingSphere.radius *= Cartesian3.maximumComponent(scale);
  1179. }
  1180. }
  1181. if (this.clippingPlanesDirty) {
  1182. this.clippingPlanesDirty = false;
  1183. shadersDirty = true;
  1184. }
  1185. if (this._attenuation !== this.attenuation) {
  1186. this._attenuation = this.attenuation;
  1187. shadersDirty = true;
  1188. }
  1189. if (this.backFaceCulling !== this._backFaceCulling) {
  1190. this._backFaceCulling = this.backFaceCulling;
  1191. shadersDirty = true;
  1192. }
  1193. if (this.normalShading !== this._normalShading) {
  1194. this._normalShading = this.normalShading;
  1195. shadersDirty = true;
  1196. }
  1197. if (this._style !== this.style || this.styleDirty) {
  1198. this._style = this.style;
  1199. this.styleDirty = false;
  1200. shadersDirty = true;
  1201. }
  1202. const splittingEnabled = this.splitDirection !== SplitDirection.NONE;
  1203. if (this._splittingEnabled !== splittingEnabled) {
  1204. this._splittingEnabled = splittingEnabled;
  1205. shadersDirty = true;
  1206. }
  1207. if (shadersDirty) {
  1208. createShaders(this, frameState, this._style);
  1209. }
  1210. this._drawCommand.castShadows = ShadowMode.castShadows(this.shadows);
  1211. this._drawCommand.receiveShadows = ShadowMode.receiveShadows(this.shadows);
  1212. // Update the render state
  1213. const isTranslucent =
  1214. this._highlightColor.alpha < 1.0 ||
  1215. this._constantColor.alpha < 1.0 ||
  1216. this._styleTranslucent;
  1217. this._drawCommand.renderState = isTranslucent
  1218. ? this._translucentRenderState
  1219. : this._opaqueRenderState;
  1220. this._drawCommand.pass = isTranslucent ? Pass.TRANSLUCENT : this._opaquePass;
  1221. const commandList = frameState.commandList;
  1222. const passes = frameState.passes;
  1223. if (passes.render || passes.pick) {
  1224. commandList.push(this._drawCommand);
  1225. }
  1226. };
  1227. PointCloud.prototype.isDestroyed = function () {
  1228. return false;
  1229. };
  1230. PointCloud.prototype.destroy = function () {
  1231. const command = this._drawCommand;
  1232. if (defined(command)) {
  1233. command.vertexArray = command.vertexArray && command.vertexArray.destroy();
  1234. command.shaderProgram =
  1235. command.shaderProgram && command.shaderProgram.destroy();
  1236. }
  1237. return destroyObject(this);
  1238. };
  1239. export default PointCloud;