TerrainEncoding-a793a9ee.js 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035
  1. /* This file is automatically rebuilt by the Cesium build process. */
  2. define(['exports', './when-e6985d2a', './Check-24cae389', './Math-392d0035', './Cartesian2-a5d6dde9', './Transforms-81680c41', './ComponentDatatype-cb08e294', './AttributeCompression-114c6354'], function (exports, when, Check, _Math, Cartesian2, Transforms, ComponentDatatype, AttributeCompression) { 'use strict';
  3. /**
  4. * Determine whether or not other objects are visible or hidden behind the visible horizon defined by
  5. * an {@link Ellipsoid} and a camera position. The ellipsoid is assumed to be located at the
  6. * origin of the coordinate system. This class uses the algorithm described in the
  7. * {@link https://cesium.com/blog/2013/04/25/Horizon-culling/|Horizon Culling} blog post.
  8. *
  9. * @alias EllipsoidalOccluder
  10. *
  11. * @param {Ellipsoid} ellipsoid The ellipsoid to use as an occluder.
  12. * @param {Cartesian3} [cameraPosition] The coordinate of the viewer/camera. If this parameter is not
  13. * specified, {@link EllipsoidalOccluder#cameraPosition} must be called before
  14. * testing visibility.
  15. *
  16. * @constructor
  17. *
  18. * @example
  19. * // Construct an ellipsoidal occluder with radii 1.0, 1.1, and 0.9.
  20. * var cameraPosition = new Cesium.Cartesian3(5.0, 6.0, 7.0);
  21. * var occluderEllipsoid = new Cesium.Ellipsoid(1.0, 1.1, 0.9);
  22. * var occluder = new Cesium.EllipsoidalOccluder(occluderEllipsoid, cameraPosition);
  23. *
  24. * @private
  25. */
  26. function EllipsoidalOccluder(ellipsoid, cameraPosition) {
  27. //>>includeStart('debug', pragmas.debug);
  28. Check.Check.typeOf.object("ellipsoid", ellipsoid);
  29. //>>includeEnd('debug');
  30. this._ellipsoid = ellipsoid;
  31. this._cameraPosition = new Cartesian2.Cartesian3();
  32. this._cameraPositionInScaledSpace = new Cartesian2.Cartesian3();
  33. this._distanceToLimbInScaledSpaceSquared = 0.0;
  34. // cameraPosition fills in the above values
  35. if (when.defined(cameraPosition)) {
  36. this.cameraPosition = cameraPosition;
  37. }
  38. }
  39. Object.defineProperties(EllipsoidalOccluder.prototype, {
  40. /**
  41. * Gets the occluding ellipsoid.
  42. * @memberof EllipsoidalOccluder.prototype
  43. * @type {Ellipsoid}
  44. */
  45. ellipsoid: {
  46. get: function () {
  47. return this._ellipsoid;
  48. },
  49. },
  50. /**
  51. * Gets or sets the position of the camera.
  52. * @memberof EllipsoidalOccluder.prototype
  53. * @type {Cartesian3}
  54. */
  55. cameraPosition: {
  56. get: function () {
  57. return this._cameraPosition;
  58. },
  59. set: function (cameraPosition) {
  60. // See https://cesium.com/blog/2013/04/25/Horizon-culling/
  61. var ellipsoid = this._ellipsoid;
  62. var cv = ellipsoid.transformPositionToScaledSpace(
  63. cameraPosition,
  64. this._cameraPositionInScaledSpace
  65. );
  66. var vhMagnitudeSquared = Cartesian2.Cartesian3.magnitudeSquared(cv) - 1.0;
  67. Cartesian2.Cartesian3.clone(cameraPosition, this._cameraPosition);
  68. this._cameraPositionInScaledSpace = cv;
  69. this._distanceToLimbInScaledSpaceSquared = vhMagnitudeSquared;
  70. },
  71. },
  72. });
  73. var scratchCartesian = new Cartesian2.Cartesian3();
  74. /**
  75. * Determines whether or not a point, the <code>occludee</code>, is hidden from view by the occluder.
  76. *
  77. * @param {Cartesian3} occludee The point to test for visibility.
  78. * @returns {Boolean} <code>true</code> if the occludee is visible; otherwise <code>false</code>.
  79. *
  80. * @example
  81. * var cameraPosition = new Cesium.Cartesian3(0, 0, 2.5);
  82. * var ellipsoid = new Cesium.Ellipsoid(1.0, 1.1, 0.9);
  83. * var occluder = new Cesium.EllipsoidalOccluder(ellipsoid, cameraPosition);
  84. * var point = new Cesium.Cartesian3(0, -3, -3);
  85. * occluder.isPointVisible(point); //returns true
  86. */
  87. EllipsoidalOccluder.prototype.isPointVisible = function (occludee) {
  88. var ellipsoid = this._ellipsoid;
  89. var occludeeScaledSpacePosition = ellipsoid.transformPositionToScaledSpace(
  90. occludee,
  91. scratchCartesian
  92. );
  93. return isScaledSpacePointVisible(
  94. occludeeScaledSpacePosition,
  95. this._cameraPositionInScaledSpace,
  96. this._distanceToLimbInScaledSpaceSquared
  97. );
  98. };
  99. /**
  100. * Determines whether or not a point expressed in the ellipsoid scaled space, is hidden from view by the
  101. * occluder. To transform a Cartesian X, Y, Z position in the coordinate system aligned with the ellipsoid
  102. * into the scaled space, call {@link Ellipsoid#transformPositionToScaledSpace}.
  103. *
  104. * @param {Cartesian3} occludeeScaledSpacePosition The point to test for visibility, represented in the scaled space.
  105. * @returns {Boolean} <code>true</code> if the occludee is visible; otherwise <code>false</code>.
  106. *
  107. * @example
  108. * var cameraPosition = new Cesium.Cartesian3(0, 0, 2.5);
  109. * var ellipsoid = new Cesium.Ellipsoid(1.0, 1.1, 0.9);
  110. * var occluder = new Cesium.EllipsoidalOccluder(ellipsoid, cameraPosition);
  111. * var point = new Cesium.Cartesian3(0, -3, -3);
  112. * var scaledSpacePoint = ellipsoid.transformPositionToScaledSpace(point);
  113. * occluder.isScaledSpacePointVisible(scaledSpacePoint); //returns true
  114. */
  115. EllipsoidalOccluder.prototype.isScaledSpacePointVisible = function (
  116. occludeeScaledSpacePosition
  117. ) {
  118. return isScaledSpacePointVisible(
  119. occludeeScaledSpacePosition,
  120. this._cameraPositionInScaledSpace,
  121. this._distanceToLimbInScaledSpaceSquared
  122. );
  123. };
  124. var scratchCameraPositionInScaledSpaceShrunk = new Cartesian2.Cartesian3();
  125. /**
  126. * Similar to {@link EllipsoidalOccluder#isScaledSpacePointVisible} except tests against an
  127. * ellipsoid that has been shrunk by the minimum height when the minimum height is below
  128. * the ellipsoid. This is intended to be used with points generated by
  129. * {@link EllipsoidalOccluder#computeHorizonCullingPointPossiblyUnderEllipsoid} or
  130. * {@link EllipsoidalOccluder#computeHorizonCullingPointFromVerticesPossiblyUnderEllipsoid}.
  131. *
  132. * @param {Cartesian3} occludeeScaledSpacePosition The point to test for visibility, represented in the scaled space of the possibly-shrunk ellipsoid.
  133. * @returns {Boolean} <code>true</code> if the occludee is visible; otherwise <code>false</code>.
  134. */
  135. EllipsoidalOccluder.prototype.isScaledSpacePointVisiblePossiblyUnderEllipsoid = function (
  136. occludeeScaledSpacePosition,
  137. minimumHeight
  138. ) {
  139. var ellipsoid = this._ellipsoid;
  140. var vhMagnitudeSquared;
  141. var cv;
  142. if (
  143. when.defined(minimumHeight) &&
  144. minimumHeight < 0.0 &&
  145. ellipsoid.minimumRadius > -minimumHeight
  146. ) {
  147. // This code is similar to the cameraPosition setter, but unrolled for performance because it will be called a lot.
  148. cv = scratchCameraPositionInScaledSpaceShrunk;
  149. cv.x = this._cameraPosition.x / (ellipsoid.radii.x + minimumHeight);
  150. cv.y = this._cameraPosition.y / (ellipsoid.radii.y + minimumHeight);
  151. cv.z = this._cameraPosition.z / (ellipsoid.radii.z + minimumHeight);
  152. vhMagnitudeSquared = cv.x * cv.x + cv.y * cv.y + cv.z * cv.z - 1.0;
  153. } else {
  154. cv = this._cameraPositionInScaledSpace;
  155. vhMagnitudeSquared = this._distanceToLimbInScaledSpaceSquared;
  156. }
  157. return isScaledSpacePointVisible(
  158. occludeeScaledSpacePosition,
  159. cv,
  160. vhMagnitudeSquared
  161. );
  162. };
  163. /**
  164. * Computes a point that can be used for horizon culling from a list of positions. If the point is below
  165. * the horizon, all of the positions are guaranteed to be below the horizon as well. The returned point
  166. * is expressed in the ellipsoid-scaled space and is suitable for use with
  167. * {@link EllipsoidalOccluder#isScaledSpacePointVisible}.
  168. *
  169. * @param {Cartesian3} directionToPoint The direction that the computed point will lie along.
  170. * A reasonable direction to use is the direction from the center of the ellipsoid to
  171. * the center of the bounding sphere computed from the positions. The direction need not
  172. * be normalized.
  173. * @param {Cartesian3[]} positions The positions from which to compute the horizon culling point. The positions
  174. * must be expressed in a reference frame centered at the ellipsoid and aligned with the
  175. * ellipsoid's axes.
  176. * @param {Cartesian3} [result] The instance on which to store the result instead of allocating a new instance.
  177. * @returns {Cartesian3} The computed horizon culling point, expressed in the ellipsoid-scaled space.
  178. */
  179. EllipsoidalOccluder.prototype.computeHorizonCullingPoint = function (
  180. directionToPoint,
  181. positions,
  182. result
  183. ) {
  184. return computeHorizonCullingPointFromPositions(
  185. this._ellipsoid,
  186. directionToPoint,
  187. positions,
  188. result
  189. );
  190. };
  191. var scratchEllipsoidShrunk = Cartesian2.Ellipsoid.clone(Cartesian2.Ellipsoid.UNIT_SPHERE);
  192. /**
  193. * Similar to {@link EllipsoidalOccluder#computeHorizonCullingPoint} except computes the culling
  194. * point relative to an ellipsoid that has been shrunk by the minimum height when the minimum height is below
  195. * the ellipsoid. The returned point is expressed in the possibly-shrunk ellipsoid-scaled space and is suitable
  196. * for use with {@link EllipsoidalOccluder#isScaledSpacePointVisiblePossiblyUnderEllipsoid}.
  197. *
  198. * @param {Cartesian3} directionToPoint The direction that the computed point will lie along.
  199. * A reasonable direction to use is the direction from the center of the ellipsoid to
  200. * the center of the bounding sphere computed from the positions. The direction need not
  201. * be normalized.
  202. * @param {Cartesian3[]} positions The positions from which to compute the horizon culling point. The positions
  203. * must be expressed in a reference frame centered at the ellipsoid and aligned with the
  204. * ellipsoid's axes.
  205. * @param {Number} [minimumHeight] The minimum height of all positions. If this value is undefined, all positions are assumed to be above the ellipsoid.
  206. * @param {Cartesian3} [result] The instance on which to store the result instead of allocating a new instance.
  207. * @returns {Cartesian3} The computed horizon culling point, expressed in the possibly-shrunk ellipsoid-scaled space.
  208. */
  209. EllipsoidalOccluder.prototype.computeHorizonCullingPointPossiblyUnderEllipsoid = function (
  210. directionToPoint,
  211. positions,
  212. minimumHeight,
  213. result
  214. ) {
  215. var possiblyShrunkEllipsoid = getPossiblyShrunkEllipsoid(
  216. this._ellipsoid,
  217. minimumHeight,
  218. scratchEllipsoidShrunk
  219. );
  220. return computeHorizonCullingPointFromPositions(
  221. possiblyShrunkEllipsoid,
  222. directionToPoint,
  223. positions,
  224. result
  225. );
  226. };
  227. /**
  228. * Computes a point that can be used for horizon culling from a list of positions. If the point is below
  229. * the horizon, all of the positions are guaranteed to be below the horizon as well. The returned point
  230. * is expressed in the ellipsoid-scaled space and is suitable for use with
  231. * {@link EllipsoidalOccluder#isScaledSpacePointVisible}.
  232. *
  233. * @param {Cartesian3} directionToPoint The direction that the computed point will lie along.
  234. * A reasonable direction to use is the direction from the center of the ellipsoid to
  235. * the center of the bounding sphere computed from the positions. The direction need not
  236. * be normalized.
  237. * @param {Number[]} vertices The vertices from which to compute the horizon culling point. The positions
  238. * must be expressed in a reference frame centered at the ellipsoid and aligned with the
  239. * ellipsoid's axes.
  240. * @param {Number} [stride=3]
  241. * @param {Cartesian3} [center=Cartesian3.ZERO]
  242. * @param {Cartesian3} [result] The instance on which to store the result instead of allocating a new instance.
  243. * @returns {Cartesian3} The computed horizon culling point, expressed in the ellipsoid-scaled space.
  244. */
  245. EllipsoidalOccluder.prototype.computeHorizonCullingPointFromVertices = function (
  246. directionToPoint,
  247. vertices,
  248. stride,
  249. center,
  250. result
  251. ) {
  252. return computeHorizonCullingPointFromVertices(
  253. this._ellipsoid,
  254. directionToPoint,
  255. vertices,
  256. stride,
  257. center,
  258. result
  259. );
  260. };
  261. /**
  262. * Similar to {@link EllipsoidalOccluder#computeHorizonCullingPointFromVertices} except computes the culling
  263. * point relative to an ellipsoid that has been shrunk by the minimum height when the minimum height is below
  264. * the ellipsoid. The returned point is expressed in the possibly-shrunk ellipsoid-scaled space and is suitable
  265. * for use with {@link EllipsoidalOccluder#isScaledSpacePointVisiblePossiblyUnderEllipsoid}.
  266. *
  267. * @param {Cartesian3} directionToPoint The direction that the computed point will lie along.
  268. * A reasonable direction to use is the direction from the center of the ellipsoid to
  269. * the center of the bounding sphere computed from the positions. The direction need not
  270. * be normalized.
  271. * @param {Number[]} vertices The vertices from which to compute the horizon culling point. The positions
  272. * must be expressed in a reference frame centered at the ellipsoid and aligned with the
  273. * ellipsoid's axes.
  274. * @param {Number} [stride=3]
  275. * @param {Cartesian3} [center=Cartesian3.ZERO]
  276. * @param {Number} [minimumHeight] The minimum height of all vertices. If this value is undefined, all vertices are assumed to be above the ellipsoid.
  277. * @param {Cartesian3} [result] The instance on which to store the result instead of allocating a new instance.
  278. * @returns {Cartesian3} The computed horizon culling point, expressed in the possibly-shrunk ellipsoid-scaled space.
  279. */
  280. EllipsoidalOccluder.prototype.computeHorizonCullingPointFromVerticesPossiblyUnderEllipsoid = function (
  281. directionToPoint,
  282. vertices,
  283. stride,
  284. center,
  285. minimumHeight,
  286. result
  287. ) {
  288. var possiblyShrunkEllipsoid = getPossiblyShrunkEllipsoid(
  289. this._ellipsoid,
  290. minimumHeight,
  291. scratchEllipsoidShrunk
  292. );
  293. return computeHorizonCullingPointFromVertices(
  294. possiblyShrunkEllipsoid,
  295. directionToPoint,
  296. vertices,
  297. stride,
  298. center,
  299. result
  300. );
  301. };
  302. var subsampleScratch = [];
  303. /**
  304. * Computes a point that can be used for horizon culling of a rectangle. If the point is below
  305. * the horizon, the ellipsoid-conforming rectangle is guaranteed to be below the horizon as well.
  306. * The returned point is expressed in the ellipsoid-scaled space and is suitable for use with
  307. * {@link EllipsoidalOccluder#isScaledSpacePointVisible}.
  308. *
  309. * @param {Rectangle} rectangle The rectangle for which to compute the horizon culling point.
  310. * @param {Ellipsoid} ellipsoid The ellipsoid on which the rectangle is defined. This may be different from
  311. * the ellipsoid used by this instance for occlusion testing.
  312. * @param {Cartesian3} [result] The instance on which to store the result instead of allocating a new instance.
  313. * @returns {Cartesian3} The computed horizon culling point, expressed in the ellipsoid-scaled space.
  314. */
  315. EllipsoidalOccluder.prototype.computeHorizonCullingPointFromRectangle = function (
  316. rectangle,
  317. ellipsoid,
  318. result
  319. ) {
  320. //>>includeStart('debug', pragmas.debug);
  321. Check.Check.typeOf.object("rectangle", rectangle);
  322. //>>includeEnd('debug');
  323. var positions = Cartesian2.Rectangle.subsample(
  324. rectangle,
  325. ellipsoid,
  326. 0.0,
  327. subsampleScratch
  328. );
  329. var bs = Transforms.BoundingSphere.fromPoints(positions);
  330. // If the bounding sphere center is too close to the center of the occluder, it doesn't make
  331. // sense to try to horizon cull it.
  332. if (Cartesian2.Cartesian3.magnitude(bs.center) < 0.1 * ellipsoid.minimumRadius) {
  333. return undefined;
  334. }
  335. return this.computeHorizonCullingPoint(bs.center, positions, result);
  336. };
  337. var scratchEllipsoidShrunkRadii = new Cartesian2.Cartesian3();
  338. function getPossiblyShrunkEllipsoid(ellipsoid, minimumHeight, result) {
  339. if (
  340. when.defined(minimumHeight) &&
  341. minimumHeight < 0.0 &&
  342. ellipsoid.minimumRadius > -minimumHeight
  343. ) {
  344. var ellipsoidShrunkRadii = Cartesian2.Cartesian3.fromElements(
  345. ellipsoid.radii.x + minimumHeight,
  346. ellipsoid.radii.y + minimumHeight,
  347. ellipsoid.radii.z + minimumHeight,
  348. scratchEllipsoidShrunkRadii
  349. );
  350. ellipsoid = Cartesian2.Ellipsoid.fromCartesian3(ellipsoidShrunkRadii, result);
  351. }
  352. return ellipsoid;
  353. }
  354. function computeHorizonCullingPointFromPositions(
  355. ellipsoid,
  356. directionToPoint,
  357. positions,
  358. result
  359. ) {
  360. //>>includeStart('debug', pragmas.debug);
  361. Check.Check.typeOf.object("directionToPoint", directionToPoint);
  362. Check.Check.defined("positions", positions);
  363. //>>includeEnd('debug');
  364. if (!when.defined(result)) {
  365. result = new Cartesian2.Cartesian3();
  366. }
  367. var scaledSpaceDirectionToPoint = computeScaledSpaceDirectionToPoint(
  368. ellipsoid,
  369. directionToPoint
  370. );
  371. var resultMagnitude = 0.0;
  372. for (var i = 0, len = positions.length; i < len; ++i) {
  373. var position = positions[i];
  374. var candidateMagnitude = computeMagnitude(
  375. ellipsoid,
  376. position,
  377. scaledSpaceDirectionToPoint
  378. );
  379. if (candidateMagnitude < 0.0) {
  380. // all points should face the same direction, but this one doesn't, so return undefined
  381. return undefined;
  382. }
  383. resultMagnitude = Math.max(resultMagnitude, candidateMagnitude);
  384. }
  385. return magnitudeToPoint(scaledSpaceDirectionToPoint, resultMagnitude, result);
  386. }
  387. var positionScratch = new Cartesian2.Cartesian3();
  388. function computeHorizonCullingPointFromVertices(
  389. ellipsoid,
  390. directionToPoint,
  391. vertices,
  392. stride,
  393. center,
  394. result
  395. ) {
  396. //>>includeStart('debug', pragmas.debug);
  397. Check.Check.typeOf.object("directionToPoint", directionToPoint);
  398. Check.Check.defined("vertices", vertices);
  399. Check.Check.typeOf.number("stride", stride);
  400. //>>includeEnd('debug');
  401. if (!when.defined(result)) {
  402. result = new Cartesian2.Cartesian3();
  403. }
  404. stride = when.defaultValue(stride, 3);
  405. center = when.defaultValue(center, Cartesian2.Cartesian3.ZERO);
  406. var scaledSpaceDirectionToPoint = computeScaledSpaceDirectionToPoint(
  407. ellipsoid,
  408. directionToPoint
  409. );
  410. var resultMagnitude = 0.0;
  411. for (var i = 0, len = vertices.length; i < len; i += stride) {
  412. positionScratch.x = vertices[i] + center.x;
  413. positionScratch.y = vertices[i + 1] + center.y;
  414. positionScratch.z = vertices[i + 2] + center.z;
  415. var candidateMagnitude = computeMagnitude(
  416. ellipsoid,
  417. positionScratch,
  418. scaledSpaceDirectionToPoint
  419. );
  420. if (candidateMagnitude < 0.0) {
  421. // all points should face the same direction, but this one doesn't, so return undefined
  422. return undefined;
  423. }
  424. resultMagnitude = Math.max(resultMagnitude, candidateMagnitude);
  425. }
  426. return magnitudeToPoint(scaledSpaceDirectionToPoint, resultMagnitude, result);
  427. }
  428. function isScaledSpacePointVisible(
  429. occludeeScaledSpacePosition,
  430. cameraPositionInScaledSpace,
  431. distanceToLimbInScaledSpaceSquared
  432. ) {
  433. // See https://cesium.com/blog/2013/04/25/Horizon-culling/
  434. var cv = cameraPositionInScaledSpace;
  435. var vhMagnitudeSquared = distanceToLimbInScaledSpaceSquared;
  436. var vt = Cartesian2.Cartesian3.subtract(
  437. occludeeScaledSpacePosition,
  438. cv,
  439. scratchCartesian
  440. );
  441. var vtDotVc = -Cartesian2.Cartesian3.dot(vt, cv);
  442. // If vhMagnitudeSquared < 0 then we are below the surface of the ellipsoid and
  443. // in this case, set the culling plane to be on V.
  444. var isOccluded =
  445. vhMagnitudeSquared < 0
  446. ? vtDotVc > 0
  447. : vtDotVc > vhMagnitudeSquared &&
  448. (vtDotVc * vtDotVc) / Cartesian2.Cartesian3.magnitudeSquared(vt) >
  449. vhMagnitudeSquared;
  450. return !isOccluded;
  451. }
  452. var scaledSpaceScratch = new Cartesian2.Cartesian3();
  453. var directionScratch = new Cartesian2.Cartesian3();
  454. function computeMagnitude(ellipsoid, position, scaledSpaceDirectionToPoint) {
  455. var scaledSpacePosition = ellipsoid.transformPositionToScaledSpace(
  456. position,
  457. scaledSpaceScratch
  458. );
  459. var magnitudeSquared = Cartesian2.Cartesian3.magnitudeSquared(scaledSpacePosition);
  460. var magnitude = Math.sqrt(magnitudeSquared);
  461. var direction = Cartesian2.Cartesian3.divideByScalar(
  462. scaledSpacePosition,
  463. magnitude,
  464. directionScratch
  465. );
  466. // For the purpose of this computation, points below the ellipsoid are consider to be on it instead.
  467. magnitudeSquared = Math.max(1.0, magnitudeSquared);
  468. magnitude = Math.max(1.0, magnitude);
  469. var cosAlpha = Cartesian2.Cartesian3.dot(direction, scaledSpaceDirectionToPoint);
  470. var sinAlpha = Cartesian2.Cartesian3.magnitude(
  471. Cartesian2.Cartesian3.cross(direction, scaledSpaceDirectionToPoint, direction)
  472. );
  473. var cosBeta = 1.0 / magnitude;
  474. var sinBeta = Math.sqrt(magnitudeSquared - 1.0) * cosBeta;
  475. return 1.0 / (cosAlpha * cosBeta - sinAlpha * sinBeta);
  476. }
  477. function magnitudeToPoint(
  478. scaledSpaceDirectionToPoint,
  479. resultMagnitude,
  480. result
  481. ) {
  482. // The horizon culling point is undefined if there were no positions from which to compute it,
  483. // the directionToPoint is pointing opposite all of the positions, or if we computed NaN or infinity.
  484. if (
  485. resultMagnitude <= 0.0 ||
  486. resultMagnitude === 1.0 / 0.0 ||
  487. resultMagnitude !== resultMagnitude
  488. ) {
  489. return undefined;
  490. }
  491. return Cartesian2.Cartesian3.multiplyByScalar(
  492. scaledSpaceDirectionToPoint,
  493. resultMagnitude,
  494. result
  495. );
  496. }
  497. var directionToPointScratch = new Cartesian2.Cartesian3();
  498. function computeScaledSpaceDirectionToPoint(ellipsoid, directionToPoint) {
  499. if (Cartesian2.Cartesian3.equals(directionToPoint, Cartesian2.Cartesian3.ZERO)) {
  500. return directionToPoint;
  501. }
  502. ellipsoid.transformPositionToScaledSpace(
  503. directionToPoint,
  504. directionToPointScratch
  505. );
  506. return Cartesian2.Cartesian3.normalize(directionToPointScratch, directionToPointScratch);
  507. }
  508. /**
  509. * This enumerated type is used to determine how the vertices of the terrain mesh are compressed.
  510. *
  511. * @enum {Number}
  512. *
  513. * @private
  514. */
  515. var TerrainQuantization = {
  516. /**
  517. * The vertices are not compressed.
  518. *
  519. * @type {Number}
  520. * @constant
  521. */
  522. NONE: 0,
  523. /**
  524. * The vertices are compressed to 12 bits.
  525. *
  526. * @type {Number}
  527. * @constant
  528. */
  529. BITS12: 1,
  530. };
  531. var TerrainQuantization$1 = Object.freeze(TerrainQuantization);
  532. var cartesian3Scratch = new Cartesian2.Cartesian3();
  533. var cartesian3DimScratch = new Cartesian2.Cartesian3();
  534. var cartesian2Scratch = new Cartesian2.Cartesian2();
  535. var matrix4Scratch = new Transforms.Matrix4();
  536. var matrix4Scratch2 = new Transforms.Matrix4();
  537. var SHIFT_LEFT_12 = Math.pow(2.0, 12.0);
  538. /**
  539. * Data used to quantize and pack the terrain mesh. The position can be unpacked for picking and all attributes
  540. * are unpacked in the vertex shader.
  541. *
  542. * @alias TerrainEncoding
  543. * @constructor
  544. *
  545. * @param {AxisAlignedBoundingBox} axisAlignedBoundingBox The bounds of the tile in the east-north-up coordinates at the tiles center.
  546. * @param {Number} minimumHeight The minimum height.
  547. * @param {Number} maximumHeight The maximum height.
  548. * @param {Matrix4} fromENU The east-north-up to fixed frame matrix at the center of the terrain mesh.
  549. * @param {Boolean} hasVertexNormals If the mesh has vertex normals.
  550. * @param {Boolean} [hasWebMercatorT=false] true if the terrain data includes a Web Mercator texture coordinate; otherwise, false.
  551. *
  552. * @private
  553. */
  554. function TerrainEncoding(
  555. axisAlignedBoundingBox,
  556. minimumHeight,
  557. maximumHeight,
  558. fromENU,
  559. hasVertexNormals,
  560. hasWebMercatorT
  561. ) {
  562. var quantization = TerrainQuantization$1.NONE;
  563. var center;
  564. var toENU;
  565. var matrix;
  566. if (
  567. when.defined(axisAlignedBoundingBox) &&
  568. when.defined(minimumHeight) &&
  569. when.defined(maximumHeight) &&
  570. when.defined(fromENU)
  571. ) {
  572. var minimum = axisAlignedBoundingBox.minimum;
  573. var maximum = axisAlignedBoundingBox.maximum;
  574. var dimensions = Cartesian2.Cartesian3.subtract(
  575. maximum,
  576. minimum,
  577. cartesian3DimScratch
  578. );
  579. var hDim = maximumHeight - minimumHeight;
  580. var maxDim = Math.max(Cartesian2.Cartesian3.maximumComponent(dimensions), hDim);
  581. if (maxDim < SHIFT_LEFT_12 - 1.0) {
  582. quantization = TerrainQuantization$1.BITS12;
  583. } else {
  584. quantization = TerrainQuantization$1.NONE;
  585. }
  586. center = axisAlignedBoundingBox.center;
  587. toENU = Transforms.Matrix4.inverseTransformation(fromENU, new Transforms.Matrix4());
  588. var translation = Cartesian2.Cartesian3.negate(minimum, cartesian3Scratch);
  589. Transforms.Matrix4.multiply(
  590. Transforms.Matrix4.fromTranslation(translation, matrix4Scratch),
  591. toENU,
  592. toENU
  593. );
  594. var scale = cartesian3Scratch;
  595. scale.x = 1.0 / dimensions.x;
  596. scale.y = 1.0 / dimensions.y;
  597. scale.z = 1.0 / dimensions.z;
  598. Transforms.Matrix4.multiply(Transforms.Matrix4.fromScale(scale, matrix4Scratch), toENU, toENU);
  599. matrix = Transforms.Matrix4.clone(fromENU);
  600. Transforms.Matrix4.setTranslation(matrix, Cartesian2.Cartesian3.ZERO, matrix);
  601. fromENU = Transforms.Matrix4.clone(fromENU, new Transforms.Matrix4());
  602. var translationMatrix = Transforms.Matrix4.fromTranslation(minimum, matrix4Scratch);
  603. var scaleMatrix = Transforms.Matrix4.fromScale(dimensions, matrix4Scratch2);
  604. var st = Transforms.Matrix4.multiply(translationMatrix, scaleMatrix, matrix4Scratch);
  605. Transforms.Matrix4.multiply(fromENU, st, fromENU);
  606. Transforms.Matrix4.multiply(matrix, st, matrix);
  607. }
  608. /**
  609. * How the vertices of the mesh were compressed.
  610. * @type {TerrainQuantization}
  611. */
  612. this.quantization = quantization;
  613. /**
  614. * The minimum height of the tile including the skirts.
  615. * @type {Number}
  616. */
  617. this.minimumHeight = minimumHeight;
  618. /**
  619. * The maximum height of the tile.
  620. * @type {Number}
  621. */
  622. this.maximumHeight = maximumHeight;
  623. /**
  624. * The center of the tile.
  625. * @type {Cartesian3}
  626. */
  627. this.center = center;
  628. /**
  629. * A matrix that takes a vertex from the tile, transforms it to east-north-up at the center and scales
  630. * it so each component is in the [0, 1] range.
  631. * @type {Matrix4}
  632. */
  633. this.toScaledENU = toENU;
  634. /**
  635. * A matrix that restores a vertex transformed with toScaledENU back to the earth fixed reference frame
  636. * @type {Matrix4}
  637. */
  638. this.fromScaledENU = fromENU;
  639. /**
  640. * The matrix used to decompress the terrain vertices in the shader for RTE rendering.
  641. * @type {Matrix4}
  642. */
  643. this.matrix = matrix;
  644. /**
  645. * The terrain mesh contains normals.
  646. * @type {Boolean}
  647. */
  648. this.hasVertexNormals = hasVertexNormals;
  649. /**
  650. * The terrain mesh contains a vertical texture coordinate following the Web Mercator projection.
  651. * @type {Boolean}
  652. */
  653. this.hasWebMercatorT = when.defaultValue(hasWebMercatorT, false);
  654. }
  655. TerrainEncoding.prototype.encode = function (
  656. vertexBuffer,
  657. bufferIndex,
  658. position,
  659. uv,
  660. height,
  661. normalToPack,
  662. webMercatorT
  663. ) {
  664. var u = uv.x;
  665. var v = uv.y;
  666. if (this.quantization === TerrainQuantization$1.BITS12) {
  667. position = Transforms.Matrix4.multiplyByPoint(
  668. this.toScaledENU,
  669. position,
  670. cartesian3Scratch
  671. );
  672. position.x = _Math.CesiumMath.clamp(position.x, 0.0, 1.0);
  673. position.y = _Math.CesiumMath.clamp(position.y, 0.0, 1.0);
  674. position.z = _Math.CesiumMath.clamp(position.z, 0.0, 1.0);
  675. var hDim = this.maximumHeight - this.minimumHeight;
  676. var h = _Math.CesiumMath.clamp((height - this.minimumHeight) / hDim, 0.0, 1.0);
  677. Cartesian2.Cartesian2.fromElements(position.x, position.y, cartesian2Scratch);
  678. var compressed0 = AttributeCompression.AttributeCompression.compressTextureCoordinates(
  679. cartesian2Scratch
  680. );
  681. Cartesian2.Cartesian2.fromElements(position.z, h, cartesian2Scratch);
  682. var compressed1 = AttributeCompression.AttributeCompression.compressTextureCoordinates(
  683. cartesian2Scratch
  684. );
  685. Cartesian2.Cartesian2.fromElements(u, v, cartesian2Scratch);
  686. var compressed2 = AttributeCompression.AttributeCompression.compressTextureCoordinates(
  687. cartesian2Scratch
  688. );
  689. vertexBuffer[bufferIndex++] = compressed0;
  690. vertexBuffer[bufferIndex++] = compressed1;
  691. vertexBuffer[bufferIndex++] = compressed2;
  692. if (this.hasWebMercatorT) {
  693. Cartesian2.Cartesian2.fromElements(webMercatorT, 0.0, cartesian2Scratch);
  694. var compressed3 = AttributeCompression.AttributeCompression.compressTextureCoordinates(
  695. cartesian2Scratch
  696. );
  697. vertexBuffer[bufferIndex++] = compressed3;
  698. }
  699. } else {
  700. Cartesian2.Cartesian3.subtract(position, this.center, cartesian3Scratch);
  701. vertexBuffer[bufferIndex++] = cartesian3Scratch.x;
  702. vertexBuffer[bufferIndex++] = cartesian3Scratch.y;
  703. vertexBuffer[bufferIndex++] = cartesian3Scratch.z;
  704. vertexBuffer[bufferIndex++] = height;
  705. vertexBuffer[bufferIndex++] = u;
  706. vertexBuffer[bufferIndex++] = v;
  707. if (this.hasWebMercatorT) {
  708. vertexBuffer[bufferIndex++] = webMercatorT;
  709. }
  710. }
  711. if (this.hasVertexNormals) {
  712. vertexBuffer[bufferIndex++] = AttributeCompression.AttributeCompression.octPackFloat(
  713. normalToPack
  714. );
  715. }
  716. return bufferIndex;
  717. };
  718. TerrainEncoding.prototype.decodePosition = function (buffer, index, result) {
  719. if (!when.defined(result)) {
  720. result = new Cartesian2.Cartesian3();
  721. }
  722. index *= this.getStride();
  723. if (this.quantization === TerrainQuantization$1.BITS12) {
  724. var xy = AttributeCompression.AttributeCompression.decompressTextureCoordinates(
  725. buffer[index],
  726. cartesian2Scratch
  727. );
  728. result.x = xy.x;
  729. result.y = xy.y;
  730. var zh = AttributeCompression.AttributeCompression.decompressTextureCoordinates(
  731. buffer[index + 1],
  732. cartesian2Scratch
  733. );
  734. result.z = zh.x;
  735. return Transforms.Matrix4.multiplyByPoint(this.fromScaledENU, result, result);
  736. }
  737. result.x = buffer[index];
  738. result.y = buffer[index + 1];
  739. result.z = buffer[index + 2];
  740. return Cartesian2.Cartesian3.add(result, this.center, result);
  741. };
  742. TerrainEncoding.prototype.decodeTextureCoordinates = function (
  743. buffer,
  744. index,
  745. result
  746. ) {
  747. if (!when.defined(result)) {
  748. result = new Cartesian2.Cartesian2();
  749. }
  750. index *= this.getStride();
  751. if (this.quantization === TerrainQuantization$1.BITS12) {
  752. return AttributeCompression.AttributeCompression.decompressTextureCoordinates(
  753. buffer[index + 2],
  754. result
  755. );
  756. }
  757. return Cartesian2.Cartesian2.fromElements(buffer[index + 4], buffer[index + 5], result);
  758. };
  759. TerrainEncoding.prototype.decodeHeight = function (buffer, index) {
  760. index *= this.getStride();
  761. if (this.quantization === TerrainQuantization$1.BITS12) {
  762. var zh = AttributeCompression.AttributeCompression.decompressTextureCoordinates(
  763. buffer[index + 1],
  764. cartesian2Scratch
  765. );
  766. return (
  767. zh.y * (this.maximumHeight - this.minimumHeight) + this.minimumHeight
  768. );
  769. }
  770. return buffer[index + 3];
  771. };
  772. TerrainEncoding.prototype.decodeWebMercatorT = function (buffer, index) {
  773. index *= this.getStride();
  774. if (this.quantization === TerrainQuantization$1.BITS12) {
  775. return AttributeCompression.AttributeCompression.decompressTextureCoordinates(
  776. buffer[index + 3],
  777. cartesian2Scratch
  778. ).x;
  779. }
  780. return buffer[index + 6];
  781. };
  782. TerrainEncoding.prototype.getOctEncodedNormal = function (
  783. buffer,
  784. index,
  785. result
  786. ) {
  787. var stride = this.getStride();
  788. index = (index + 1) * stride - 1;
  789. var temp = buffer[index] / 256.0;
  790. var x = Math.floor(temp);
  791. var y = (temp - x) * 256.0;
  792. return Cartesian2.Cartesian2.fromElements(x, y, result);
  793. };
  794. TerrainEncoding.prototype.getStride = function () {
  795. var vertexStride;
  796. switch (this.quantization) {
  797. case TerrainQuantization$1.BITS12:
  798. vertexStride = 3;
  799. break;
  800. default:
  801. vertexStride = 6;
  802. }
  803. if (this.hasWebMercatorT) {
  804. ++vertexStride;
  805. }
  806. if (this.hasVertexNormals) {
  807. ++vertexStride;
  808. }
  809. return vertexStride;
  810. };
  811. var attributesNone = {
  812. position3DAndHeight: 0,
  813. textureCoordAndEncodedNormals: 1,
  814. };
  815. var attributes = {
  816. compressed0: 0,
  817. compressed1: 1,
  818. };
  819. TerrainEncoding.prototype.getAttributes = function (buffer) {
  820. var datatype = ComponentDatatype.ComponentDatatype.FLOAT;
  821. var sizeInBytes = ComponentDatatype.ComponentDatatype.getSizeInBytes(datatype);
  822. var stride;
  823. if (this.quantization === TerrainQuantization$1.NONE) {
  824. var position3DAndHeightLength = 4;
  825. var numTexCoordComponents = 2;
  826. if (this.hasWebMercatorT) {
  827. ++numTexCoordComponents;
  828. }
  829. if (this.hasVertexNormals) {
  830. ++numTexCoordComponents;
  831. }
  832. stride = (position3DAndHeightLength + numTexCoordComponents) * sizeInBytes;
  833. return [
  834. {
  835. index: attributesNone.position3DAndHeight,
  836. vertexBuffer: buffer,
  837. componentDatatype: datatype,
  838. componentsPerAttribute: position3DAndHeightLength,
  839. offsetInBytes: 0,
  840. strideInBytes: stride,
  841. },
  842. {
  843. index: attributesNone.textureCoordAndEncodedNormals,
  844. vertexBuffer: buffer,
  845. componentDatatype: datatype,
  846. componentsPerAttribute: numTexCoordComponents,
  847. offsetInBytes: position3DAndHeightLength * sizeInBytes,
  848. strideInBytes: stride,
  849. },
  850. ];
  851. }
  852. var numCompressed0 = 3;
  853. var numCompressed1 = 0;
  854. if (this.hasWebMercatorT || this.hasVertexNormals) {
  855. ++numCompressed0;
  856. }
  857. if (this.hasWebMercatorT && this.hasVertexNormals) {
  858. ++numCompressed1;
  859. stride = (numCompressed0 + numCompressed1) * sizeInBytes;
  860. return [
  861. {
  862. index: attributes.compressed0,
  863. vertexBuffer: buffer,
  864. componentDatatype: datatype,
  865. componentsPerAttribute: numCompressed0,
  866. offsetInBytes: 0,
  867. strideInBytes: stride,
  868. },
  869. {
  870. index: attributes.compressed1,
  871. vertexBuffer: buffer,
  872. componentDatatype: datatype,
  873. componentsPerAttribute: numCompressed1,
  874. offsetInBytes: numCompressed0 * sizeInBytes,
  875. strideInBytes: stride,
  876. },
  877. ];
  878. }
  879. return [
  880. {
  881. index: attributes.compressed0,
  882. vertexBuffer: buffer,
  883. componentDatatype: datatype,
  884. componentsPerAttribute: numCompressed0,
  885. },
  886. ];
  887. };
  888. TerrainEncoding.prototype.getAttributeLocations = function () {
  889. if (this.quantization === TerrainQuantization$1.NONE) {
  890. return attributesNone;
  891. }
  892. return attributes;
  893. };
  894. TerrainEncoding.clone = function (encoding, result) {
  895. if (!when.defined(result)) {
  896. result = new TerrainEncoding();
  897. }
  898. result.quantization = encoding.quantization;
  899. result.minimumHeight = encoding.minimumHeight;
  900. result.maximumHeight = encoding.maximumHeight;
  901. result.center = Cartesian2.Cartesian3.clone(encoding.center);
  902. result.toScaledENU = Transforms.Matrix4.clone(encoding.toScaledENU);
  903. result.fromScaledENU = Transforms.Matrix4.clone(encoding.fromScaledENU);
  904. result.matrix = Transforms.Matrix4.clone(encoding.matrix);
  905. result.hasVertexNormals = encoding.hasVertexNormals;
  906. result.hasWebMercatorT = encoding.hasWebMercatorT;
  907. return result;
  908. };
  909. exports.EllipsoidalOccluder = EllipsoidalOccluder;
  910. exports.TerrainEncoding = TerrainEncoding;
  911. });