upsampleQuantizedTerrainMesh.js 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854
  1. /**
  2. * Cesium - https://github.com/AnalyticalGraphicsInc/cesium
  3. *
  4. * Copyright 2011-2017 Cesium Contributors
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. *
  18. * Columbus View (Pat. Pend.)
  19. *
  20. * Portions licensed separately.
  21. * See https://github.com/AnalyticalGraphicsInc/cesium/blob/master/LICENSE.md for full licensing details.
  22. */
  23. define(['./when-8d13db60', './Check-70bec281', './Math-61ede240', './Cartographic-fe4be337', './Cartesian2-85064f09', './BoundingSphere-775c5788', './Cartesian4-5af5bb24', './RuntimeError-ba10bc3e', './WebGLConstants-4c11ee5f', './ComponentDatatype-5862616f', './FeatureDetection-7bd32c34', './Transforms-b2e71640', './buildModuleUrl-14bfe498', './AttributeCompression-84a90a13', './IndexDatatype-9435b55f', './IntersectionTests-397d9494', './Plane-8390418f', './createTaskProcessorWorker', './EllipsoidTangentPlane-a815c96f', './OrientedBoundingBox-635e6e10', './TerrainEncoding-a807a704'], function (when, Check, _Math, Cartographic, Cartesian2, BoundingSphere, Cartesian4, RuntimeError, WebGLConstants, ComponentDatatype, FeatureDetection, Transforms, buildModuleUrl, AttributeCompression, IndexDatatype, IntersectionTests, Plane, createTaskProcessorWorker, EllipsoidTangentPlane, OrientedBoundingBox, TerrainEncoding) { 'use strict';
  24. /**
  25. * Contains functions for operating on 2D triangles.
  26. *
  27. * @exports Intersections2D
  28. */
  29. var Intersections2D = {};
  30. /**
  31. * Splits a 2D triangle at given axis-aligned threshold value and returns the resulting
  32. * polygon on a given side of the threshold. The resulting polygon may have 0, 1, 2,
  33. * 3, or 4 vertices.
  34. *
  35. * @param {Number} threshold The threshold coordinate value at which to clip the triangle.
  36. * @param {Boolean} keepAbove true to keep the portion of the triangle above the threshold, or false
  37. * to keep the portion below.
  38. * @param {Number} u0 The coordinate of the first vertex in the triangle, in counter-clockwise order.
  39. * @param {Number} u1 The coordinate of the second vertex in the triangle, in counter-clockwise order.
  40. * @param {Number} u2 The coordinate of the third vertex in the triangle, in counter-clockwise order.
  41. * @param {Number[]} [result] The array into which to copy the result. If this parameter is not supplied,
  42. * a new array is constructed and returned.
  43. * @returns {Number[]} The polygon that results after the clip, specified as a list of
  44. * vertices. The vertices are specified in counter-clockwise order.
  45. * Each vertex is either an index from the existing list (identified as
  46. * a 0, 1, or 2) or -1 indicating a new vertex not in the original triangle.
  47. * For new vertices, the -1 is followed by three additional numbers: the
  48. * index of each of the two original vertices forming the line segment that
  49. * the new vertex lies on, and the fraction of the distance from the first
  50. * vertex to the second one.
  51. *
  52. * @example
  53. * var result = Cesium.Intersections2D.clipTriangleAtAxisAlignedThreshold(0.5, false, 0.2, 0.6, 0.4);
  54. * // result === [2, 0, -1, 1, 0, 0.25, -1, 1, 2, 0.5]
  55. */
  56. Intersections2D.clipTriangleAtAxisAlignedThreshold = function(threshold, keepAbove, u0, u1, u2, result) {
  57. //>>includeStart('debug', pragmas.debug);
  58. if (!when.defined(threshold)) {
  59. throw new Check.DeveloperError('threshold is required.');
  60. }
  61. if (!when.defined(keepAbove)) {
  62. throw new Check.DeveloperError('keepAbove is required.');
  63. }
  64. if (!when.defined(u0)) {
  65. throw new Check.DeveloperError('u0 is required.');
  66. }
  67. if (!when.defined(u1)) {
  68. throw new Check.DeveloperError('u1 is required.');
  69. }
  70. if (!when.defined(u2)) {
  71. throw new Check.DeveloperError('u2 is required.');
  72. }
  73. //>>includeEnd('debug');
  74. if (!when.defined(result)) {
  75. result = [];
  76. } else {
  77. result.length = 0;
  78. }
  79. var u0Behind;
  80. var u1Behind;
  81. var u2Behind;
  82. if (keepAbove) {
  83. u0Behind = u0 < threshold;
  84. u1Behind = u1 < threshold;
  85. u2Behind = u2 < threshold;
  86. } else {
  87. u0Behind = u0 > threshold;
  88. u1Behind = u1 > threshold;
  89. u2Behind = u2 > threshold;
  90. }
  91. var numBehind = u0Behind + u1Behind + u2Behind;
  92. var u01Ratio;
  93. var u02Ratio;
  94. var u12Ratio;
  95. var u10Ratio;
  96. var u20Ratio;
  97. var u21Ratio;
  98. if (numBehind === 1) {
  99. if (u0Behind) {
  100. u01Ratio = (threshold - u0) / (u1 - u0);
  101. u02Ratio = (threshold - u0) / (u2 - u0);
  102. result.push(1);
  103. result.push(2);
  104. if (u02Ratio !== 1.0) {
  105. result.push(-1);
  106. result.push(0);
  107. result.push(2);
  108. result.push(u02Ratio);
  109. }
  110. if (u01Ratio !== 1.0) {
  111. result.push(-1);
  112. result.push(0);
  113. result.push(1);
  114. result.push(u01Ratio);
  115. }
  116. } else if (u1Behind) {
  117. u12Ratio = (threshold - u1) / (u2 - u1);
  118. u10Ratio = (threshold - u1) / (u0 - u1);
  119. result.push(2);
  120. result.push(0);
  121. if (u10Ratio !== 1.0) {
  122. result.push(-1);
  123. result.push(1);
  124. result.push(0);
  125. result.push(u10Ratio);
  126. }
  127. if (u12Ratio !== 1.0) {
  128. result.push(-1);
  129. result.push(1);
  130. result.push(2);
  131. result.push(u12Ratio);
  132. }
  133. } else if (u2Behind) {
  134. u20Ratio = (threshold - u2) / (u0 - u2);
  135. u21Ratio = (threshold - u2) / (u1 - u2);
  136. result.push(0);
  137. result.push(1);
  138. if (u21Ratio !== 1.0) {
  139. result.push(-1);
  140. result.push(2);
  141. result.push(1);
  142. result.push(u21Ratio);
  143. }
  144. if (u20Ratio !== 1.0) {
  145. result.push(-1);
  146. result.push(2);
  147. result.push(0);
  148. result.push(u20Ratio);
  149. }
  150. }
  151. } else if (numBehind === 2) {
  152. if (!u0Behind && u0 !== threshold) {
  153. u10Ratio = (threshold - u1) / (u0 - u1);
  154. u20Ratio = (threshold - u2) / (u0 - u2);
  155. result.push(0);
  156. result.push(-1);
  157. result.push(1);
  158. result.push(0);
  159. result.push(u10Ratio);
  160. result.push(-1);
  161. result.push(2);
  162. result.push(0);
  163. result.push(u20Ratio);
  164. } else if (!u1Behind && u1 !== threshold) {
  165. u21Ratio = (threshold - u2) / (u1 - u2);
  166. u01Ratio = (threshold - u0) / (u1 - u0);
  167. result.push(1);
  168. result.push(-1);
  169. result.push(2);
  170. result.push(1);
  171. result.push(u21Ratio);
  172. result.push(-1);
  173. result.push(0);
  174. result.push(1);
  175. result.push(u01Ratio);
  176. } else if (!u2Behind && u2 !== threshold) {
  177. u02Ratio = (threshold - u0) / (u2 - u0);
  178. u12Ratio = (threshold - u1) / (u2 - u1);
  179. result.push(2);
  180. result.push(-1);
  181. result.push(0);
  182. result.push(2);
  183. result.push(u02Ratio);
  184. result.push(-1);
  185. result.push(1);
  186. result.push(2);
  187. result.push(u12Ratio);
  188. }
  189. } else if (numBehind !== 3) {
  190. // Completely in front of threshold
  191. result.push(0);
  192. result.push(1);
  193. result.push(2);
  194. }
  195. // else Completely behind threshold
  196. return result;
  197. };
  198. /**
  199. * Compute the barycentric coordinates of a 2D position within a 2D triangle.
  200. *
  201. * @param {Number} x The x coordinate of the position for which to find the barycentric coordinates.
  202. * @param {Number} y The y coordinate of the position for which to find the barycentric coordinates.
  203. * @param {Number} x1 The x coordinate of the triangle's first vertex.
  204. * @param {Number} y1 The y coordinate of the triangle's first vertex.
  205. * @param {Number} x2 The x coordinate of the triangle's second vertex.
  206. * @param {Number} y2 The y coordinate of the triangle's second vertex.
  207. * @param {Number} x3 The x coordinate of the triangle's third vertex.
  208. * @param {Number} y3 The y coordinate of the triangle's third vertex.
  209. * @param {Cartesian3} [result] The instance into to which to copy the result. If this parameter
  210. * is undefined, a new instance is created and returned.
  211. * @returns {Cartesian3} The barycentric coordinates of the position within the triangle.
  212. *
  213. * @example
  214. * var result = Cesium.Intersections2D.computeBarycentricCoordinates(0.0, 0.0, 0.0, 1.0, -1, -0.5, 1, -0.5);
  215. * // result === new Cesium.Cartesian3(1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0);
  216. */
  217. Intersections2D.computeBarycentricCoordinates = function(x, y, x1, y1, x2, y2, x3, y3, result) {
  218. //>>includeStart('debug', pragmas.debug);
  219. if (!when.defined(x)) {
  220. throw new Check.DeveloperError('x is required.');
  221. }
  222. if (!when.defined(y)) {
  223. throw new Check.DeveloperError('y is required.');
  224. }
  225. if (!when.defined(x1)) {
  226. throw new Check.DeveloperError('x1 is required.');
  227. }
  228. if (!when.defined(y1)) {
  229. throw new Check.DeveloperError('y1 is required.');
  230. }
  231. if (!when.defined(x2)) {
  232. throw new Check.DeveloperError('x2 is required.');
  233. }
  234. if (!when.defined(y2)) {
  235. throw new Check.DeveloperError('y2 is required.');
  236. }
  237. if (!when.defined(x3)) {
  238. throw new Check.DeveloperError('x3 is required.');
  239. }
  240. if (!when.defined(y3)) {
  241. throw new Check.DeveloperError('y3 is required.');
  242. }
  243. //>>includeEnd('debug');
  244. var x1mx3 = x1 - x3;
  245. var x3mx2 = x3 - x2;
  246. var y2my3 = y2 - y3;
  247. var y1my3 = y1 - y3;
  248. var inverseDeterminant = 1.0 / (y2my3 * x1mx3 + x3mx2 * y1my3);
  249. var ymy3 = y - y3;
  250. var xmx3 = x - x3;
  251. var l1 = (y2my3 * xmx3 + x3mx2 * ymy3) * inverseDeterminant;
  252. var l2 = (-y1my3 * xmx3 + x1mx3 * ymy3) * inverseDeterminant;
  253. var l3 = 1.0 - l1 - l2;
  254. if (when.defined(result)) {
  255. result.x = l1;
  256. result.y = l2;
  257. result.z = l3;
  258. return result;
  259. }
  260. return new Cartographic.Cartesian3(l1, l2, l3);
  261. };
  262. /**
  263. * Compute the intersection between 2 line segments
  264. *
  265. * @param {Number} x00 The x coordinate of the first line's first vertex.
  266. * @param {Number} y00 The y coordinate of the first line's first vertex.
  267. * @param {Number} x01 The x coordinate of the first line's second vertex.
  268. * @param {Number} y01 The y coordinate of the first line's second vertex.
  269. * @param {Number} x10 The x coordinate of the second line's first vertex.
  270. * @param {Number} y10 The y coordinate of the second line's first vertex.
  271. * @param {Number} x11 The x coordinate of the second line's second vertex.
  272. * @param {Number} y11 The y coordinate of the second line's second vertex.
  273. * @param {Cartesian2} [result] The instance into to which to copy the result. If this parameter
  274. * is undefined, a new instance is created and returned.
  275. * @returns {Cartesian2} The intersection point, undefined if there is no intersection point or lines are coincident.
  276. *
  277. * @example
  278. * var result = Cesium.Intersections2D.computeLineSegmentLineSegmentIntersection(0.0, 0.0, 0.0, 2.0, -1, 1, 1, 1);
  279. * // result === new Cesium.Cartesian2(0.0, 1.0);
  280. */
  281. Intersections2D.computeLineSegmentLineSegmentIntersection = function(x00, y00, x01, y01, x10, y10, x11, y11, result) {
  282. //>>includeStart('debug', pragmas.debug);
  283. Check.Check.typeOf.number('x00', x00);
  284. Check.Check.typeOf.number('y00', y00);
  285. Check.Check.typeOf.number('x01', x01);
  286. Check.Check.typeOf.number('y01', y01);
  287. Check.Check.typeOf.number('x10', x10);
  288. Check.Check.typeOf.number('y10', y10);
  289. Check.Check.typeOf.number('x11', x11);
  290. Check.Check.typeOf.number('y11', y11);
  291. //>>includeEnd('debug');
  292. var numerator1A = (x11 - x10) * (y00 - y10) - (y11 - y10) * (x00 - x10);
  293. var numerator1B = (x01 - x00) * (y00 - y10) - (y01 - y00) * (x00 - x10);
  294. var denominator1 = (y11 - y10) * (x01 - x00) - (x11 - x10) * (y01 - y00);
  295. // If denominator = 0, then lines are parallel. If denominator = 0 and both numerators are 0, then coincident
  296. if (denominator1 === 0) {
  297. return;
  298. }
  299. var ua1 = numerator1A / denominator1;
  300. var ub1 = numerator1B / denominator1;
  301. if (ua1 >= 0 && ua1 <= 1 && ub1 >= 0 && ub1 <= 1) {
  302. if (!when.defined(result)) {
  303. result = new Cartesian2.Cartesian2();
  304. }
  305. result.x = x00 + ua1 * (x01 - x00);
  306. result.y = y00 + ua1 * (y01 - y00);
  307. return result;
  308. }
  309. };
  310. var maxShort = 32767;
  311. var halfMaxShort = (maxShort / 2) | 0;
  312. var clipScratch = [];
  313. var clipScratch2 = [];
  314. var verticesScratch = [];
  315. var cartographicScratch = new Cartographic.Cartographic();
  316. var cartesian3Scratch = new Cartographic.Cartesian3();
  317. var uScratch = [];
  318. var vScratch = [];
  319. var heightScratch = [];
  320. var indicesScratch = [];
  321. var normalsScratch = [];
  322. var horizonOcclusionPointScratch = new Cartographic.Cartesian3();
  323. var boundingSphereScratch = new BoundingSphere.BoundingSphere();
  324. var orientedBoundingBoxScratch = new OrientedBoundingBox.OrientedBoundingBox();
  325. var decodeTexCoordsScratch = new Cartesian2.Cartesian2();
  326. var octEncodedNormalScratch = new Cartographic.Cartesian3();
  327. function upsampleQuantizedTerrainMesh(parameters, transferableObjects) {
  328. var isEastChild = parameters.isEastChild;
  329. var isNorthChild = parameters.isNorthChild;
  330. var minU = isEastChild ? halfMaxShort : 0;
  331. var maxU = isEastChild ? maxShort : halfMaxShort;
  332. var minV = isNorthChild ? halfMaxShort : 0;
  333. var maxV = isNorthChild ? maxShort : halfMaxShort;
  334. var uBuffer = uScratch;
  335. var vBuffer = vScratch;
  336. var heightBuffer = heightScratch;
  337. var normalBuffer = normalsScratch;
  338. uBuffer.length = 0;
  339. vBuffer.length = 0;
  340. heightBuffer.length = 0;
  341. normalBuffer.length = 0;
  342. var indices = indicesScratch;
  343. indices.length = 0;
  344. var vertexMap = {};
  345. var parentVertices = parameters.vertices;
  346. var parentIndices = parameters.indices;
  347. parentIndices = parentIndices.subarray(0, parameters.indexCountWithoutSkirts);
  348. var encoding = TerrainEncoding.TerrainEncoding.clone(parameters.encoding);
  349. var hasVertexNormals = encoding.hasVertexNormals;
  350. var exaggeration = parameters.exaggeration;
  351. var vertexCount = 0;
  352. var quantizedVertexCount = parameters.vertexCountWithoutSkirts;
  353. var parentMinimumHeight = parameters.minimumHeight;
  354. var parentMaximumHeight = parameters.maximumHeight;
  355. var parentUBuffer = new Array(quantizedVertexCount);
  356. var parentVBuffer = new Array(quantizedVertexCount);
  357. var parentHeightBuffer = new Array(quantizedVertexCount);
  358. var parentNormalBuffer = hasVertexNormals ? new Array(quantizedVertexCount * 2) : undefined;
  359. var threshold = 20;
  360. var height;
  361. var i, n;
  362. var u, v;
  363. for (i = 0, n = 0; i < quantizedVertexCount; ++i, n += 2) {
  364. var texCoords = encoding.decodeTextureCoordinates(parentVertices, i, decodeTexCoordsScratch);
  365. height = encoding.decodeHeight(parentVertices, i) / exaggeration;
  366. u = _Math.CesiumMath.clamp((texCoords.x * maxShort) | 0, 0, maxShort);
  367. v = _Math.CesiumMath.clamp((texCoords.y * maxShort) | 0, 0, maxShort);
  368. parentHeightBuffer[i] = _Math.CesiumMath.clamp((((height - parentMinimumHeight) / (parentMaximumHeight - parentMinimumHeight)) * maxShort) | 0, 0, maxShort);
  369. if (u < threshold) {
  370. u = 0;
  371. }
  372. if (v < threshold) {
  373. v = 0;
  374. }
  375. if (maxShort - u < threshold) {
  376. u = maxShort;
  377. }
  378. if (maxShort - v < threshold) {
  379. v = maxShort;
  380. }
  381. parentUBuffer[i] = u;
  382. parentVBuffer[i] = v;
  383. if (hasVertexNormals) {
  384. var encodedNormal = encoding.getOctEncodedNormal(parentVertices, i, octEncodedNormalScratch);
  385. parentNormalBuffer[n] = encodedNormal.x;
  386. parentNormalBuffer[n + 1] = encodedNormal.y;
  387. }
  388. if ((isEastChild && u >= halfMaxShort || !isEastChild && u <= halfMaxShort) &&
  389. (isNorthChild && v >= halfMaxShort || !isNorthChild && v <= halfMaxShort)) {
  390. vertexMap[i] = vertexCount;
  391. uBuffer.push(u);
  392. vBuffer.push(v);
  393. heightBuffer.push(parentHeightBuffer[i]);
  394. if (hasVertexNormals) {
  395. normalBuffer.push(parentNormalBuffer[n]);
  396. normalBuffer.push(parentNormalBuffer[n + 1]);
  397. }
  398. ++vertexCount;
  399. }
  400. }
  401. var triangleVertices = [];
  402. triangleVertices.push(new Vertex());
  403. triangleVertices.push(new Vertex());
  404. triangleVertices.push(new Vertex());
  405. var clippedTriangleVertices = [];
  406. clippedTriangleVertices.push(new Vertex());
  407. clippedTriangleVertices.push(new Vertex());
  408. clippedTriangleVertices.push(new Vertex());
  409. var clippedIndex;
  410. var clipped2;
  411. for (i = 0; i < parentIndices.length; i += 3) {
  412. var i0 = parentIndices[i];
  413. var i1 = parentIndices[i + 1];
  414. var i2 = parentIndices[i + 2];
  415. var u0 = parentUBuffer[i0];
  416. var u1 = parentUBuffer[i1];
  417. var u2 = parentUBuffer[i2];
  418. triangleVertices[0].initializeIndexed(parentUBuffer, parentVBuffer, parentHeightBuffer, parentNormalBuffer, i0);
  419. triangleVertices[1].initializeIndexed(parentUBuffer, parentVBuffer, parentHeightBuffer, parentNormalBuffer, i1);
  420. triangleVertices[2].initializeIndexed(parentUBuffer, parentVBuffer, parentHeightBuffer, parentNormalBuffer, i2);
  421. // Clip triangle on the east-west boundary.
  422. var clipped = Intersections2D.clipTriangleAtAxisAlignedThreshold(halfMaxShort, isEastChild, u0, u1, u2, clipScratch);
  423. // Get the first clipped triangle, if any.
  424. clippedIndex = 0;
  425. if (clippedIndex >= clipped.length) {
  426. continue;
  427. }
  428. clippedIndex = clippedTriangleVertices[0].initializeFromClipResult(clipped, clippedIndex, triangleVertices);
  429. if (clippedIndex >= clipped.length) {
  430. continue;
  431. }
  432. clippedIndex = clippedTriangleVertices[1].initializeFromClipResult(clipped, clippedIndex, triangleVertices);
  433. if (clippedIndex >= clipped.length) {
  434. continue;
  435. }
  436. clippedIndex = clippedTriangleVertices[2].initializeFromClipResult(clipped, clippedIndex, triangleVertices);
  437. // Clip the triangle against the North-south boundary.
  438. clipped2 = Intersections2D.clipTriangleAtAxisAlignedThreshold(halfMaxShort, isNorthChild, clippedTriangleVertices[0].getV(), clippedTriangleVertices[1].getV(), clippedTriangleVertices[2].getV(), clipScratch2);
  439. addClippedPolygon(uBuffer, vBuffer, heightBuffer, normalBuffer, indices, vertexMap, clipped2, clippedTriangleVertices, hasVertexNormals);
  440. // If there's another vertex in the original clipped result,
  441. // it forms a second triangle. Clip it as well.
  442. if (clippedIndex < clipped.length) {
  443. clippedTriangleVertices[2].clone(clippedTriangleVertices[1]);
  444. clippedTriangleVertices[2].initializeFromClipResult(clipped, clippedIndex, triangleVertices);
  445. clipped2 = Intersections2D.clipTriangleAtAxisAlignedThreshold(halfMaxShort, isNorthChild, clippedTriangleVertices[0].getV(), clippedTriangleVertices[1].getV(), clippedTriangleVertices[2].getV(), clipScratch2);
  446. addClippedPolygon(uBuffer, vBuffer, heightBuffer, normalBuffer, indices, vertexMap, clipped2, clippedTriangleVertices, hasVertexNormals);
  447. }
  448. }
  449. var uOffset = isEastChild ? -maxShort : 0;
  450. var vOffset = isNorthChild ? -maxShort : 0;
  451. var westIndices = [];
  452. var southIndices = [];
  453. var eastIndices = [];
  454. var northIndices = [];
  455. var minimumHeight = Number.MAX_VALUE;
  456. var maximumHeight = -minimumHeight;
  457. var cartesianVertices = verticesScratch;
  458. cartesianVertices.length = 0;
  459. var ellipsoid = Cartesian2.Ellipsoid.clone(parameters.ellipsoid);
  460. var rectangle = Cartesian2.Rectangle.clone(parameters.childRectangle);
  461. var north = rectangle.north;
  462. var south = rectangle.south;
  463. var east = rectangle.east;
  464. var west = rectangle.west;
  465. if (east < west) {
  466. east += _Math.CesiumMath.TWO_PI;
  467. }
  468. for (i = 0; i < uBuffer.length; ++i) {
  469. u = Math.round(uBuffer[i]);
  470. if (u <= minU) {
  471. westIndices.push(i);
  472. u = 0;
  473. } else if (u >= maxU) {
  474. eastIndices.push(i);
  475. u = maxShort;
  476. } else {
  477. u = u * 2 + uOffset;
  478. }
  479. uBuffer[i] = u;
  480. v = Math.round(vBuffer[i]);
  481. if (v <= minV) {
  482. southIndices.push(i);
  483. v = 0;
  484. } else if (v >= maxV) {
  485. northIndices.push(i);
  486. v = maxShort;
  487. } else {
  488. v = v * 2 + vOffset;
  489. }
  490. vBuffer[i] = v;
  491. height = _Math.CesiumMath.lerp(parentMinimumHeight, parentMaximumHeight, heightBuffer[i] / maxShort);
  492. if (height < minimumHeight) {
  493. minimumHeight = height;
  494. }
  495. if (height > maximumHeight) {
  496. maximumHeight = height;
  497. }
  498. heightBuffer[i] = height;
  499. cartographicScratch.longitude = _Math.CesiumMath.lerp(west, east, u / maxShort);
  500. cartographicScratch.latitude = _Math.CesiumMath.lerp(south, north, v / maxShort);
  501. cartographicScratch.height = height;
  502. ellipsoid.cartographicToCartesian(cartographicScratch, cartesian3Scratch);
  503. cartesianVertices.push(cartesian3Scratch.x);
  504. cartesianVertices.push(cartesian3Scratch.y);
  505. cartesianVertices.push(cartesian3Scratch.z);
  506. }
  507. var boundingSphere = BoundingSphere.BoundingSphere.fromVertices(cartesianVertices, Cartographic.Cartesian3.ZERO, 3, boundingSphereScratch);
  508. var orientedBoundingBox = OrientedBoundingBox.OrientedBoundingBox.fromRectangle(rectangle, minimumHeight, maximumHeight, ellipsoid, orientedBoundingBoxScratch);
  509. var occluder = new TerrainEncoding.EllipsoidalOccluder(ellipsoid);
  510. var horizonOcclusionPoint = occluder.computeHorizonCullingPointFromVerticesPossiblyUnderEllipsoid(boundingSphere.center, cartesianVertices, 3, boundingSphere.center, minimumHeight, horizonOcclusionPointScratch);
  511. var heightRange = maximumHeight - minimumHeight;
  512. var vertices = new Uint16Array(uBuffer.length + vBuffer.length + heightBuffer.length);
  513. for (i = 0; i < uBuffer.length; ++i) {
  514. vertices[i] = uBuffer[i];
  515. }
  516. var start = uBuffer.length;
  517. for (i = 0; i < vBuffer.length; ++i) {
  518. vertices[start + i] = vBuffer[i];
  519. }
  520. start += vBuffer.length;
  521. for (i = 0; i < heightBuffer.length; ++i) {
  522. vertices[start + i] = maxShort * (heightBuffer[i] - minimumHeight) / heightRange;
  523. }
  524. var indicesTypedArray = IndexDatatype.IndexDatatype.createTypedArray(uBuffer.length, indices);
  525. var encodedNormals;
  526. if (hasVertexNormals) {
  527. var normalArray = new Uint8Array(normalBuffer);
  528. transferableObjects.push(vertices.buffer, indicesTypedArray.buffer, normalArray.buffer);
  529. encodedNormals = normalArray.buffer;
  530. } else {
  531. transferableObjects.push(vertices.buffer, indicesTypedArray.buffer);
  532. }
  533. return {
  534. vertices : vertices.buffer,
  535. encodedNormals : encodedNormals,
  536. indices : indicesTypedArray.buffer,
  537. minimumHeight : minimumHeight,
  538. maximumHeight : maximumHeight,
  539. westIndices : westIndices,
  540. southIndices : southIndices,
  541. eastIndices : eastIndices,
  542. northIndices : northIndices,
  543. boundingSphere : boundingSphere,
  544. orientedBoundingBox : orientedBoundingBox,
  545. horizonOcclusionPoint : horizonOcclusionPoint
  546. };
  547. }
  548. function Vertex() {
  549. this.vertexBuffer = undefined;
  550. this.index = undefined;
  551. this.first = undefined;
  552. this.second = undefined;
  553. this.ratio = undefined;
  554. }
  555. Vertex.prototype.clone = function(result) {
  556. if (!when.defined(result)) {
  557. result = new Vertex();
  558. }
  559. result.uBuffer = this.uBuffer;
  560. result.vBuffer = this.vBuffer;
  561. result.heightBuffer = this.heightBuffer;
  562. result.normalBuffer = this.normalBuffer;
  563. result.index = this.index;
  564. result.first = this.first;
  565. result.second = this.second;
  566. result.ratio = this.ratio;
  567. return result;
  568. };
  569. Vertex.prototype.initializeIndexed = function(uBuffer, vBuffer, heightBuffer, normalBuffer, index) {
  570. this.uBuffer = uBuffer;
  571. this.vBuffer = vBuffer;
  572. this.heightBuffer = heightBuffer;
  573. this.normalBuffer = normalBuffer;
  574. this.index = index;
  575. this.first = undefined;
  576. this.second = undefined;
  577. this.ratio = undefined;
  578. };
  579. Vertex.prototype.initializeFromClipResult = function(clipResult, index, vertices) {
  580. var nextIndex = index + 1;
  581. if (clipResult[index] !== -1) {
  582. vertices[clipResult[index]].clone(this);
  583. } else {
  584. this.vertexBuffer = undefined;
  585. this.index = undefined;
  586. this.first = vertices[clipResult[nextIndex]];
  587. ++nextIndex;
  588. this.second = vertices[clipResult[nextIndex]];
  589. ++nextIndex;
  590. this.ratio = clipResult[nextIndex];
  591. ++nextIndex;
  592. }
  593. return nextIndex;
  594. };
  595. Vertex.prototype.getKey = function() {
  596. if (this.isIndexed()) {
  597. return this.index;
  598. }
  599. return JSON.stringify({
  600. first : this.first.getKey(),
  601. second : this.second.getKey(),
  602. ratio : this.ratio
  603. });
  604. };
  605. Vertex.prototype.isIndexed = function() {
  606. return when.defined(this.index);
  607. };
  608. Vertex.prototype.getH = function() {
  609. if (when.defined(this.index)) {
  610. return this.heightBuffer[this.index];
  611. }
  612. return _Math.CesiumMath.lerp(this.first.getH(), this.second.getH(), this.ratio);
  613. };
  614. Vertex.prototype.getU = function() {
  615. if (when.defined(this.index)) {
  616. return this.uBuffer[this.index];
  617. }
  618. return _Math.CesiumMath.lerp(this.first.getU(), this.second.getU(), this.ratio);
  619. };
  620. Vertex.prototype.getV = function() {
  621. if (when.defined(this.index)) {
  622. return this.vBuffer[this.index];
  623. }
  624. return _Math.CesiumMath.lerp(this.first.getV(), this.second.getV(), this.ratio);
  625. };
  626. var encodedScratch = new Cartesian2.Cartesian2();
  627. // An upsampled triangle may be clipped twice before it is assigned an index
  628. // In this case, we need a buffer to handle the recursion of getNormalX() and getNormalY().
  629. var depth = -1;
  630. var cartesianScratch1 = [new Cartographic.Cartesian3(), new Cartographic.Cartesian3()];
  631. var cartesianScratch2 = [new Cartographic.Cartesian3(), new Cartographic.Cartesian3()];
  632. function lerpOctEncodedNormal(vertex, result) {
  633. ++depth;
  634. var first = cartesianScratch1[depth];
  635. var second = cartesianScratch2[depth];
  636. first = AttributeCompression.AttributeCompression.octDecode(vertex.first.getNormalX(), vertex.first.getNormalY(), first);
  637. second = AttributeCompression.AttributeCompression.octDecode(vertex.second.getNormalX(), vertex.second.getNormalY(), second);
  638. cartesian3Scratch = Cartographic.Cartesian3.lerp(first, second, vertex.ratio, cartesian3Scratch);
  639. Cartographic.Cartesian3.normalize(cartesian3Scratch, cartesian3Scratch);
  640. AttributeCompression.AttributeCompression.octEncode(cartesian3Scratch, result);
  641. --depth;
  642. return result;
  643. }
  644. Vertex.prototype.getNormalX = function() {
  645. if (when.defined(this.index)) {
  646. return this.normalBuffer[this.index * 2];
  647. }
  648. encodedScratch = lerpOctEncodedNormal(this, encodedScratch);
  649. return encodedScratch.x;
  650. };
  651. Vertex.prototype.getNormalY = function() {
  652. if (when.defined(this.index)) {
  653. return this.normalBuffer[this.index * 2 + 1];
  654. }
  655. encodedScratch = lerpOctEncodedNormal(this, encodedScratch);
  656. return encodedScratch.y;
  657. };
  658. var polygonVertices = [];
  659. polygonVertices.push(new Vertex());
  660. polygonVertices.push(new Vertex());
  661. polygonVertices.push(new Vertex());
  662. polygonVertices.push(new Vertex());
  663. function addClippedPolygon(uBuffer, vBuffer, heightBuffer, normalBuffer, indices, vertexMap, clipped, triangleVertices, hasVertexNormals) {
  664. if (clipped.length === 0) {
  665. return;
  666. }
  667. var numVertices = 0;
  668. var clippedIndex = 0;
  669. while (clippedIndex < clipped.length) {
  670. clippedIndex = polygonVertices[numVertices++].initializeFromClipResult(clipped, clippedIndex, triangleVertices);
  671. }
  672. for (var i = 0; i < numVertices; ++i) {
  673. var polygonVertex = polygonVertices[i];
  674. if (!polygonVertex.isIndexed()) {
  675. var key = polygonVertex.getKey();
  676. if (when.defined(vertexMap[key])) {
  677. polygonVertex.newIndex = vertexMap[key];
  678. } else {
  679. var newIndex = uBuffer.length;
  680. uBuffer.push(polygonVertex.getU());
  681. vBuffer.push(polygonVertex.getV());
  682. heightBuffer.push(polygonVertex.getH());
  683. if (hasVertexNormals) {
  684. normalBuffer.push(polygonVertex.getNormalX());
  685. normalBuffer.push(polygonVertex.getNormalY());
  686. }
  687. polygonVertex.newIndex = newIndex;
  688. vertexMap[key] = newIndex;
  689. }
  690. } else {
  691. polygonVertex.newIndex = vertexMap[polygonVertex.index];
  692. polygonVertex.uBuffer = uBuffer;
  693. polygonVertex.vBuffer = vBuffer;
  694. polygonVertex.heightBuffer = heightBuffer;
  695. if (hasVertexNormals) {
  696. polygonVertex.normalBuffer = normalBuffer;
  697. }
  698. }
  699. }
  700. if (numVertices === 3) {
  701. // A triangle.
  702. indices.push(polygonVertices[0].newIndex);
  703. indices.push(polygonVertices[1].newIndex);
  704. indices.push(polygonVertices[2].newIndex);
  705. } else if (numVertices === 4) {
  706. // A quad - two triangles.
  707. indices.push(polygonVertices[0].newIndex);
  708. indices.push(polygonVertices[1].newIndex);
  709. indices.push(polygonVertices[2].newIndex);
  710. indices.push(polygonVertices[0].newIndex);
  711. indices.push(polygonVertices[2].newIndex);
  712. indices.push(polygonVertices[3].newIndex);
  713. }
  714. }
  715. var upsampleQuantizedTerrainMesh$1 = createTaskProcessorWorker(upsampleQuantizedTerrainMesh);
  716. return upsampleQuantizedTerrainMesh$1;
  717. });