upsampleQuantizedTerrainMesh.js 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023
  1. /* This file is automatically rebuilt by the Cesium build process. */
  2. define(['./AttributeCompression-3cfab808', './Transforms-323408fe', './Matrix2-69c32d33', './defaultValue-94c3e563', './TerrainEncoding-12c7d791', './IndexDatatype-c4099fe9', './RuntimeError-c581ca93', './ComponentDatatype-b1ea011a', './OrientedBoundingBox-a5e39a7d', './createTaskProcessorWorker', './_commonjsHelpers-3aae1032-f55dc0c4', './combine-761d9c3f', './WebGLConstants-7dccdc96', './EllipsoidTangentPlane-1e8d1fc2', './AxisAlignedBoundingBox-df2331b2', './IntersectionTests-d5d945ac', './Plane-069b6800'], (function (AttributeCompression, Transforms, Matrix2, defaultValue, TerrainEncoding, IndexDatatype, RuntimeError, ComponentDatatype, OrientedBoundingBox, createTaskProcessorWorker, _commonjsHelpers3aae1032, combine, WebGLConstants, EllipsoidTangentPlane, AxisAlignedBoundingBox, IntersectionTests, Plane) { 'use strict';
  3. /**
  4. * Contains functions for operating on 2D triangles.
  5. *
  6. * @namespace Intersections2D
  7. */
  8. const Intersections2D = {};
  9. /**
  10. * Splits a 2D triangle at given axis-aligned threshold value and returns the resulting
  11. * polygon on a given side of the threshold. The resulting polygon may have 0, 1, 2,
  12. * 3, or 4 vertices.
  13. *
  14. * @param {Number} threshold The threshold coordinate value at which to clip the triangle.
  15. * @param {Boolean} keepAbove true to keep the portion of the triangle above the threshold, or false
  16. * to keep the portion below.
  17. * @param {Number} u0 The coordinate of the first vertex in the triangle, in counter-clockwise order.
  18. * @param {Number} u1 The coordinate of the second vertex in the triangle, in counter-clockwise order.
  19. * @param {Number} u2 The coordinate of the third vertex in the triangle, in counter-clockwise order.
  20. * @param {Number[]} [result] The array into which to copy the result. If this parameter is not supplied,
  21. * a new array is constructed and returned.
  22. * @returns {Number[]} The polygon that results after the clip, specified as a list of
  23. * vertices. The vertices are specified in counter-clockwise order.
  24. * Each vertex is either an index from the existing list (identified as
  25. * a 0, 1, or 2) or -1 indicating a new vertex not in the original triangle.
  26. * For new vertices, the -1 is followed by three additional numbers: the
  27. * index of each of the two original vertices forming the line segment that
  28. * the new vertex lies on, and the fraction of the distance from the first
  29. * vertex to the second one.
  30. *
  31. * @example
  32. * const result = Cesium.Intersections2D.clipTriangleAtAxisAlignedThreshold(0.5, false, 0.2, 0.6, 0.4);
  33. * // result === [2, 0, -1, 1, 0, 0.25, -1, 1, 2, 0.5]
  34. */
  35. Intersections2D.clipTriangleAtAxisAlignedThreshold = function (
  36. threshold,
  37. keepAbove,
  38. u0,
  39. u1,
  40. u2,
  41. result
  42. ) {
  43. //>>includeStart('debug', pragmas.debug);
  44. if (!defaultValue.defined(threshold)) {
  45. throw new RuntimeError.DeveloperError("threshold is required.");
  46. }
  47. if (!defaultValue.defined(keepAbove)) {
  48. throw new RuntimeError.DeveloperError("keepAbove is required.");
  49. }
  50. if (!defaultValue.defined(u0)) {
  51. throw new RuntimeError.DeveloperError("u0 is required.");
  52. }
  53. if (!defaultValue.defined(u1)) {
  54. throw new RuntimeError.DeveloperError("u1 is required.");
  55. }
  56. if (!defaultValue.defined(u2)) {
  57. throw new RuntimeError.DeveloperError("u2 is required.");
  58. }
  59. //>>includeEnd('debug');
  60. if (!defaultValue.defined(result)) {
  61. result = [];
  62. } else {
  63. result.length = 0;
  64. }
  65. let u0Behind;
  66. let u1Behind;
  67. let u2Behind;
  68. if (keepAbove) {
  69. u0Behind = u0 < threshold;
  70. u1Behind = u1 < threshold;
  71. u2Behind = u2 < threshold;
  72. } else {
  73. u0Behind = u0 > threshold;
  74. u1Behind = u1 > threshold;
  75. u2Behind = u2 > threshold;
  76. }
  77. const numBehind = u0Behind + u1Behind + u2Behind;
  78. let u01Ratio;
  79. let u02Ratio;
  80. let u12Ratio;
  81. let u10Ratio;
  82. let u20Ratio;
  83. let u21Ratio;
  84. if (numBehind === 1) {
  85. if (u0Behind) {
  86. u01Ratio = (threshold - u0) / (u1 - u0);
  87. u02Ratio = (threshold - u0) / (u2 - u0);
  88. result.push(1);
  89. result.push(2);
  90. if (u02Ratio !== 1.0) {
  91. result.push(-1);
  92. result.push(0);
  93. result.push(2);
  94. result.push(u02Ratio);
  95. }
  96. if (u01Ratio !== 1.0) {
  97. result.push(-1);
  98. result.push(0);
  99. result.push(1);
  100. result.push(u01Ratio);
  101. }
  102. } else if (u1Behind) {
  103. u12Ratio = (threshold - u1) / (u2 - u1);
  104. u10Ratio = (threshold - u1) / (u0 - u1);
  105. result.push(2);
  106. result.push(0);
  107. if (u10Ratio !== 1.0) {
  108. result.push(-1);
  109. result.push(1);
  110. result.push(0);
  111. result.push(u10Ratio);
  112. }
  113. if (u12Ratio !== 1.0) {
  114. result.push(-1);
  115. result.push(1);
  116. result.push(2);
  117. result.push(u12Ratio);
  118. }
  119. } else if (u2Behind) {
  120. u20Ratio = (threshold - u2) / (u0 - u2);
  121. u21Ratio = (threshold - u2) / (u1 - u2);
  122. result.push(0);
  123. result.push(1);
  124. if (u21Ratio !== 1.0) {
  125. result.push(-1);
  126. result.push(2);
  127. result.push(1);
  128. result.push(u21Ratio);
  129. }
  130. if (u20Ratio !== 1.0) {
  131. result.push(-1);
  132. result.push(2);
  133. result.push(0);
  134. result.push(u20Ratio);
  135. }
  136. }
  137. } else if (numBehind === 2) {
  138. if (!u0Behind && u0 !== threshold) {
  139. u10Ratio = (threshold - u1) / (u0 - u1);
  140. u20Ratio = (threshold - u2) / (u0 - u2);
  141. result.push(0);
  142. result.push(-1);
  143. result.push(1);
  144. result.push(0);
  145. result.push(u10Ratio);
  146. result.push(-1);
  147. result.push(2);
  148. result.push(0);
  149. result.push(u20Ratio);
  150. } else if (!u1Behind && u1 !== threshold) {
  151. u21Ratio = (threshold - u2) / (u1 - u2);
  152. u01Ratio = (threshold - u0) / (u1 - u0);
  153. result.push(1);
  154. result.push(-1);
  155. result.push(2);
  156. result.push(1);
  157. result.push(u21Ratio);
  158. result.push(-1);
  159. result.push(0);
  160. result.push(1);
  161. result.push(u01Ratio);
  162. } else if (!u2Behind && u2 !== threshold) {
  163. u02Ratio = (threshold - u0) / (u2 - u0);
  164. u12Ratio = (threshold - u1) / (u2 - u1);
  165. result.push(2);
  166. result.push(-1);
  167. result.push(0);
  168. result.push(2);
  169. result.push(u02Ratio);
  170. result.push(-1);
  171. result.push(1);
  172. result.push(2);
  173. result.push(u12Ratio);
  174. }
  175. } else if (numBehind !== 3) {
  176. // Completely in front of threshold
  177. result.push(0);
  178. result.push(1);
  179. result.push(2);
  180. }
  181. // else Completely behind threshold
  182. return result;
  183. };
  184. /**
  185. * Compute the barycentric coordinates of a 2D position within a 2D triangle.
  186. *
  187. * @param {Number} x The x coordinate of the position for which to find the barycentric coordinates.
  188. * @param {Number} y The y coordinate of the position for which to find the barycentric coordinates.
  189. * @param {Number} x1 The x coordinate of the triangle's first vertex.
  190. * @param {Number} y1 The y coordinate of the triangle's first vertex.
  191. * @param {Number} x2 The x coordinate of the triangle's second vertex.
  192. * @param {Number} y2 The y coordinate of the triangle's second vertex.
  193. * @param {Number} x3 The x coordinate of the triangle's third vertex.
  194. * @param {Number} y3 The y coordinate of the triangle's third vertex.
  195. * @param {Cartesian3} [result] The instance into to which to copy the result. If this parameter
  196. * is undefined, a new instance is created and returned.
  197. * @returns {Cartesian3} The barycentric coordinates of the position within the triangle.
  198. *
  199. * @example
  200. * const result = Cesium.Intersections2D.computeBarycentricCoordinates(0.0, 0.0, 0.0, 1.0, -1, -0.5, 1, -0.5);
  201. * // result === new Cesium.Cartesian3(1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0);
  202. */
  203. Intersections2D.computeBarycentricCoordinates = function (
  204. x,
  205. y,
  206. x1,
  207. y1,
  208. x2,
  209. y2,
  210. x3,
  211. y3,
  212. result
  213. ) {
  214. //>>includeStart('debug', pragmas.debug);
  215. if (!defaultValue.defined(x)) {
  216. throw new RuntimeError.DeveloperError("x is required.");
  217. }
  218. if (!defaultValue.defined(y)) {
  219. throw new RuntimeError.DeveloperError("y is required.");
  220. }
  221. if (!defaultValue.defined(x1)) {
  222. throw new RuntimeError.DeveloperError("x1 is required.");
  223. }
  224. if (!defaultValue.defined(y1)) {
  225. throw new RuntimeError.DeveloperError("y1 is required.");
  226. }
  227. if (!defaultValue.defined(x2)) {
  228. throw new RuntimeError.DeveloperError("x2 is required.");
  229. }
  230. if (!defaultValue.defined(y2)) {
  231. throw new RuntimeError.DeveloperError("y2 is required.");
  232. }
  233. if (!defaultValue.defined(x3)) {
  234. throw new RuntimeError.DeveloperError("x3 is required.");
  235. }
  236. if (!defaultValue.defined(y3)) {
  237. throw new RuntimeError.DeveloperError("y3 is required.");
  238. }
  239. //>>includeEnd('debug');
  240. const x1mx3 = x1 - x3;
  241. const x3mx2 = x3 - x2;
  242. const y2my3 = y2 - y3;
  243. const y1my3 = y1 - y3;
  244. const inverseDeterminant = 1.0 / (y2my3 * x1mx3 + x3mx2 * y1my3);
  245. const ymy3 = y - y3;
  246. const xmx3 = x - x3;
  247. const l1 = (y2my3 * xmx3 + x3mx2 * ymy3) * inverseDeterminant;
  248. const l2 = (-y1my3 * xmx3 + x1mx3 * ymy3) * inverseDeterminant;
  249. const l3 = 1.0 - l1 - l2;
  250. if (defaultValue.defined(result)) {
  251. result.x = l1;
  252. result.y = l2;
  253. result.z = l3;
  254. return result;
  255. }
  256. return new Matrix2.Cartesian3(l1, l2, l3);
  257. };
  258. /**
  259. * Compute the intersection between 2 line segments
  260. *
  261. * @param {Number} x00 The x coordinate of the first line's first vertex.
  262. * @param {Number} y00 The y coordinate of the first line's first vertex.
  263. * @param {Number} x01 The x coordinate of the first line's second vertex.
  264. * @param {Number} y01 The y coordinate of the first line's second vertex.
  265. * @param {Number} x10 The x coordinate of the second line's first vertex.
  266. * @param {Number} y10 The y coordinate of the second line's first vertex.
  267. * @param {Number} x11 The x coordinate of the second line's second vertex.
  268. * @param {Number} y11 The y coordinate of the second line's second vertex.
  269. * @param {Cartesian2} [result] The instance into to which to copy the result. If this parameter
  270. * is undefined, a new instance is created and returned.
  271. * @returns {Cartesian2} The intersection point, undefined if there is no intersection point or lines are coincident.
  272. *
  273. * @example
  274. * const result = Cesium.Intersections2D.computeLineSegmentLineSegmentIntersection(0.0, 0.0, 0.0, 2.0, -1, 1, 1, 1);
  275. * // result === new Cesium.Cartesian2(0.0, 1.0);
  276. */
  277. Intersections2D.computeLineSegmentLineSegmentIntersection = function (
  278. x00,
  279. y00,
  280. x01,
  281. y01,
  282. x10,
  283. y10,
  284. x11,
  285. y11,
  286. result
  287. ) {
  288. //>>includeStart('debug', pragmas.debug);
  289. RuntimeError.Check.typeOf.number("x00", x00);
  290. RuntimeError.Check.typeOf.number("y00", y00);
  291. RuntimeError.Check.typeOf.number("x01", x01);
  292. RuntimeError.Check.typeOf.number("y01", y01);
  293. RuntimeError.Check.typeOf.number("x10", x10);
  294. RuntimeError.Check.typeOf.number("y10", y10);
  295. RuntimeError.Check.typeOf.number("x11", x11);
  296. RuntimeError.Check.typeOf.number("y11", y11);
  297. //>>includeEnd('debug');
  298. const numerator1A = (x11 - x10) * (y00 - y10) - (y11 - y10) * (x00 - x10);
  299. const numerator1B = (x01 - x00) * (y00 - y10) - (y01 - y00) * (x00 - x10);
  300. const denominator1 = (y11 - y10) * (x01 - x00) - (x11 - x10) * (y01 - y00);
  301. // If denominator = 0, then lines are parallel. If denominator = 0 and both numerators are 0, then coincident
  302. if (denominator1 === 0) {
  303. return;
  304. }
  305. const ua1 = numerator1A / denominator1;
  306. const ub1 = numerator1B / denominator1;
  307. if (ua1 >= 0 && ua1 <= 1 && ub1 >= 0 && ub1 <= 1) {
  308. if (!defaultValue.defined(result)) {
  309. result = new Matrix2.Cartesian2();
  310. }
  311. result.x = x00 + ua1 * (x01 - x00);
  312. result.y = y00 + ua1 * (y01 - y00);
  313. return result;
  314. }
  315. };
  316. const maxShort = 32767;
  317. const halfMaxShort = (maxShort / 2) | 0;
  318. const clipScratch = [];
  319. const clipScratch2 = [];
  320. const verticesScratch = [];
  321. const cartographicScratch = new Matrix2.Cartographic();
  322. let cartesian3Scratch = new Matrix2.Cartesian3();
  323. const uScratch = [];
  324. const vScratch = [];
  325. const heightScratch = [];
  326. const indicesScratch = [];
  327. const normalsScratch = [];
  328. const horizonOcclusionPointScratch = new Matrix2.Cartesian3();
  329. const boundingSphereScratch = new Transforms.BoundingSphere();
  330. const orientedBoundingBoxScratch = new OrientedBoundingBox.OrientedBoundingBox();
  331. const decodeTexCoordsScratch = new Matrix2.Cartesian2();
  332. const octEncodedNormalScratch = new Matrix2.Cartesian3();
  333. function upsampleQuantizedTerrainMesh(parameters, transferableObjects) {
  334. const isEastChild = parameters.isEastChild;
  335. const isNorthChild = parameters.isNorthChild;
  336. const minU = isEastChild ? halfMaxShort : 0;
  337. const maxU = isEastChild ? maxShort : halfMaxShort;
  338. const minV = isNorthChild ? halfMaxShort : 0;
  339. const maxV = isNorthChild ? maxShort : halfMaxShort;
  340. const uBuffer = uScratch;
  341. const vBuffer = vScratch;
  342. const heightBuffer = heightScratch;
  343. const normalBuffer = normalsScratch;
  344. uBuffer.length = 0;
  345. vBuffer.length = 0;
  346. heightBuffer.length = 0;
  347. normalBuffer.length = 0;
  348. const indices = indicesScratch;
  349. indices.length = 0;
  350. const vertexMap = {};
  351. const parentVertices = parameters.vertices;
  352. let parentIndices = parameters.indices;
  353. parentIndices = parentIndices.subarray(0, parameters.indexCountWithoutSkirts);
  354. const encoding = TerrainEncoding.TerrainEncoding.clone(parameters.encoding);
  355. const hasVertexNormals = encoding.hasVertexNormals;
  356. let vertexCount = 0;
  357. const quantizedVertexCount = parameters.vertexCountWithoutSkirts;
  358. const parentMinimumHeight = parameters.minimumHeight;
  359. const parentMaximumHeight = parameters.maximumHeight;
  360. const parentUBuffer = new Array(quantizedVertexCount);
  361. const parentVBuffer = new Array(quantizedVertexCount);
  362. const parentHeightBuffer = new Array(quantizedVertexCount);
  363. const parentNormalBuffer = hasVertexNormals
  364. ? new Array(quantizedVertexCount * 2)
  365. : undefined;
  366. const threshold = 20;
  367. let height;
  368. let i, n;
  369. let u, v;
  370. for (i = 0, n = 0; i < quantizedVertexCount; ++i, n += 2) {
  371. const texCoords = encoding.decodeTextureCoordinates(
  372. parentVertices,
  373. i,
  374. decodeTexCoordsScratch
  375. );
  376. height = encoding.decodeHeight(parentVertices, i);
  377. u = ComponentDatatype.CesiumMath.clamp((texCoords.x * maxShort) | 0, 0, maxShort);
  378. v = ComponentDatatype.CesiumMath.clamp((texCoords.y * maxShort) | 0, 0, maxShort);
  379. parentHeightBuffer[i] = ComponentDatatype.CesiumMath.clamp(
  380. (((height - parentMinimumHeight) /
  381. (parentMaximumHeight - parentMinimumHeight)) *
  382. maxShort) |
  383. 0,
  384. 0,
  385. maxShort
  386. );
  387. if (u < threshold) {
  388. u = 0;
  389. }
  390. if (v < threshold) {
  391. v = 0;
  392. }
  393. if (maxShort - u < threshold) {
  394. u = maxShort;
  395. }
  396. if (maxShort - v < threshold) {
  397. v = maxShort;
  398. }
  399. parentUBuffer[i] = u;
  400. parentVBuffer[i] = v;
  401. if (hasVertexNormals) {
  402. const encodedNormal = encoding.getOctEncodedNormal(
  403. parentVertices,
  404. i,
  405. octEncodedNormalScratch
  406. );
  407. parentNormalBuffer[n] = encodedNormal.x;
  408. parentNormalBuffer[n + 1] = encodedNormal.y;
  409. }
  410. if (
  411. ((isEastChild && u >= halfMaxShort) ||
  412. (!isEastChild && u <= halfMaxShort)) &&
  413. ((isNorthChild && v >= halfMaxShort) ||
  414. (!isNorthChild && v <= halfMaxShort))
  415. ) {
  416. vertexMap[i] = vertexCount;
  417. uBuffer.push(u);
  418. vBuffer.push(v);
  419. heightBuffer.push(parentHeightBuffer[i]);
  420. if (hasVertexNormals) {
  421. normalBuffer.push(parentNormalBuffer[n]);
  422. normalBuffer.push(parentNormalBuffer[n + 1]);
  423. }
  424. ++vertexCount;
  425. }
  426. }
  427. const triangleVertices = [];
  428. triangleVertices.push(new Vertex());
  429. triangleVertices.push(new Vertex());
  430. triangleVertices.push(new Vertex());
  431. const clippedTriangleVertices = [];
  432. clippedTriangleVertices.push(new Vertex());
  433. clippedTriangleVertices.push(new Vertex());
  434. clippedTriangleVertices.push(new Vertex());
  435. let clippedIndex;
  436. let clipped2;
  437. for (i = 0; i < parentIndices.length; i += 3) {
  438. const i0 = parentIndices[i];
  439. const i1 = parentIndices[i + 1];
  440. const i2 = parentIndices[i + 2];
  441. const u0 = parentUBuffer[i0];
  442. const u1 = parentUBuffer[i1];
  443. const u2 = parentUBuffer[i2];
  444. triangleVertices[0].initializeIndexed(
  445. parentUBuffer,
  446. parentVBuffer,
  447. parentHeightBuffer,
  448. parentNormalBuffer,
  449. i0
  450. );
  451. triangleVertices[1].initializeIndexed(
  452. parentUBuffer,
  453. parentVBuffer,
  454. parentHeightBuffer,
  455. parentNormalBuffer,
  456. i1
  457. );
  458. triangleVertices[2].initializeIndexed(
  459. parentUBuffer,
  460. parentVBuffer,
  461. parentHeightBuffer,
  462. parentNormalBuffer,
  463. i2
  464. );
  465. // Clip triangle on the east-west boundary.
  466. const clipped = Intersections2D.clipTriangleAtAxisAlignedThreshold(
  467. halfMaxShort,
  468. isEastChild,
  469. u0,
  470. u1,
  471. u2,
  472. clipScratch
  473. );
  474. // Get the first clipped triangle, if any.
  475. clippedIndex = 0;
  476. if (clippedIndex >= clipped.length) {
  477. continue;
  478. }
  479. clippedIndex = clippedTriangleVertices[0].initializeFromClipResult(
  480. clipped,
  481. clippedIndex,
  482. triangleVertices
  483. );
  484. if (clippedIndex >= clipped.length) {
  485. continue;
  486. }
  487. clippedIndex = clippedTriangleVertices[1].initializeFromClipResult(
  488. clipped,
  489. clippedIndex,
  490. triangleVertices
  491. );
  492. if (clippedIndex >= clipped.length) {
  493. continue;
  494. }
  495. clippedIndex = clippedTriangleVertices[2].initializeFromClipResult(
  496. clipped,
  497. clippedIndex,
  498. triangleVertices
  499. );
  500. // Clip the triangle against the North-south boundary.
  501. clipped2 = Intersections2D.clipTriangleAtAxisAlignedThreshold(
  502. halfMaxShort,
  503. isNorthChild,
  504. clippedTriangleVertices[0].getV(),
  505. clippedTriangleVertices[1].getV(),
  506. clippedTriangleVertices[2].getV(),
  507. clipScratch2
  508. );
  509. addClippedPolygon(
  510. uBuffer,
  511. vBuffer,
  512. heightBuffer,
  513. normalBuffer,
  514. indices,
  515. vertexMap,
  516. clipped2,
  517. clippedTriangleVertices,
  518. hasVertexNormals
  519. );
  520. // If there's another vertex in the original clipped result,
  521. // it forms a second triangle. Clip it as well.
  522. if (clippedIndex < clipped.length) {
  523. clippedTriangleVertices[2].clone(clippedTriangleVertices[1]);
  524. clippedTriangleVertices[2].initializeFromClipResult(
  525. clipped,
  526. clippedIndex,
  527. triangleVertices
  528. );
  529. clipped2 = Intersections2D.clipTriangleAtAxisAlignedThreshold(
  530. halfMaxShort,
  531. isNorthChild,
  532. clippedTriangleVertices[0].getV(),
  533. clippedTriangleVertices[1].getV(),
  534. clippedTriangleVertices[2].getV(),
  535. clipScratch2
  536. );
  537. addClippedPolygon(
  538. uBuffer,
  539. vBuffer,
  540. heightBuffer,
  541. normalBuffer,
  542. indices,
  543. vertexMap,
  544. clipped2,
  545. clippedTriangleVertices,
  546. hasVertexNormals
  547. );
  548. }
  549. }
  550. const uOffset = isEastChild ? -maxShort : 0;
  551. const vOffset = isNorthChild ? -maxShort : 0;
  552. const westIndices = [];
  553. const southIndices = [];
  554. const eastIndices = [];
  555. const northIndices = [];
  556. let minimumHeight = Number.MAX_VALUE;
  557. let maximumHeight = -minimumHeight;
  558. const cartesianVertices = verticesScratch;
  559. cartesianVertices.length = 0;
  560. const ellipsoid = Matrix2.Ellipsoid.clone(parameters.ellipsoid);
  561. const rectangle = Matrix2.Rectangle.clone(parameters.childRectangle);
  562. const north = rectangle.north;
  563. const south = rectangle.south;
  564. let east = rectangle.east;
  565. const west = rectangle.west;
  566. if (east < west) {
  567. east += ComponentDatatype.CesiumMath.TWO_PI;
  568. }
  569. for (i = 0; i < uBuffer.length; ++i) {
  570. u = Math.round(uBuffer[i]);
  571. if (u <= minU) {
  572. westIndices.push(i);
  573. u = 0;
  574. } else if (u >= maxU) {
  575. eastIndices.push(i);
  576. u = maxShort;
  577. } else {
  578. u = u * 2 + uOffset;
  579. }
  580. uBuffer[i] = u;
  581. v = Math.round(vBuffer[i]);
  582. if (v <= minV) {
  583. southIndices.push(i);
  584. v = 0;
  585. } else if (v >= maxV) {
  586. northIndices.push(i);
  587. v = maxShort;
  588. } else {
  589. v = v * 2 + vOffset;
  590. }
  591. vBuffer[i] = v;
  592. height = ComponentDatatype.CesiumMath.lerp(
  593. parentMinimumHeight,
  594. parentMaximumHeight,
  595. heightBuffer[i] / maxShort
  596. );
  597. if (height < minimumHeight) {
  598. minimumHeight = height;
  599. }
  600. if (height > maximumHeight) {
  601. maximumHeight = height;
  602. }
  603. heightBuffer[i] = height;
  604. cartographicScratch.longitude = ComponentDatatype.CesiumMath.lerp(west, east, u / maxShort);
  605. cartographicScratch.latitude = ComponentDatatype.CesiumMath.lerp(south, north, v / maxShort);
  606. cartographicScratch.height = height;
  607. ellipsoid.cartographicToCartesian(cartographicScratch, cartesian3Scratch);
  608. cartesianVertices.push(cartesian3Scratch.x);
  609. cartesianVertices.push(cartesian3Scratch.y);
  610. cartesianVertices.push(cartesian3Scratch.z);
  611. }
  612. const boundingSphere = Transforms.BoundingSphere.fromVertices(
  613. cartesianVertices,
  614. Matrix2.Cartesian3.ZERO,
  615. 3,
  616. boundingSphereScratch
  617. );
  618. const orientedBoundingBox = OrientedBoundingBox.OrientedBoundingBox.fromRectangle(
  619. rectangle,
  620. minimumHeight,
  621. maximumHeight,
  622. ellipsoid,
  623. orientedBoundingBoxScratch
  624. );
  625. const occluder = new TerrainEncoding.EllipsoidalOccluder(ellipsoid);
  626. const horizonOcclusionPoint = occluder.computeHorizonCullingPointFromVerticesPossiblyUnderEllipsoid(
  627. boundingSphere.center,
  628. cartesianVertices,
  629. 3,
  630. boundingSphere.center,
  631. minimumHeight,
  632. horizonOcclusionPointScratch
  633. );
  634. const heightRange = maximumHeight - minimumHeight;
  635. const vertices = new Uint16Array(
  636. uBuffer.length + vBuffer.length + heightBuffer.length
  637. );
  638. for (i = 0; i < uBuffer.length; ++i) {
  639. vertices[i] = uBuffer[i];
  640. }
  641. let start = uBuffer.length;
  642. for (i = 0; i < vBuffer.length; ++i) {
  643. vertices[start + i] = vBuffer[i];
  644. }
  645. start += vBuffer.length;
  646. for (i = 0; i < heightBuffer.length; ++i) {
  647. vertices[start + i] =
  648. (maxShort * (heightBuffer[i] - minimumHeight)) / heightRange;
  649. }
  650. const indicesTypedArray = IndexDatatype.IndexDatatype.createTypedArray(
  651. uBuffer.length,
  652. indices
  653. );
  654. let encodedNormals;
  655. if (hasVertexNormals) {
  656. const normalArray = new Uint8Array(normalBuffer);
  657. transferableObjects.push(
  658. vertices.buffer,
  659. indicesTypedArray.buffer,
  660. normalArray.buffer
  661. );
  662. encodedNormals = normalArray.buffer;
  663. } else {
  664. transferableObjects.push(vertices.buffer, indicesTypedArray.buffer);
  665. }
  666. return {
  667. vertices: vertices.buffer,
  668. encodedNormals: encodedNormals,
  669. indices: indicesTypedArray.buffer,
  670. minimumHeight: minimumHeight,
  671. maximumHeight: maximumHeight,
  672. westIndices: westIndices,
  673. southIndices: southIndices,
  674. eastIndices: eastIndices,
  675. northIndices: northIndices,
  676. boundingSphere: boundingSphere,
  677. orientedBoundingBox: orientedBoundingBox,
  678. horizonOcclusionPoint: horizonOcclusionPoint,
  679. };
  680. }
  681. function Vertex() {
  682. this.vertexBuffer = undefined;
  683. this.index = undefined;
  684. this.first = undefined;
  685. this.second = undefined;
  686. this.ratio = undefined;
  687. }
  688. Vertex.prototype.clone = function (result) {
  689. if (!defaultValue.defined(result)) {
  690. result = new Vertex();
  691. }
  692. result.uBuffer = this.uBuffer;
  693. result.vBuffer = this.vBuffer;
  694. result.heightBuffer = this.heightBuffer;
  695. result.normalBuffer = this.normalBuffer;
  696. result.index = this.index;
  697. result.first = this.first;
  698. result.second = this.second;
  699. result.ratio = this.ratio;
  700. return result;
  701. };
  702. Vertex.prototype.initializeIndexed = function (
  703. uBuffer,
  704. vBuffer,
  705. heightBuffer,
  706. normalBuffer,
  707. index
  708. ) {
  709. this.uBuffer = uBuffer;
  710. this.vBuffer = vBuffer;
  711. this.heightBuffer = heightBuffer;
  712. this.normalBuffer = normalBuffer;
  713. this.index = index;
  714. this.first = undefined;
  715. this.second = undefined;
  716. this.ratio = undefined;
  717. };
  718. Vertex.prototype.initializeFromClipResult = function (
  719. clipResult,
  720. index,
  721. vertices
  722. ) {
  723. let nextIndex = index + 1;
  724. if (clipResult[index] !== -1) {
  725. vertices[clipResult[index]].clone(this);
  726. } else {
  727. this.vertexBuffer = undefined;
  728. this.index = undefined;
  729. this.first = vertices[clipResult[nextIndex]];
  730. ++nextIndex;
  731. this.second = vertices[clipResult[nextIndex]];
  732. ++nextIndex;
  733. this.ratio = clipResult[nextIndex];
  734. ++nextIndex;
  735. }
  736. return nextIndex;
  737. };
  738. Vertex.prototype.getKey = function () {
  739. if (this.isIndexed()) {
  740. return this.index;
  741. }
  742. return JSON.stringify({
  743. first: this.first.getKey(),
  744. second: this.second.getKey(),
  745. ratio: this.ratio,
  746. });
  747. };
  748. Vertex.prototype.isIndexed = function () {
  749. return defaultValue.defined(this.index);
  750. };
  751. Vertex.prototype.getH = function () {
  752. if (defaultValue.defined(this.index)) {
  753. return this.heightBuffer[this.index];
  754. }
  755. return ComponentDatatype.CesiumMath.lerp(this.first.getH(), this.second.getH(), this.ratio);
  756. };
  757. Vertex.prototype.getU = function () {
  758. if (defaultValue.defined(this.index)) {
  759. return this.uBuffer[this.index];
  760. }
  761. return ComponentDatatype.CesiumMath.lerp(this.first.getU(), this.second.getU(), this.ratio);
  762. };
  763. Vertex.prototype.getV = function () {
  764. if (defaultValue.defined(this.index)) {
  765. return this.vBuffer[this.index];
  766. }
  767. return ComponentDatatype.CesiumMath.lerp(this.first.getV(), this.second.getV(), this.ratio);
  768. };
  769. let encodedScratch = new Matrix2.Cartesian2();
  770. // An upsampled triangle may be clipped twice before it is assigned an index
  771. // In this case, we need a buffer to handle the recursion of getNormalX() and getNormalY().
  772. let depth = -1;
  773. const cartesianScratch1 = [new Matrix2.Cartesian3(), new Matrix2.Cartesian3()];
  774. const cartesianScratch2 = [new Matrix2.Cartesian3(), new Matrix2.Cartesian3()];
  775. function lerpOctEncodedNormal(vertex, result) {
  776. ++depth;
  777. let first = cartesianScratch1[depth];
  778. let second = cartesianScratch2[depth];
  779. first = AttributeCompression.AttributeCompression.octDecode(
  780. vertex.first.getNormalX(),
  781. vertex.first.getNormalY(),
  782. first
  783. );
  784. second = AttributeCompression.AttributeCompression.octDecode(
  785. vertex.second.getNormalX(),
  786. vertex.second.getNormalY(),
  787. second
  788. );
  789. cartesian3Scratch = Matrix2.Cartesian3.lerp(
  790. first,
  791. second,
  792. vertex.ratio,
  793. cartesian3Scratch
  794. );
  795. Matrix2.Cartesian3.normalize(cartesian3Scratch, cartesian3Scratch);
  796. AttributeCompression.AttributeCompression.octEncode(cartesian3Scratch, result);
  797. --depth;
  798. return result;
  799. }
  800. Vertex.prototype.getNormalX = function () {
  801. if (defaultValue.defined(this.index)) {
  802. return this.normalBuffer[this.index * 2];
  803. }
  804. encodedScratch = lerpOctEncodedNormal(this, encodedScratch);
  805. return encodedScratch.x;
  806. };
  807. Vertex.prototype.getNormalY = function () {
  808. if (defaultValue.defined(this.index)) {
  809. return this.normalBuffer[this.index * 2 + 1];
  810. }
  811. encodedScratch = lerpOctEncodedNormal(this, encodedScratch);
  812. return encodedScratch.y;
  813. };
  814. const polygonVertices = [];
  815. polygonVertices.push(new Vertex());
  816. polygonVertices.push(new Vertex());
  817. polygonVertices.push(new Vertex());
  818. polygonVertices.push(new Vertex());
  819. function addClippedPolygon(
  820. uBuffer,
  821. vBuffer,
  822. heightBuffer,
  823. normalBuffer,
  824. indices,
  825. vertexMap,
  826. clipped,
  827. triangleVertices,
  828. hasVertexNormals
  829. ) {
  830. if (clipped.length === 0) {
  831. return;
  832. }
  833. let numVertices = 0;
  834. let clippedIndex = 0;
  835. while (clippedIndex < clipped.length) {
  836. clippedIndex = polygonVertices[numVertices++].initializeFromClipResult(
  837. clipped,
  838. clippedIndex,
  839. triangleVertices
  840. );
  841. }
  842. for (let i = 0; i < numVertices; ++i) {
  843. const polygonVertex = polygonVertices[i];
  844. if (!polygonVertex.isIndexed()) {
  845. const key = polygonVertex.getKey();
  846. if (defaultValue.defined(vertexMap[key])) {
  847. polygonVertex.newIndex = vertexMap[key];
  848. } else {
  849. const newIndex = uBuffer.length;
  850. uBuffer.push(polygonVertex.getU());
  851. vBuffer.push(polygonVertex.getV());
  852. heightBuffer.push(polygonVertex.getH());
  853. if (hasVertexNormals) {
  854. normalBuffer.push(polygonVertex.getNormalX());
  855. normalBuffer.push(polygonVertex.getNormalY());
  856. }
  857. polygonVertex.newIndex = newIndex;
  858. vertexMap[key] = newIndex;
  859. }
  860. } else {
  861. polygonVertex.newIndex = vertexMap[polygonVertex.index];
  862. polygonVertex.uBuffer = uBuffer;
  863. polygonVertex.vBuffer = vBuffer;
  864. polygonVertex.heightBuffer = heightBuffer;
  865. if (hasVertexNormals) {
  866. polygonVertex.normalBuffer = normalBuffer;
  867. }
  868. }
  869. }
  870. if (numVertices === 3) {
  871. // A triangle.
  872. indices.push(polygonVertices[0].newIndex);
  873. indices.push(polygonVertices[1].newIndex);
  874. indices.push(polygonVertices[2].newIndex);
  875. } else if (numVertices === 4) {
  876. // A quad - two triangles.
  877. indices.push(polygonVertices[0].newIndex);
  878. indices.push(polygonVertices[1].newIndex);
  879. indices.push(polygonVertices[2].newIndex);
  880. indices.push(polygonVertices[0].newIndex);
  881. indices.push(polygonVertices[2].newIndex);
  882. indices.push(polygonVertices[3].newIndex);
  883. }
  884. }
  885. var upsampleQuantizedTerrainMesh$1 = createTaskProcessorWorker(upsampleQuantizedTerrainMesh);
  886. return upsampleQuantizedTerrainMesh$1;
  887. }));