createVectorTileGeometries.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. import BoundingSphere from "../Core/BoundingSphere.js";
  2. import BoxGeometry from "../Core/BoxGeometry.js";
  3. import Cartesian3 from "../Core/Cartesian3.js";
  4. import Color from "../Core/Color.js";
  5. import CylinderGeometry from "../Core/CylinderGeometry.js";
  6. import defined from "../Core/defined.js";
  7. import EllipsoidGeometry from "../Core/EllipsoidGeometry.js";
  8. import IndexDatatype from "../Core/IndexDatatype.js";
  9. import Matrix4 from "../Core/Matrix4.js";
  10. import Vector3DTileBatch from "../Scene/Vector3DTileBatch.js";
  11. import createTaskProcessorWorker from "./createTaskProcessorWorker.js";
  12. const scratchCartesian = new Cartesian3();
  13. const packedBoxLength = Matrix4.packedLength + Cartesian3.packedLength;
  14. const packedCylinderLength = Matrix4.packedLength + 2;
  15. const packedEllipsoidLength = Matrix4.packedLength + Cartesian3.packedLength;
  16. const packedSphereLength = Cartesian3.packedLength + 1;
  17. const scratchModelMatrixAndBV = {
  18. modelMatrix: new Matrix4(),
  19. boundingVolume: new BoundingSphere(),
  20. };
  21. function boxModelMatrixAndBoundingVolume(boxes, index) {
  22. let boxIndex = index * packedBoxLength;
  23. const dimensions = Cartesian3.unpack(boxes, boxIndex, scratchCartesian);
  24. boxIndex += Cartesian3.packedLength;
  25. const boxModelMatrix = Matrix4.unpack(
  26. boxes,
  27. boxIndex,
  28. scratchModelMatrixAndBV.modelMatrix
  29. );
  30. Matrix4.multiplyByScale(boxModelMatrix, dimensions, boxModelMatrix);
  31. const boundingVolume = scratchModelMatrixAndBV.boundingVolume;
  32. Cartesian3.clone(Cartesian3.ZERO, boundingVolume.center);
  33. boundingVolume.radius = Math.sqrt(3.0);
  34. return scratchModelMatrixAndBV;
  35. }
  36. function cylinderModelMatrixAndBoundingVolume(cylinders, index) {
  37. let cylinderIndex = index * packedCylinderLength;
  38. const cylinderRadius = cylinders[cylinderIndex++];
  39. const length = cylinders[cylinderIndex++];
  40. const scale = Cartesian3.fromElements(
  41. cylinderRadius,
  42. cylinderRadius,
  43. length,
  44. scratchCartesian
  45. );
  46. const cylinderModelMatrix = Matrix4.unpack(
  47. cylinders,
  48. cylinderIndex,
  49. scratchModelMatrixAndBV.modelMatrix
  50. );
  51. Matrix4.multiplyByScale(cylinderModelMatrix, scale, cylinderModelMatrix);
  52. const boundingVolume = scratchModelMatrixAndBV.boundingVolume;
  53. Cartesian3.clone(Cartesian3.ZERO, boundingVolume.center);
  54. boundingVolume.radius = Math.sqrt(2.0);
  55. return scratchModelMatrixAndBV;
  56. }
  57. function ellipsoidModelMatrixAndBoundingVolume(ellipsoids, index) {
  58. let ellipsoidIndex = index * packedEllipsoidLength;
  59. const radii = Cartesian3.unpack(ellipsoids, ellipsoidIndex, scratchCartesian);
  60. ellipsoidIndex += Cartesian3.packedLength;
  61. const ellipsoidModelMatrix = Matrix4.unpack(
  62. ellipsoids,
  63. ellipsoidIndex,
  64. scratchModelMatrixAndBV.modelMatrix
  65. );
  66. Matrix4.multiplyByScale(ellipsoidModelMatrix, radii, ellipsoidModelMatrix);
  67. const boundingVolume = scratchModelMatrixAndBV.boundingVolume;
  68. Cartesian3.clone(Cartesian3.ZERO, boundingVolume.center);
  69. boundingVolume.radius = 1.0;
  70. return scratchModelMatrixAndBV;
  71. }
  72. function sphereModelMatrixAndBoundingVolume(spheres, index) {
  73. let sphereIndex = index * packedSphereLength;
  74. const sphereRadius = spheres[sphereIndex++];
  75. const sphereTranslation = Cartesian3.unpack(
  76. spheres,
  77. sphereIndex,
  78. scratchCartesian
  79. );
  80. const sphereModelMatrix = Matrix4.fromTranslation(
  81. sphereTranslation,
  82. scratchModelMatrixAndBV.modelMatrix
  83. );
  84. Matrix4.multiplyByUniformScale(
  85. sphereModelMatrix,
  86. sphereRadius,
  87. sphereModelMatrix
  88. );
  89. const boundingVolume = scratchModelMatrixAndBV.boundingVolume;
  90. Cartesian3.clone(Cartesian3.ZERO, boundingVolume.center);
  91. boundingVolume.radius = 1.0;
  92. return scratchModelMatrixAndBV;
  93. }
  94. const scratchPosition = new Cartesian3();
  95. function createPrimitive(
  96. options,
  97. primitive,
  98. primitiveBatchIds,
  99. geometry,
  100. getModelMatrixAndBoundingVolume
  101. ) {
  102. if (!defined(primitive)) {
  103. return;
  104. }
  105. const numberOfPrimitives = primitiveBatchIds.length;
  106. const geometryPositions = geometry.attributes.position.values;
  107. const geometryIndices = geometry.indices;
  108. const positions = options.positions;
  109. const vertexBatchIds = options.vertexBatchIds;
  110. const indices = options.indices;
  111. const batchIds = options.batchIds;
  112. const batchTableColors = options.batchTableColors;
  113. const batchedIndices = options.batchedIndices;
  114. const indexOffsets = options.indexOffsets;
  115. const indexCounts = options.indexCounts;
  116. const boundingVolumes = options.boundingVolumes;
  117. const modelMatrix = options.modelMatrix;
  118. const center = options.center;
  119. let positionOffset = options.positionOffset;
  120. let batchIdIndex = options.batchIdIndex;
  121. let indexOffset = options.indexOffset;
  122. const batchedIndicesOffset = options.batchedIndicesOffset;
  123. for (let i = 0; i < numberOfPrimitives; ++i) {
  124. const primitiveModelMatrixAndBV = getModelMatrixAndBoundingVolume(
  125. primitive,
  126. i
  127. );
  128. const primitiveModelMatrix = primitiveModelMatrixAndBV.modelMatrix;
  129. Matrix4.multiply(modelMatrix, primitiveModelMatrix, primitiveModelMatrix);
  130. const batchId = primitiveBatchIds[i];
  131. const positionsLength = geometryPositions.length;
  132. for (let j = 0; j < positionsLength; j += 3) {
  133. const position = Cartesian3.unpack(geometryPositions, j, scratchPosition);
  134. Matrix4.multiplyByPoint(primitiveModelMatrix, position, position);
  135. Cartesian3.subtract(position, center, position);
  136. Cartesian3.pack(position, positions, positionOffset * 3 + j);
  137. vertexBatchIds[batchIdIndex++] = batchId;
  138. }
  139. const indicesLength = geometryIndices.length;
  140. for (let k = 0; k < indicesLength; ++k) {
  141. indices[indexOffset + k] = geometryIndices[k] + positionOffset;
  142. }
  143. const offset = i + batchedIndicesOffset;
  144. batchedIndices[offset] = new Vector3DTileBatch({
  145. offset: indexOffset,
  146. count: indicesLength,
  147. color: Color.fromRgba(batchTableColors[batchId]),
  148. batchIds: [batchId],
  149. });
  150. batchIds[offset] = batchId;
  151. indexOffsets[offset] = indexOffset;
  152. indexCounts[offset] = indicesLength;
  153. boundingVolumes[offset] = BoundingSphere.transform(
  154. primitiveModelMatrixAndBV.boundingVolume,
  155. primitiveModelMatrix
  156. );
  157. positionOffset += positionsLength / 3;
  158. indexOffset += indicesLength;
  159. }
  160. options.positionOffset = positionOffset;
  161. options.batchIdIndex = batchIdIndex;
  162. options.indexOffset = indexOffset;
  163. options.batchedIndicesOffset += numberOfPrimitives;
  164. }
  165. const scratchCenter = new Cartesian3();
  166. const scratchMatrix4 = new Matrix4();
  167. function unpackBuffer(buffer) {
  168. const packedBuffer = new Float64Array(buffer);
  169. let offset = 0;
  170. Cartesian3.unpack(packedBuffer, offset, scratchCenter);
  171. offset += Cartesian3.packedLength;
  172. Matrix4.unpack(packedBuffer, offset, scratchMatrix4);
  173. }
  174. function packedBatchedIndicesLength(batchedIndices) {
  175. const length = batchedIndices.length;
  176. let count = 0;
  177. for (let i = 0; i < length; ++i) {
  178. count += Color.packedLength + 3 + batchedIndices[i].batchIds.length;
  179. }
  180. return count;
  181. }
  182. function packBuffer(indicesBytesPerElement, batchedIndices, boundingVolumes) {
  183. const numBVs = boundingVolumes.length;
  184. const length =
  185. 1 +
  186. 1 +
  187. numBVs * BoundingSphere.packedLength +
  188. 1 +
  189. packedBatchedIndicesLength(batchedIndices);
  190. const packedBuffer = new Float64Array(length);
  191. let offset = 0;
  192. packedBuffer[offset++] = indicesBytesPerElement;
  193. packedBuffer[offset++] = numBVs;
  194. for (let i = 0; i < numBVs; ++i) {
  195. BoundingSphere.pack(boundingVolumes[i], packedBuffer, offset);
  196. offset += BoundingSphere.packedLength;
  197. }
  198. const indicesLength = batchedIndices.length;
  199. packedBuffer[offset++] = indicesLength;
  200. for (let j = 0; j < indicesLength; ++j) {
  201. const batchedIndex = batchedIndices[j];
  202. Color.pack(batchedIndex.color, packedBuffer, offset);
  203. offset += Color.packedLength;
  204. packedBuffer[offset++] = batchedIndex.offset;
  205. packedBuffer[offset++] = batchedIndex.count;
  206. const batchIds = batchedIndex.batchIds;
  207. const batchIdsLength = batchIds.length;
  208. packedBuffer[offset++] = batchIdsLength;
  209. for (let k = 0; k < batchIdsLength; ++k) {
  210. packedBuffer[offset++] = batchIds[k];
  211. }
  212. }
  213. return packedBuffer;
  214. }
  215. function createVectorTileGeometries(parameters, transferableObjects) {
  216. const boxes = defined(parameters.boxes)
  217. ? new Float32Array(parameters.boxes)
  218. : undefined;
  219. const boxBatchIds = defined(parameters.boxBatchIds)
  220. ? new Uint16Array(parameters.boxBatchIds)
  221. : undefined;
  222. const cylinders = defined(parameters.cylinders)
  223. ? new Float32Array(parameters.cylinders)
  224. : undefined;
  225. const cylinderBatchIds = defined(parameters.cylinderBatchIds)
  226. ? new Uint16Array(parameters.cylinderBatchIds)
  227. : undefined;
  228. const ellipsoids = defined(parameters.ellipsoids)
  229. ? new Float32Array(parameters.ellipsoids)
  230. : undefined;
  231. const ellipsoidBatchIds = defined(parameters.ellipsoidBatchIds)
  232. ? new Uint16Array(parameters.ellipsoidBatchIds)
  233. : undefined;
  234. const spheres = defined(parameters.spheres)
  235. ? new Float32Array(parameters.spheres)
  236. : undefined;
  237. const sphereBatchIds = defined(parameters.sphereBatchIds)
  238. ? new Uint16Array(parameters.sphereBatchIds)
  239. : undefined;
  240. const numberOfBoxes = defined(boxes) ? boxBatchIds.length : 0;
  241. const numberOfCylinders = defined(cylinders) ? cylinderBatchIds.length : 0;
  242. const numberOfEllipsoids = defined(ellipsoids) ? ellipsoidBatchIds.length : 0;
  243. const numberOfSpheres = defined(spheres) ? sphereBatchIds.length : 0;
  244. const boxGeometry = BoxGeometry.getUnitBox();
  245. const cylinderGeometry = CylinderGeometry.getUnitCylinder();
  246. const ellipsoidGeometry = EllipsoidGeometry.getUnitEllipsoid();
  247. const boxPositions = boxGeometry.attributes.position.values;
  248. const cylinderPositions = cylinderGeometry.attributes.position.values;
  249. const ellipsoidPositions = ellipsoidGeometry.attributes.position.values;
  250. let numberOfPositions = boxPositions.length * numberOfBoxes;
  251. numberOfPositions += cylinderPositions.length * numberOfCylinders;
  252. numberOfPositions +=
  253. ellipsoidPositions.length * (numberOfEllipsoids + numberOfSpheres);
  254. const boxIndices = boxGeometry.indices;
  255. const cylinderIndices = cylinderGeometry.indices;
  256. const ellipsoidIndices = ellipsoidGeometry.indices;
  257. let numberOfIndices = boxIndices.length * numberOfBoxes;
  258. numberOfIndices += cylinderIndices.length * numberOfCylinders;
  259. numberOfIndices +=
  260. ellipsoidIndices.length * (numberOfEllipsoids + numberOfSpheres);
  261. const positions = new Float32Array(numberOfPositions);
  262. const vertexBatchIds = new Uint16Array(numberOfPositions / 3);
  263. const indices = IndexDatatype.createTypedArray(
  264. numberOfPositions / 3,
  265. numberOfIndices
  266. );
  267. const numberOfGeometries =
  268. numberOfBoxes + numberOfCylinders + numberOfEllipsoids + numberOfSpheres;
  269. const batchIds = new Uint16Array(numberOfGeometries);
  270. const batchedIndices = new Array(numberOfGeometries);
  271. const indexOffsets = new Uint32Array(numberOfGeometries);
  272. const indexCounts = new Uint32Array(numberOfGeometries);
  273. const boundingVolumes = new Array(numberOfGeometries);
  274. unpackBuffer(parameters.packedBuffer);
  275. const options = {
  276. batchTableColors: new Uint32Array(parameters.batchTableColors),
  277. positions: positions,
  278. vertexBatchIds: vertexBatchIds,
  279. indices: indices,
  280. batchIds: batchIds,
  281. batchedIndices: batchedIndices,
  282. indexOffsets: indexOffsets,
  283. indexCounts: indexCounts,
  284. boundingVolumes: boundingVolumes,
  285. positionOffset: 0,
  286. batchIdIndex: 0,
  287. indexOffset: 0,
  288. batchedIndicesOffset: 0,
  289. modelMatrix: scratchMatrix4,
  290. center: scratchCenter,
  291. };
  292. createPrimitive(
  293. options,
  294. boxes,
  295. boxBatchIds,
  296. boxGeometry,
  297. boxModelMatrixAndBoundingVolume
  298. );
  299. createPrimitive(
  300. options,
  301. cylinders,
  302. cylinderBatchIds,
  303. cylinderGeometry,
  304. cylinderModelMatrixAndBoundingVolume
  305. );
  306. createPrimitive(
  307. options,
  308. ellipsoids,
  309. ellipsoidBatchIds,
  310. ellipsoidGeometry,
  311. ellipsoidModelMatrixAndBoundingVolume
  312. );
  313. createPrimitive(
  314. options,
  315. spheres,
  316. sphereBatchIds,
  317. ellipsoidGeometry,
  318. sphereModelMatrixAndBoundingVolume
  319. );
  320. const packedBuffer = packBuffer(
  321. indices.BYTES_PER_ELEMENT,
  322. batchedIndices,
  323. boundingVolumes
  324. );
  325. transferableObjects.push(
  326. positions.buffer,
  327. vertexBatchIds.buffer,
  328. indices.buffer
  329. );
  330. transferableObjects.push(
  331. batchIds.buffer,
  332. indexOffsets.buffer,
  333. indexCounts.buffer
  334. );
  335. transferableObjects.push(packedBuffer.buffer);
  336. return {
  337. positions: positions.buffer,
  338. vertexBatchIds: vertexBatchIds.buffer,
  339. indices: indices.buffer,
  340. indexOffsets: indexOffsets.buffer,
  341. indexCounts: indexCounts.buffer,
  342. batchIds: batchIds.buffer,
  343. packedBuffer: packedBuffer.buffer,
  344. };
  345. }
  346. export default createTaskProcessorWorker(createVectorTileGeometries);