GlobeSurfaceTileProvider.js 86 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653
  1. import BoundingSphere from "../Core/BoundingSphere.js";
  2. import BoxOutlineGeometry from "../Core/BoxOutlineGeometry.js";
  3. import Cartesian2 from "../Core/Cartesian2.js";
  4. import Cartesian3 from "../Core/Cartesian3.js";
  5. import Cartesian4 from "../Core/Cartesian4.js";
  6. import Cartographic from "../Core/Cartographic.js";
  7. import clone from "../Core/clone.js";
  8. import Color from "../Core/Color.js";
  9. import ColorGeometryInstanceAttribute from "../Core/ColorGeometryInstanceAttribute.js";
  10. import combine from "../Core/combine.js";
  11. import defaultValue from "../Core/defaultValue.js";
  12. import defined from "../Core/defined.js";
  13. import destroyObject from "../Core/destroyObject.js";
  14. import DeveloperError from "../Core/DeveloperError.js";
  15. import Event from "../Core/Event.js";
  16. import GeometryInstance from "../Core/GeometryInstance.js";
  17. import GeometryPipeline from "../Core/GeometryPipeline.js";
  18. import IndexDatatype from "../Core/IndexDatatype.js";
  19. import Intersect from "../Core/Intersect.js";
  20. import CesiumMath from "../Core/Math.js";
  21. import Matrix4 from "../Core/Matrix4.js";
  22. import NearFarScalar from "../Core/NearFarScalar.js";
  23. import OrientedBoundingBox from "../Core/OrientedBoundingBox.js";
  24. import OrthographicFrustum from "../Core/OrthographicFrustum.js";
  25. import PrimitiveType from "../Core/PrimitiveType.js";
  26. import Rectangle from "../Core/Rectangle.js";
  27. import SphereOutlineGeometry from "../Core/SphereOutlineGeometry.js";
  28. import TerrainQuantization from "../Core/TerrainQuantization.js";
  29. import Visibility from "../Core/Visibility.js";
  30. import WebMercatorProjection from "../Core/WebMercatorProjection.js";
  31. import Buffer from "../Renderer/Buffer.js";
  32. import BufferUsage from "../Renderer/BufferUsage.js";
  33. import ContextLimits from "../Renderer/ContextLimits.js";
  34. import DrawCommand from "../Renderer/DrawCommand.js";
  35. import Pass from "../Renderer/Pass.js";
  36. import RenderState from "../Renderer/RenderState.js";
  37. import VertexArray from "../Renderer/VertexArray.js";
  38. import BlendingState from "./BlendingState.js";
  39. import ClippingPlaneCollection from "./ClippingPlaneCollection.js";
  40. import DepthFunction from "./DepthFunction.js";
  41. import GlobeSurfaceTile from "./GlobeSurfaceTile.js";
  42. import ImageryLayer from "./ImageryLayer.js";
  43. import ImageryState from "./ImageryState.js";
  44. import PerInstanceColorAppearance from "./PerInstanceColorAppearance.js";
  45. import Primitive from "./Primitive.js";
  46. import QuadtreeTileLoadState from "./QuadtreeTileLoadState.js";
  47. import SceneMode from "./SceneMode.js";
  48. import ShadowMode from "./ShadowMode.js";
  49. import TerrainFillMesh from "./TerrainFillMesh.js";
  50. import TerrainState from "./TerrainState.js";
  51. import TileBoundingRegion from "./TileBoundingRegion.js";
  52. import TileSelectionResult from "./TileSelectionResult.js";
  53. /**
  54. * Provides quadtree tiles representing the surface of the globe. This type is intended to be used
  55. * with {@link QuadtreePrimitive}.
  56. *
  57. * @alias GlobeSurfaceTileProvider
  58. * @constructor
  59. *
  60. * @param {TerrainProvider} options.terrainProvider The terrain provider that describes the surface geometry.
  61. * @param {ImageryLayerCollection} option.imageryLayers The collection of imagery layers describing the shading of the surface.
  62. * @param {GlobeSurfaceShaderSet} options.surfaceShaderSet The set of shaders used to render the surface.
  63. *
  64. * @private
  65. */
  66. function GlobeSurfaceTileProvider(options) {
  67. //>>includeStart('debug', pragmas.debug);
  68. if (!defined(options)) {
  69. throw new DeveloperError("options is required.");
  70. }
  71. if (!defined(options.terrainProvider)) {
  72. throw new DeveloperError("options.terrainProvider is required.");
  73. } else if (!defined(options.imageryLayers)) {
  74. throw new DeveloperError("options.imageryLayers is required.");
  75. } else if (!defined(options.surfaceShaderSet)) {
  76. throw new DeveloperError("options.surfaceShaderSet is required.");
  77. }
  78. //>>includeEnd('debug');
  79. this.lightingFadeOutDistance = 6500000.0;
  80. this.lightingFadeInDistance = 9000000.0;
  81. this.hasWaterMask = false;
  82. this.oceanNormalMap = undefined;
  83. this.zoomedOutOceanSpecularIntensity = 0.5;
  84. this.enableLighting = false;
  85. this.dynamicAtmosphereLighting = false;
  86. this.dynamicAtmosphereLightingFromSun = false;
  87. this.showGroundAtmosphere = false;
  88. this.shadows = ShadowMode.RECEIVE_ONLY;
  89. /**
  90. * The color to use to highlight terrain fill tiles. If undefined, fill tiles are not
  91. * highlighted at all. The alpha value is used to alpha blend with the tile's
  92. * actual color. Because terrain fill tiles do not represent the actual terrain surface,
  93. * it may be useful in some applications to indicate visually that they are not to be trusted.
  94. * @type {Color}
  95. * @default undefined
  96. */
  97. this.fillHighlightColor = undefined;
  98. this.hueShift = 0.0;
  99. this.saturationShift = 0.0;
  100. this.brightnessShift = 0.0;
  101. this.showSkirts = true;
  102. this.backFaceCulling = true;
  103. this.undergroundColor = undefined;
  104. this.undergroundColorAlphaByDistance = undefined;
  105. this.materialUniformMap = undefined;
  106. this._materialUniformMap = undefined;
  107. this._quadtree = undefined;
  108. this._terrainProvider = options.terrainProvider;
  109. this._imageryLayers = options.imageryLayers;
  110. this._surfaceShaderSet = options.surfaceShaderSet;
  111. this._renderState = undefined;
  112. this._blendRenderState = undefined;
  113. this._disableCullingRenderState = undefined;
  114. this._disableCullingBlendRenderState = undefined;
  115. this._errorEvent = new Event();
  116. this._imageryLayers.layerAdded.addEventListener(
  117. GlobeSurfaceTileProvider.prototype._onLayerAdded,
  118. this
  119. );
  120. this._imageryLayers.layerRemoved.addEventListener(
  121. GlobeSurfaceTileProvider.prototype._onLayerRemoved,
  122. this
  123. );
  124. this._imageryLayers.layerMoved.addEventListener(
  125. GlobeSurfaceTileProvider.prototype._onLayerMoved,
  126. this
  127. );
  128. this._imageryLayers.layerShownOrHidden.addEventListener(
  129. GlobeSurfaceTileProvider.prototype._onLayerShownOrHidden,
  130. this
  131. );
  132. this._imageryLayersUpdatedEvent = new Event();
  133. this._layerOrderChanged = false;
  134. this._tilesToRenderByTextureCount = [];
  135. this._drawCommands = [];
  136. this._uniformMaps = [];
  137. this._usedDrawCommands = 0;
  138. this._vertexArraysToDestroy = [];
  139. this._debug = {
  140. wireframe: false,
  141. boundingSphereTile: undefined,
  142. };
  143. this._baseColor = undefined;
  144. this._firstPassInitialColor = undefined;
  145. this.baseColor = new Color(0.0, 0.0, 0.5, 1.0);
  146. /**
  147. * A property specifying a {@link ClippingPlaneCollection} used to selectively disable rendering on the outside of each plane.
  148. * @type {ClippingPlaneCollection}
  149. * @private
  150. */
  151. this._clippingPlanes = undefined;
  152. /**
  153. * A property specifying a {@link Rectangle} used to selectively limit terrain and imagery rendering.
  154. * @type {Rectangle}
  155. */
  156. this.cartographicLimitRectangle = Rectangle.clone(Rectangle.MAX_VALUE);
  157. this._hasLoadedTilesThisFrame = false;
  158. this._hasFillTilesThisFrame = false;
  159. }
  160. Object.defineProperties(GlobeSurfaceTileProvider.prototype, {
  161. /**
  162. * Gets or sets the color of the globe when no imagery is available.
  163. * @memberof GlobeSurfaceTileProvider.prototype
  164. * @type {Color}
  165. */
  166. baseColor: {
  167. get: function () {
  168. return this._baseColor;
  169. },
  170. set: function (value) {
  171. //>>includeStart('debug', pragmas.debug);
  172. if (!defined(value)) {
  173. throw new DeveloperError("value is required.");
  174. }
  175. //>>includeEnd('debug');
  176. this._baseColor = value;
  177. this._firstPassInitialColor = Cartesian4.fromColor(
  178. value,
  179. this._firstPassInitialColor
  180. );
  181. },
  182. },
  183. /**
  184. * Gets or sets the {@link QuadtreePrimitive} for which this provider is
  185. * providing tiles. This property may be undefined if the provider is not yet associated
  186. * with a {@link QuadtreePrimitive}.
  187. * @memberof GlobeSurfaceTileProvider.prototype
  188. * @type {QuadtreePrimitive}
  189. */
  190. quadtree: {
  191. get: function () {
  192. return this._quadtree;
  193. },
  194. set: function (value) {
  195. //>>includeStart('debug', pragmas.debug);
  196. if (!defined(value)) {
  197. throw new DeveloperError("value is required.");
  198. }
  199. //>>includeEnd('debug');
  200. this._quadtree = value;
  201. },
  202. },
  203. /**
  204. * Gets a value indicating whether or not the provider is ready for use.
  205. * @memberof GlobeSurfaceTileProvider.prototype
  206. * @type {Boolean}
  207. */
  208. ready: {
  209. get: function () {
  210. return (
  211. this._terrainProvider.ready &&
  212. (this._imageryLayers.length === 0 ||
  213. this._imageryLayers.get(0).imageryProvider.ready)
  214. );
  215. },
  216. },
  217. /**
  218. * Gets the tiling scheme used by the provider. This property should
  219. * not be accessed before {@link GlobeSurfaceTileProvider#ready} returns true.
  220. * @memberof GlobeSurfaceTileProvider.prototype
  221. * @type {TilingScheme}
  222. */
  223. tilingScheme: {
  224. get: function () {
  225. return this._terrainProvider.tilingScheme;
  226. },
  227. },
  228. /**
  229. * Gets an event that is raised when the geometry provider encounters an asynchronous error. By subscribing
  230. * to the event, you will be notified of the error and can potentially recover from it. Event listeners
  231. * are passed an instance of {@link TileProviderError}.
  232. * @memberof GlobeSurfaceTileProvider.prototype
  233. * @type {Event}
  234. */
  235. errorEvent: {
  236. get: function () {
  237. return this._errorEvent;
  238. },
  239. },
  240. /**
  241. * Gets an event that is raised when an imagery layer is added, shown, hidden, moved, or removed.
  242. * @memberof GlobeSurfaceTileProvider.prototype
  243. * @type {Event}
  244. */
  245. imageryLayersUpdatedEvent: {
  246. get: function () {
  247. return this._imageryLayersUpdatedEvent;
  248. },
  249. },
  250. /**
  251. * Gets or sets the terrain provider that describes the surface geometry.
  252. * @memberof GlobeSurfaceTileProvider.prototype
  253. * @type {TerrainProvider}
  254. */
  255. terrainProvider: {
  256. get: function () {
  257. return this._terrainProvider;
  258. },
  259. set: function (terrainProvider) {
  260. if (this._terrainProvider === terrainProvider) {
  261. return;
  262. }
  263. //>>includeStart('debug', pragmas.debug);
  264. if (!defined(terrainProvider)) {
  265. throw new DeveloperError("terrainProvider is required.");
  266. }
  267. //>>includeEnd('debug');
  268. this._terrainProvider = terrainProvider;
  269. if (defined(this._quadtree)) {
  270. this._quadtree.invalidateAllTiles();
  271. }
  272. },
  273. },
  274. /**
  275. * The {@link ClippingPlaneCollection} used to selectively disable rendering the tileset.
  276. *
  277. * @type {ClippingPlaneCollection}
  278. *
  279. * @private
  280. */
  281. clippingPlanes: {
  282. get: function () {
  283. return this._clippingPlanes;
  284. },
  285. set: function (value) {
  286. ClippingPlaneCollection.setOwner(value, this, "_clippingPlanes");
  287. },
  288. },
  289. });
  290. function sortTileImageryByLayerIndex(a, b) {
  291. var aImagery = a.loadingImagery;
  292. if (!defined(aImagery)) {
  293. aImagery = a.readyImagery;
  294. }
  295. var bImagery = b.loadingImagery;
  296. if (!defined(bImagery)) {
  297. bImagery = b.readyImagery;
  298. }
  299. return aImagery.imageryLayer._layerIndex - bImagery.imageryLayer._layerIndex;
  300. }
  301. /**
  302. * Make updates to the tile provider that are not involved in rendering. Called before the render update cycle.
  303. */
  304. GlobeSurfaceTileProvider.prototype.update = function (frameState) {
  305. // update collection: imagery indices, base layers, raise layer show/hide event
  306. this._imageryLayers._update();
  307. };
  308. function updateCredits(surface, frameState) {
  309. var creditDisplay = frameState.creditDisplay;
  310. if (
  311. surface._terrainProvider.ready &&
  312. defined(surface._terrainProvider.credit)
  313. ) {
  314. creditDisplay.addCredit(surface._terrainProvider.credit);
  315. }
  316. var imageryLayers = surface._imageryLayers;
  317. for (var i = 0, len = imageryLayers.length; i < len; ++i) {
  318. var imageryProvider = imageryLayers.get(i).imageryProvider;
  319. if (imageryProvider.ready && defined(imageryProvider.credit)) {
  320. creditDisplay.addCredit(imageryProvider.credit);
  321. }
  322. }
  323. }
  324. /**
  325. * Called at the beginning of each render frame, before {@link QuadtreeTileProvider#showTileThisFrame}
  326. * @param {FrameState} frameState The frame state.
  327. */
  328. GlobeSurfaceTileProvider.prototype.initialize = function (frameState) {
  329. // update each layer for texture reprojection.
  330. this._imageryLayers.queueReprojectionCommands(frameState);
  331. if (this._layerOrderChanged) {
  332. this._layerOrderChanged = false;
  333. // Sort the TileImagery instances in each tile by the layer index.
  334. this._quadtree.forEachLoadedTile(function (tile) {
  335. tile.data.imagery.sort(sortTileImageryByLayerIndex);
  336. });
  337. }
  338. // Add credits for terrain and imagery providers.
  339. updateCredits(this, frameState);
  340. var vertexArraysToDestroy = this._vertexArraysToDestroy;
  341. var length = vertexArraysToDestroy.length;
  342. for (var j = 0; j < length; ++j) {
  343. GlobeSurfaceTile._freeVertexArray(vertexArraysToDestroy[j]);
  344. }
  345. vertexArraysToDestroy.length = 0;
  346. };
  347. /**
  348. * Called at the beginning of the update cycle for each render frame, before {@link QuadtreeTileProvider#showTileThisFrame}
  349. * or any other functions.
  350. *
  351. * @param {FrameState} frameState The frame state.
  352. */
  353. GlobeSurfaceTileProvider.prototype.beginUpdate = function (frameState) {
  354. var tilesToRenderByTextureCount = this._tilesToRenderByTextureCount;
  355. for (var i = 0, len = tilesToRenderByTextureCount.length; i < len; ++i) {
  356. var tiles = tilesToRenderByTextureCount[i];
  357. if (defined(tiles)) {
  358. tiles.length = 0;
  359. }
  360. }
  361. // update clipping planes
  362. var clippingPlanes = this._clippingPlanes;
  363. if (defined(clippingPlanes) && clippingPlanes.enabled) {
  364. clippingPlanes.update(frameState);
  365. }
  366. this._usedDrawCommands = 0;
  367. this._hasLoadedTilesThisFrame = false;
  368. this._hasFillTilesThisFrame = false;
  369. };
  370. /**
  371. * Called at the end of the update cycle for each render frame, after {@link QuadtreeTileProvider#showTileThisFrame}
  372. * and any other functions.
  373. *
  374. * @param {FrameState} frameState The frame state.
  375. */
  376. GlobeSurfaceTileProvider.prototype.endUpdate = function (frameState) {
  377. if (!defined(this._renderState)) {
  378. this._renderState = RenderState.fromCache({
  379. // Write color and depth
  380. cull: {
  381. enabled: true,
  382. },
  383. depthTest: {
  384. enabled: true,
  385. func: DepthFunction.LESS,
  386. },
  387. });
  388. this._blendRenderState = RenderState.fromCache({
  389. // Write color and depth
  390. cull: {
  391. enabled: true,
  392. },
  393. depthTest: {
  394. enabled: true,
  395. func: DepthFunction.LESS_OR_EQUAL,
  396. },
  397. blending: BlendingState.ALPHA_BLEND,
  398. });
  399. var rs = clone(this._renderState, true);
  400. rs.cull.enabled = false;
  401. this._disableCullingRenderState = RenderState.fromCache(rs);
  402. rs = clone(this._blendRenderState, true);
  403. rs.cull.enabled = false;
  404. this._disableCullingBlendRenderState = RenderState.fromCache(rs);
  405. }
  406. // If this frame has a mix of loaded and fill tiles, we need to propagate
  407. // loaded heights to the fill tiles.
  408. if (this._hasFillTilesThisFrame && this._hasLoadedTilesThisFrame) {
  409. TerrainFillMesh.updateFillTiles(
  410. this,
  411. this._quadtree._tilesToRender,
  412. frameState,
  413. this._vertexArraysToDestroy
  414. );
  415. }
  416. // Add the tile render commands to the command list, sorted by texture count.
  417. var tilesToRenderByTextureCount = this._tilesToRenderByTextureCount;
  418. for (
  419. var textureCountIndex = 0,
  420. textureCountLength = tilesToRenderByTextureCount.length;
  421. textureCountIndex < textureCountLength;
  422. ++textureCountIndex
  423. ) {
  424. var tilesToRender = tilesToRenderByTextureCount[textureCountIndex];
  425. if (!defined(tilesToRender)) {
  426. continue;
  427. }
  428. for (
  429. var tileIndex = 0, tileLength = tilesToRender.length;
  430. tileIndex < tileLength;
  431. ++tileIndex
  432. ) {
  433. var tile = tilesToRender[tileIndex];
  434. var tileBoundingRegion = tile.data.tileBoundingRegion;
  435. addDrawCommandsForTile(this, tile, frameState);
  436. frameState.minimumTerrainHeight = Math.min(
  437. frameState.minimumTerrainHeight,
  438. tileBoundingRegion.minimumHeight
  439. );
  440. }
  441. }
  442. };
  443. function pushCommand(command, frameState) {
  444. var globeTranslucencyState = frameState.globeTranslucencyState;
  445. if (globeTranslucencyState.translucent) {
  446. var isBlendCommand = command.renderState.blending.enabled;
  447. globeTranslucencyState.pushDerivedCommands(
  448. command,
  449. isBlendCommand,
  450. frameState
  451. );
  452. } else {
  453. frameState.commandList.push(command);
  454. }
  455. }
  456. /**
  457. * Adds draw commands for tiles rendered in the previous frame for a pick pass.
  458. *
  459. * @param {FrameState} frameState The frame state.
  460. */
  461. GlobeSurfaceTileProvider.prototype.updateForPick = function (frameState) {
  462. // Add the tile pick commands from the tiles drawn last frame.
  463. var drawCommands = this._drawCommands;
  464. for (var i = 0, length = this._usedDrawCommands; i < length; ++i) {
  465. pushCommand(drawCommands[i], frameState);
  466. }
  467. };
  468. /**
  469. * Cancels any imagery re-projections in the queue.
  470. */
  471. GlobeSurfaceTileProvider.prototype.cancelReprojections = function () {
  472. this._imageryLayers.cancelReprojections();
  473. };
  474. /**
  475. * Gets the maximum geometric error allowed in a tile at a given level, in meters. This function should not be
  476. * called before {@link GlobeSurfaceTileProvider#ready} returns true.
  477. *
  478. * @param {Number} level The tile level for which to get the maximum geometric error.
  479. * @returns {Number} The maximum geometric error in meters.
  480. */
  481. GlobeSurfaceTileProvider.prototype.getLevelMaximumGeometricError = function (
  482. level
  483. ) {
  484. return this._terrainProvider.getLevelMaximumGeometricError(level);
  485. };
  486. /**
  487. * Loads, or continues loading, a given tile. This function will continue to be called
  488. * until {@link QuadtreeTile#state} is no longer {@link QuadtreeTileLoadState#LOADING}. This function should
  489. * not be called before {@link GlobeSurfaceTileProvider#ready} returns true.
  490. *
  491. * @param {FrameState} frameState The frame state.
  492. * @param {QuadtreeTile} tile The tile to load.
  493. *
  494. * @exception {DeveloperError} <code>loadTile</code> must not be called before the tile provider is ready.
  495. */
  496. GlobeSurfaceTileProvider.prototype.loadTile = function (frameState, tile) {
  497. // We don't want to load imagery until we're certain that the terrain tiles are actually visible.
  498. // So if our bounding volume isn't accurate because it came from another tile, load terrain only
  499. // initially. If we load some terrain and suddenly have a more accurate bounding volume and the
  500. // tile is _still_ visible, give the tile a chance to load imagery immediately rather than
  501. // waiting for next frame.
  502. var surfaceTile = tile.data;
  503. var terrainOnly = true;
  504. var terrainStateBefore;
  505. if (defined(surfaceTile)) {
  506. terrainOnly =
  507. surfaceTile.boundingVolumeSourceTile !== tile ||
  508. tile._lastSelectionResult === TileSelectionResult.CULLED_BUT_NEEDED;
  509. terrainStateBefore = surfaceTile.terrainState;
  510. }
  511. GlobeSurfaceTile.processStateMachine(
  512. tile,
  513. frameState,
  514. this.terrainProvider,
  515. this._imageryLayers,
  516. this._vertexArraysToDestroy,
  517. terrainOnly
  518. );
  519. surfaceTile = tile.data;
  520. if (terrainOnly && terrainStateBefore !== tile.data.terrainState) {
  521. // Terrain state changed. If:
  522. // a) The tile is visible, and
  523. // b) The bounding volume is accurate (updated as a side effect of computing visibility)
  524. // Then we'll load imagery, too.
  525. if (
  526. this.computeTileVisibility(tile, frameState, this.quadtree.occluders) !==
  527. Visibility.NONE &&
  528. surfaceTile.boundingVolumeSourceTile === tile
  529. ) {
  530. terrainOnly = false;
  531. GlobeSurfaceTile.processStateMachine(
  532. tile,
  533. frameState,
  534. this.terrainProvider,
  535. this._imageryLayers,
  536. this._vertexArraysToDestroy,
  537. terrainOnly
  538. );
  539. }
  540. }
  541. };
  542. var boundingSphereScratch = new BoundingSphere();
  543. var rectangleIntersectionScratch = new Rectangle();
  544. var splitCartographicLimitRectangleScratch = new Rectangle();
  545. var rectangleCenterScratch = new Cartographic();
  546. // cartographicLimitRectangle may span the IDL, but tiles never will.
  547. function clipRectangleAntimeridian(tileRectangle, cartographicLimitRectangle) {
  548. if (cartographicLimitRectangle.west < cartographicLimitRectangle.east) {
  549. return cartographicLimitRectangle;
  550. }
  551. var splitRectangle = Rectangle.clone(
  552. cartographicLimitRectangle,
  553. splitCartographicLimitRectangleScratch
  554. );
  555. var tileCenter = Rectangle.center(tileRectangle, rectangleCenterScratch);
  556. if (tileCenter.longitude > 0.0) {
  557. splitRectangle.east = CesiumMath.PI;
  558. } else {
  559. splitRectangle.west = -CesiumMath.PI;
  560. }
  561. return splitRectangle;
  562. }
  563. function isUndergroundVisible(tileProvider, frameState) {
  564. if (frameState.cameraUnderground) {
  565. return true;
  566. }
  567. if (frameState.globeTranslucencyState.translucent) {
  568. return true;
  569. }
  570. if (tileProvider.backFaceCulling) {
  571. return false;
  572. }
  573. var clippingPlanes = tileProvider._clippingPlanes;
  574. if (defined(clippingPlanes) && clippingPlanes.enabled) {
  575. return true;
  576. }
  577. if (
  578. !Rectangle.equals(
  579. tileProvider.cartographicLimitRectangle,
  580. Rectangle.MAX_VALUE
  581. )
  582. ) {
  583. return true;
  584. }
  585. return false;
  586. }
  587. /**
  588. * Determines the visibility of a given tile. The tile may be fully visible, partially visible, or not
  589. * visible at all. Tiles that are renderable and are at least partially visible will be shown by a call
  590. * to {@link GlobeSurfaceTileProvider#showTileThisFrame}.
  591. *
  592. * @param {QuadtreeTile} tile The tile instance.
  593. * @param {FrameState} frameState The state information about the current frame.
  594. * @param {QuadtreeOccluders} occluders The objects that may occlude this tile.
  595. *
  596. * @returns {Visibility} Visibility.NONE if the tile is not visible,
  597. * Visibility.PARTIAL if the tile is partially visible, or
  598. * Visibility.FULL if the tile is fully visible.
  599. */
  600. GlobeSurfaceTileProvider.prototype.computeTileVisibility = function (
  601. tile,
  602. frameState,
  603. occluders
  604. ) {
  605. var distance = this.computeDistanceToTile(tile, frameState);
  606. tile._distance = distance;
  607. var undergroundVisible = isUndergroundVisible(this, frameState);
  608. if (frameState.fog.enabled && !undergroundVisible) {
  609. if (CesiumMath.fog(distance, frameState.fog.density) >= 1.0) {
  610. // Tile is completely in fog so return that it is not visible.
  611. return Visibility.NONE;
  612. }
  613. }
  614. var surfaceTile = tile.data;
  615. var tileBoundingRegion = surfaceTile.tileBoundingRegion;
  616. if (surfaceTile.boundingVolumeSourceTile === undefined) {
  617. // We have no idea where this tile is, so let's just call it partially visible.
  618. return Visibility.PARTIAL;
  619. }
  620. var cullingVolume = frameState.cullingVolume;
  621. var boundingVolume = surfaceTile.orientedBoundingBox;
  622. if (!defined(boundingVolume) && defined(surfaceTile.renderedMesh)) {
  623. boundingVolume = surfaceTile.renderedMesh.boundingSphere3D;
  624. }
  625. // Check if the tile is outside the limit area in cartographic space
  626. surfaceTile.clippedByBoundaries = false;
  627. var clippedCartographicLimitRectangle = clipRectangleAntimeridian(
  628. tile.rectangle,
  629. this.cartographicLimitRectangle
  630. );
  631. var areaLimitIntersection = Rectangle.simpleIntersection(
  632. clippedCartographicLimitRectangle,
  633. tile.rectangle,
  634. rectangleIntersectionScratch
  635. );
  636. if (!defined(areaLimitIntersection)) {
  637. return Visibility.NONE;
  638. }
  639. if (!Rectangle.equals(areaLimitIntersection, tile.rectangle)) {
  640. surfaceTile.clippedByBoundaries = true;
  641. }
  642. if (frameState.mode !== SceneMode.SCENE3D) {
  643. boundingVolume = boundingSphereScratch;
  644. BoundingSphere.fromRectangleWithHeights2D(
  645. tile.rectangle,
  646. frameState.mapProjection,
  647. tileBoundingRegion.minimumHeight,
  648. tileBoundingRegion.maximumHeight,
  649. boundingVolume
  650. );
  651. Cartesian3.fromElements(
  652. boundingVolume.center.z,
  653. boundingVolume.center.x,
  654. boundingVolume.center.y,
  655. boundingVolume.center
  656. );
  657. if (
  658. frameState.mode === SceneMode.MORPHING &&
  659. defined(surfaceTile.renderedMesh)
  660. ) {
  661. boundingVolume = BoundingSphere.union(
  662. surfaceTile.renderedMesh.boundingSphere3D,
  663. boundingVolume,
  664. boundingVolume
  665. );
  666. }
  667. }
  668. if (!defined(boundingVolume)) {
  669. return Visibility.PARTIAL;
  670. }
  671. var clippingPlanes = this._clippingPlanes;
  672. if (defined(clippingPlanes) && clippingPlanes.enabled) {
  673. var planeIntersection = clippingPlanes.computeIntersectionWithBoundingVolume(
  674. boundingVolume
  675. );
  676. tile.isClipped = planeIntersection !== Intersect.INSIDE;
  677. if (planeIntersection === Intersect.OUTSIDE) {
  678. return Visibility.NONE;
  679. }
  680. }
  681. var visibility;
  682. var intersection = cullingVolume.computeVisibility(boundingVolume);
  683. if (intersection === Intersect.OUTSIDE) {
  684. visibility = Visibility.NONE;
  685. } else if (intersection === Intersect.INTERSECTING) {
  686. visibility = Visibility.PARTIAL;
  687. } else if (intersection === Intersect.INSIDE) {
  688. visibility = Visibility.FULL;
  689. }
  690. if (visibility === Visibility.NONE) {
  691. return visibility;
  692. }
  693. var ortho3D =
  694. frameState.mode === SceneMode.SCENE3D &&
  695. frameState.camera.frustum instanceof OrthographicFrustum;
  696. if (
  697. frameState.mode === SceneMode.SCENE3D &&
  698. !ortho3D &&
  699. defined(occluders) &&
  700. !undergroundVisible
  701. ) {
  702. var occludeePointInScaledSpace = surfaceTile.occludeePointInScaledSpace;
  703. if (!defined(occludeePointInScaledSpace)) {
  704. return visibility;
  705. }
  706. if (
  707. occluders.ellipsoid.isScaledSpacePointVisiblePossiblyUnderEllipsoid(
  708. occludeePointInScaledSpace,
  709. tileBoundingRegion.minimumHeight
  710. )
  711. ) {
  712. return visibility;
  713. }
  714. return Visibility.NONE;
  715. }
  716. return visibility;
  717. };
  718. /**
  719. * Determines if the given tile can be refined
  720. * @param {QuadtreeTile} tile The tile to check.
  721. * @returns {boolean} True if the tile can be refined, false if it cannot.
  722. */
  723. GlobeSurfaceTileProvider.prototype.canRefine = function (tile) {
  724. // Only allow refinement it we know whether or not the children of this tile exist.
  725. // For a tileset with `availability`, we'll always be able to refine.
  726. // We can ask for availability of _any_ child tile because we only need to confirm
  727. // that we get a yes or no answer, it doesn't matter what the answer is.
  728. if (defined(tile.data.terrainData)) {
  729. return true;
  730. }
  731. var childAvailable = this.terrainProvider.getTileDataAvailable(
  732. tile.x * 2,
  733. tile.y * 2,
  734. tile.level + 1
  735. );
  736. return childAvailable !== undefined;
  737. };
  738. var readyImageryScratch = [];
  739. var canRenderTraversalStack = [];
  740. /**
  741. * Determines if the given not-fully-loaded tile can be rendered without losing detail that
  742. * was present last frame as a result of rendering descendant tiles. This method will only be
  743. * called if this tile's descendants were rendered last frame. If the tile is fully loaded,
  744. * it is assumed that this method will return true and it will not be called.
  745. * @param {QuadtreeTile} tile The tile to check.
  746. * @returns {boolean} True if the tile can be rendered without losing detail.
  747. */
  748. GlobeSurfaceTileProvider.prototype.canRenderWithoutLosingDetail = function (
  749. tile,
  750. frameState
  751. ) {
  752. var surfaceTile = tile.data;
  753. var readyImagery = readyImageryScratch;
  754. readyImagery.length = this._imageryLayers.length;
  755. var terrainReady = false;
  756. var initialImageryState = false;
  757. var imagery;
  758. if (defined(surfaceTile)) {
  759. // We can render even with non-ready terrain as long as all our rendered descendants
  760. // are missing terrain geometry too. i.e. if we rendered fills for more detailed tiles
  761. // last frame, it's ok to render a fill for this tile this frame.
  762. terrainReady = surfaceTile.terrainState === TerrainState.READY;
  763. // Initially assume all imagery layers are ready, unless imagery hasn't been initialized at all.
  764. initialImageryState = true;
  765. imagery = surfaceTile.imagery;
  766. }
  767. var i;
  768. var len;
  769. for (i = 0, len = readyImagery.length; i < len; ++i) {
  770. readyImagery[i] = initialImageryState;
  771. }
  772. if (defined(imagery)) {
  773. for (i = 0, len = imagery.length; i < len; ++i) {
  774. var tileImagery = imagery[i];
  775. var loadingImagery = tileImagery.loadingImagery;
  776. var isReady =
  777. !defined(loadingImagery) ||
  778. loadingImagery.state === ImageryState.FAILED ||
  779. loadingImagery.state === ImageryState.INVALID;
  780. var layerIndex = (tileImagery.loadingImagery || tileImagery.readyImagery)
  781. .imageryLayer._layerIndex;
  782. // For a layer to be ready, all tiles belonging to that layer must be ready.
  783. readyImagery[layerIndex] = isReady && readyImagery[layerIndex];
  784. }
  785. }
  786. var lastFrame = this.quadtree._lastSelectionFrameNumber;
  787. // Traverse the descendants looking for one with terrain or imagery that is not loaded on this tile.
  788. var stack = canRenderTraversalStack;
  789. stack.length = 0;
  790. stack.push(
  791. tile.southwestChild,
  792. tile.southeastChild,
  793. tile.northwestChild,
  794. tile.northeastChild
  795. );
  796. while (stack.length > 0) {
  797. var descendant = stack.pop();
  798. var lastFrameSelectionResult =
  799. descendant._lastSelectionResultFrame === lastFrame
  800. ? descendant._lastSelectionResult
  801. : TileSelectionResult.NONE;
  802. if (lastFrameSelectionResult === TileSelectionResult.RENDERED) {
  803. var descendantSurface = descendant.data;
  804. if (!defined(descendantSurface)) {
  805. // Descendant has no data, so it can't block rendering.
  806. continue;
  807. }
  808. if (
  809. !terrainReady &&
  810. descendant.data.terrainState === TerrainState.READY
  811. ) {
  812. // Rendered descendant has real terrain, but we don't. Rendering is blocked.
  813. return false;
  814. }
  815. var descendantImagery = descendant.data.imagery;
  816. for (i = 0, len = descendantImagery.length; i < len; ++i) {
  817. var descendantTileImagery = descendantImagery[i];
  818. var descendantLoadingImagery = descendantTileImagery.loadingImagery;
  819. var descendantIsReady =
  820. !defined(descendantLoadingImagery) ||
  821. descendantLoadingImagery.state === ImageryState.FAILED ||
  822. descendantLoadingImagery.state === ImageryState.INVALID;
  823. var descendantLayerIndex = (
  824. descendantTileImagery.loadingImagery ||
  825. descendantTileImagery.readyImagery
  826. ).imageryLayer._layerIndex;
  827. // If this imagery tile of a descendant is ready but the layer isn't ready in this tile,
  828. // then rendering is blocked.
  829. if (descendantIsReady && !readyImagery[descendantLayerIndex]) {
  830. return false;
  831. }
  832. }
  833. } else if (lastFrameSelectionResult === TileSelectionResult.REFINED) {
  834. stack.push(
  835. descendant.southwestChild,
  836. descendant.southeastChild,
  837. descendant.northwestChild,
  838. descendant.northeastChild
  839. );
  840. }
  841. }
  842. return true;
  843. };
  844. var tileDirectionScratch = new Cartesian3();
  845. /**
  846. * Determines the priority for loading this tile. Lower priority values load sooner.
  847. * @param {QuadtreeTile} tile The tile.
  848. * @param {FrameState} frameState The frame state.
  849. * @returns {Number} The load priority value.
  850. */
  851. GlobeSurfaceTileProvider.prototype.computeTileLoadPriority = function (
  852. tile,
  853. frameState
  854. ) {
  855. var surfaceTile = tile.data;
  856. if (surfaceTile === undefined) {
  857. return 0.0;
  858. }
  859. var obb = surfaceTile.orientedBoundingBox;
  860. if (obb === undefined) {
  861. return 0.0;
  862. }
  863. var cameraPosition = frameState.camera.positionWC;
  864. var cameraDirection = frameState.camera.directionWC;
  865. var tileDirection = Cartesian3.subtract(
  866. obb.center,
  867. cameraPosition,
  868. tileDirectionScratch
  869. );
  870. var magnitude = Cartesian3.magnitude(tileDirection);
  871. if (magnitude < CesiumMath.EPSILON5) {
  872. return 0.0;
  873. }
  874. Cartesian3.divideByScalar(tileDirection, magnitude, tileDirection);
  875. return (
  876. (1.0 - Cartesian3.dot(tileDirection, cameraDirection)) * tile._distance
  877. );
  878. };
  879. var modifiedModelViewScratch = new Matrix4();
  880. var modifiedModelViewProjectionScratch = new Matrix4();
  881. var tileRectangleScratch = new Cartesian4();
  882. var localizedCartographicLimitRectangleScratch = new Cartesian4();
  883. var localizedTranslucencyRectangleScratch = new Cartesian4();
  884. var rtcScratch = new Cartesian3();
  885. var centerEyeScratch = new Cartesian3();
  886. var southwestScratch = new Cartesian3();
  887. var northeastScratch = new Cartesian3();
  888. /**
  889. * Shows a specified tile in this frame. The provider can cause the tile to be shown by adding
  890. * render commands to the commandList, or use any other method as appropriate. The tile is not
  891. * expected to be visible next frame as well, unless this method is called next frame, too.
  892. *
  893. * @param {QuadtreeTile} tile The tile instance.
  894. * @param {FrameState} frameState The state information of the current rendering frame.
  895. */
  896. GlobeSurfaceTileProvider.prototype.showTileThisFrame = function (
  897. tile,
  898. frameState
  899. ) {
  900. var readyTextureCount = 0;
  901. var tileImageryCollection = tile.data.imagery;
  902. for (var i = 0, len = tileImageryCollection.length; i < len; ++i) {
  903. var tileImagery = tileImageryCollection[i];
  904. if (
  905. defined(tileImagery.readyImagery) &&
  906. tileImagery.readyImagery.imageryLayer.alpha !== 0.0
  907. ) {
  908. ++readyTextureCount;
  909. }
  910. }
  911. var tileSet = this._tilesToRenderByTextureCount[readyTextureCount];
  912. if (!defined(tileSet)) {
  913. tileSet = [];
  914. this._tilesToRenderByTextureCount[readyTextureCount] = tileSet;
  915. }
  916. tileSet.push(tile);
  917. var surfaceTile = tile.data;
  918. if (!defined(surfaceTile.vertexArray)) {
  919. this._hasFillTilesThisFrame = true;
  920. } else {
  921. this._hasLoadedTilesThisFrame = true;
  922. }
  923. var debug = this._debug;
  924. ++debug.tilesRendered;
  925. debug.texturesRendered += readyTextureCount;
  926. };
  927. var cornerPositionsScratch = [
  928. new Cartesian3(),
  929. new Cartesian3(),
  930. new Cartesian3(),
  931. new Cartesian3(),
  932. ];
  933. function computeOccludeePoint(
  934. tileProvider,
  935. center,
  936. rectangle,
  937. minimumHeight,
  938. maximumHeight,
  939. result
  940. ) {
  941. var ellipsoidalOccluder = tileProvider.quadtree._occluders.ellipsoid;
  942. var ellipsoid = ellipsoidalOccluder.ellipsoid;
  943. var cornerPositions = cornerPositionsScratch;
  944. Cartesian3.fromRadians(
  945. rectangle.west,
  946. rectangle.south,
  947. maximumHeight,
  948. ellipsoid,
  949. cornerPositions[0]
  950. );
  951. Cartesian3.fromRadians(
  952. rectangle.east,
  953. rectangle.south,
  954. maximumHeight,
  955. ellipsoid,
  956. cornerPositions[1]
  957. );
  958. Cartesian3.fromRadians(
  959. rectangle.west,
  960. rectangle.north,
  961. maximumHeight,
  962. ellipsoid,
  963. cornerPositions[2]
  964. );
  965. Cartesian3.fromRadians(
  966. rectangle.east,
  967. rectangle.north,
  968. maximumHeight,
  969. ellipsoid,
  970. cornerPositions[3]
  971. );
  972. return ellipsoidalOccluder.computeHorizonCullingPointPossiblyUnderEllipsoid(
  973. center,
  974. cornerPositions,
  975. minimumHeight,
  976. result
  977. );
  978. }
  979. /**
  980. * Gets the distance from the camera to the closest point on the tile. This is used for level-of-detail selection.
  981. *
  982. * @param {QuadtreeTile} tile The tile instance.
  983. * @param {FrameState} frameState The state information of the current rendering frame.
  984. *
  985. * @returns {Number} The distance from the camera to the closest point on the tile, in meters.
  986. */
  987. GlobeSurfaceTileProvider.prototype.computeDistanceToTile = function (
  988. tile,
  989. frameState
  990. ) {
  991. // The distance should be:
  992. // 1. the actual distance to the tight-fitting bounding volume, or
  993. // 2. a distance that is equal to or greater than the actual distance to the tight-fitting bounding volume.
  994. //
  995. // When we don't know the min/max heights for a tile, but we do know the min/max of an ancestor tile, we can
  996. // build a tight-fitting bounding volume horizontally, but not vertically. The min/max heights from the
  997. // ancestor will likely form a volume that is much bigger than it needs to be. This means that the volume may
  998. // be deemed to be much closer to the camera than it really is, causing us to select tiles that are too detailed.
  999. // Loading too-detailed tiles is super expensive, so we don't want to do that. We don't know where the child
  1000. // tile really lies within the parent range of heights, but we _do_ know the child tile can't be any closer than
  1001. // the ancestor height surface (min or max) that is _farthest away_ from the camera. So if we compute distance
  1002. // based that conservative metric, we may end up loading tiles that are not detailed enough, but that's much
  1003. // better (faster) than loading tiles that are too detailed.
  1004. var heightSource = updateTileBoundingRegion(
  1005. tile,
  1006. this.terrainProvider,
  1007. frameState
  1008. );
  1009. var surfaceTile = tile.data;
  1010. var tileBoundingRegion = surfaceTile.tileBoundingRegion;
  1011. if (heightSource === undefined) {
  1012. // Can't find any min/max heights anywhere? Ok, let's just say the
  1013. // tile is really far away so we'll load and render it rather than
  1014. // refining.
  1015. return 9999999999.0;
  1016. } else if (surfaceTile.boundingVolumeSourceTile !== heightSource) {
  1017. // Heights are from a new source tile, so update the bounding volume.
  1018. surfaceTile.boundingVolumeSourceTile = heightSource;
  1019. var rectangle = tile.rectangle;
  1020. if (defined(rectangle)) {
  1021. surfaceTile.orientedBoundingBox = OrientedBoundingBox.fromRectangle(
  1022. tile.rectangle,
  1023. tileBoundingRegion.minimumHeight,
  1024. tileBoundingRegion.maximumHeight,
  1025. tile.tilingScheme.ellipsoid,
  1026. surfaceTile.orientedBoundingBox
  1027. );
  1028. surfaceTile.occludeePointInScaledSpace = computeOccludeePoint(
  1029. this,
  1030. surfaceTile.orientedBoundingBox.center,
  1031. tile.rectangle,
  1032. tileBoundingRegion.minimumHeight,
  1033. tileBoundingRegion.maximumHeight,
  1034. surfaceTile.occludeePointInScaledSpace
  1035. );
  1036. }
  1037. }
  1038. var min = tileBoundingRegion.minimumHeight;
  1039. var max = tileBoundingRegion.maximumHeight;
  1040. if (surfaceTile.boundingVolumeSourceTile !== tile) {
  1041. var cameraHeight = frameState.camera.positionCartographic.height;
  1042. var distanceToMin = Math.abs(cameraHeight - min);
  1043. var distanceToMax = Math.abs(cameraHeight - max);
  1044. if (distanceToMin > distanceToMax) {
  1045. tileBoundingRegion.minimumHeight = min;
  1046. tileBoundingRegion.maximumHeight = min;
  1047. } else {
  1048. tileBoundingRegion.minimumHeight = max;
  1049. tileBoundingRegion.maximumHeight = max;
  1050. }
  1051. }
  1052. var result = tileBoundingRegion.distanceToCamera(frameState);
  1053. tileBoundingRegion.minimumHeight = min;
  1054. tileBoundingRegion.maximumHeight = max;
  1055. return result;
  1056. };
  1057. function updateTileBoundingRegion(tile, terrainProvider, frameState) {
  1058. var surfaceTile = tile.data;
  1059. if (surfaceTile === undefined) {
  1060. surfaceTile = tile.data = new GlobeSurfaceTile();
  1061. }
  1062. if (surfaceTile.tileBoundingRegion === undefined) {
  1063. surfaceTile.tileBoundingRegion = new TileBoundingRegion({
  1064. computeBoundingVolumes: false,
  1065. rectangle: tile.rectangle,
  1066. ellipsoid: tile.tilingScheme.ellipsoid,
  1067. minimumHeight: 0.0,
  1068. maximumHeight: 0.0,
  1069. });
  1070. }
  1071. var terrainData = surfaceTile.terrainData;
  1072. var mesh = surfaceTile.mesh;
  1073. var tileBoundingRegion = surfaceTile.tileBoundingRegion;
  1074. if (
  1075. mesh !== undefined &&
  1076. mesh.minimumHeight !== undefined &&
  1077. mesh.maximumHeight !== undefined
  1078. ) {
  1079. // We have tight-fitting min/max heights from the mesh.
  1080. tileBoundingRegion.minimumHeight = mesh.minimumHeight;
  1081. tileBoundingRegion.maximumHeight = mesh.maximumHeight;
  1082. return tile;
  1083. }
  1084. if (
  1085. terrainData !== undefined &&
  1086. terrainData._minimumHeight !== undefined &&
  1087. terrainData._maximumHeight !== undefined
  1088. ) {
  1089. // We have tight-fitting min/max heights from the terrain data.
  1090. tileBoundingRegion.minimumHeight =
  1091. terrainData._minimumHeight * frameState.terrainExaggeration;
  1092. tileBoundingRegion.maximumHeight =
  1093. terrainData._maximumHeight * frameState.terrainExaggeration;
  1094. return tile;
  1095. }
  1096. // No accurate min/max heights available, so we're stuck with min/max heights from an ancestor tile.
  1097. tileBoundingRegion.minimumHeight = Number.NaN;
  1098. tileBoundingRegion.maximumHeight = Number.NaN;
  1099. var ancestor = tile.parent;
  1100. while (ancestor !== undefined) {
  1101. var ancestorSurfaceTile = ancestor.data;
  1102. if (ancestorSurfaceTile !== undefined) {
  1103. var ancestorMesh = ancestorSurfaceTile.mesh;
  1104. if (
  1105. ancestorMesh !== undefined &&
  1106. ancestorMesh.minimumHeight !== undefined &&
  1107. ancestorMesh.maximumHeight !== undefined
  1108. ) {
  1109. tileBoundingRegion.minimumHeight = ancestorMesh.minimumHeight;
  1110. tileBoundingRegion.maximumHeight = ancestorMesh.maximumHeight;
  1111. return ancestor;
  1112. }
  1113. var ancestorTerrainData = ancestorSurfaceTile.terrainData;
  1114. if (
  1115. ancestorTerrainData !== undefined &&
  1116. ancestorTerrainData._minimumHeight !== undefined &&
  1117. ancestorTerrainData._maximumHeight !== undefined
  1118. ) {
  1119. tileBoundingRegion.minimumHeight =
  1120. ancestorTerrainData._minimumHeight * frameState.terrainExaggeration;
  1121. tileBoundingRegion.maximumHeight =
  1122. ancestorTerrainData._maximumHeight * frameState.terrainExaggeration;
  1123. return ancestor;
  1124. }
  1125. }
  1126. ancestor = ancestor.parent;
  1127. }
  1128. return undefined;
  1129. }
  1130. /**
  1131. * Returns true if this object was destroyed; otherwise, false.
  1132. * <br /><br />
  1133. * If this object was destroyed, it should not be used; calling any function other than
  1134. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  1135. *
  1136. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  1137. *
  1138. * @see GlobeSurfaceTileProvider#destroy
  1139. */
  1140. GlobeSurfaceTileProvider.prototype.isDestroyed = function () {
  1141. return false;
  1142. };
  1143. /**
  1144. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  1145. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  1146. * <br /><br />
  1147. * Once an object is destroyed, it should not be used; calling any function other than
  1148. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  1149. * assign the return value (<code>undefined</code>) to the object as done in the example.
  1150. *
  1151. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  1152. *
  1153. *
  1154. * @example
  1155. * provider = provider && provider();
  1156. *
  1157. * @see GlobeSurfaceTileProvider#isDestroyed
  1158. */
  1159. GlobeSurfaceTileProvider.prototype.destroy = function () {
  1160. this._tileProvider = this._tileProvider && this._tileProvider.destroy();
  1161. this._clippingPlanes = this._clippingPlanes && this._clippingPlanes.destroy();
  1162. return destroyObject(this);
  1163. };
  1164. function getTileReadyCallback(tileImageriesToFree, layer, terrainProvider) {
  1165. return function (tile) {
  1166. var tileImagery;
  1167. var imagery;
  1168. var startIndex = -1;
  1169. var tileImageryCollection = tile.data.imagery;
  1170. var length = tileImageryCollection.length;
  1171. var i;
  1172. for (i = 0; i < length; ++i) {
  1173. tileImagery = tileImageryCollection[i];
  1174. imagery = defaultValue(
  1175. tileImagery.readyImagery,
  1176. tileImagery.loadingImagery
  1177. );
  1178. if (imagery.imageryLayer === layer) {
  1179. startIndex = i;
  1180. break;
  1181. }
  1182. }
  1183. if (startIndex !== -1) {
  1184. var endIndex = startIndex + tileImageriesToFree;
  1185. tileImagery = tileImageryCollection[endIndex];
  1186. imagery = defined(tileImagery)
  1187. ? defaultValue(tileImagery.readyImagery, tileImagery.loadingImagery)
  1188. : undefined;
  1189. if (!defined(imagery) || imagery.imageryLayer !== layer) {
  1190. // Return false to keep the callback if we have to wait on the skeletons
  1191. // Return true to remove the callback if something went wrong
  1192. return !layer._createTileImagerySkeletons(
  1193. tile,
  1194. terrainProvider,
  1195. endIndex
  1196. );
  1197. }
  1198. for (i = startIndex; i < endIndex; ++i) {
  1199. tileImageryCollection[i].freeResources();
  1200. }
  1201. tileImageryCollection.splice(startIndex, tileImageriesToFree);
  1202. }
  1203. return true; // Everything is done, so remove the callback
  1204. };
  1205. }
  1206. GlobeSurfaceTileProvider.prototype._onLayerAdded = function (layer, index) {
  1207. if (layer.show) {
  1208. var terrainProvider = this._terrainProvider;
  1209. var that = this;
  1210. var imageryProvider = layer.imageryProvider;
  1211. var tileImageryUpdatedEvent = this._imageryLayersUpdatedEvent;
  1212. imageryProvider._reload = function () {
  1213. // Clear the layer's cache
  1214. layer._imageryCache = {};
  1215. that._quadtree.forEachLoadedTile(function (tile) {
  1216. // If this layer is still waiting to for the loaded callback, just return
  1217. if (defined(tile._loadedCallbacks[layer._layerIndex])) {
  1218. return;
  1219. }
  1220. var i;
  1221. // Figure out how many TileImageries we will need to remove and where to insert new ones
  1222. var tileImageryCollection = tile.data.imagery;
  1223. var length = tileImageryCollection.length;
  1224. var startIndex = -1;
  1225. var tileImageriesToFree = 0;
  1226. for (i = 0; i < length; ++i) {
  1227. var tileImagery = tileImageryCollection[i];
  1228. var imagery = defaultValue(
  1229. tileImagery.readyImagery,
  1230. tileImagery.loadingImagery
  1231. );
  1232. if (imagery.imageryLayer === layer) {
  1233. if (startIndex === -1) {
  1234. startIndex = i;
  1235. }
  1236. ++tileImageriesToFree;
  1237. } else if (startIndex !== -1) {
  1238. // iterated past the section of TileImageries belonging to this layer, no need to continue.
  1239. break;
  1240. }
  1241. }
  1242. if (startIndex === -1) {
  1243. return;
  1244. }
  1245. // Insert immediately after existing TileImageries
  1246. var insertionPoint = startIndex + tileImageriesToFree;
  1247. // Create new TileImageries for all loaded tiles
  1248. if (
  1249. layer._createTileImagerySkeletons(
  1250. tile,
  1251. terrainProvider,
  1252. insertionPoint
  1253. )
  1254. ) {
  1255. // Add callback to remove old TileImageries when the new TileImageries are ready
  1256. tile._loadedCallbacks[layer._layerIndex] = getTileReadyCallback(
  1257. tileImageriesToFree,
  1258. layer,
  1259. terrainProvider
  1260. );
  1261. tile.state = QuadtreeTileLoadState.LOADING;
  1262. }
  1263. });
  1264. };
  1265. // create TileImageries for this layer for all previously loaded tiles
  1266. this._quadtree.forEachLoadedTile(function (tile) {
  1267. if (layer._createTileImagerySkeletons(tile, terrainProvider)) {
  1268. tile.state = QuadtreeTileLoadState.LOADING;
  1269. // Tiles that are not currently being rendered need to load the new layer before they're renderable.
  1270. // We don't mark the rendered tiles non-renderable, though, because that would make the globe disappear.
  1271. if (
  1272. tile.level !== 0 &&
  1273. (tile._lastSelectionResultFrame !==
  1274. that.quadtree._lastSelectionFrameNumber ||
  1275. tile._lastSelectionResult !== TileSelectionResult.RENDERED)
  1276. ) {
  1277. tile.renderable = false;
  1278. }
  1279. }
  1280. });
  1281. this._layerOrderChanged = true;
  1282. tileImageryUpdatedEvent.raiseEvent();
  1283. }
  1284. };
  1285. GlobeSurfaceTileProvider.prototype._onLayerRemoved = function (layer, index) {
  1286. // destroy TileImagerys for this layer for all previously loaded tiles
  1287. this._quadtree.forEachLoadedTile(function (tile) {
  1288. var tileImageryCollection = tile.data.imagery;
  1289. var startIndex = -1;
  1290. var numDestroyed = 0;
  1291. for (var i = 0, len = tileImageryCollection.length; i < len; ++i) {
  1292. var tileImagery = tileImageryCollection[i];
  1293. var imagery = tileImagery.loadingImagery;
  1294. if (!defined(imagery)) {
  1295. imagery = tileImagery.readyImagery;
  1296. }
  1297. if (imagery.imageryLayer === layer) {
  1298. if (startIndex === -1) {
  1299. startIndex = i;
  1300. }
  1301. tileImagery.freeResources();
  1302. ++numDestroyed;
  1303. } else if (startIndex !== -1) {
  1304. // iterated past the section of TileImagerys belonging to this layer, no need to continue.
  1305. break;
  1306. }
  1307. }
  1308. if (startIndex !== -1) {
  1309. tileImageryCollection.splice(startIndex, numDestroyed);
  1310. }
  1311. });
  1312. if (defined(layer.imageryProvider)) {
  1313. layer.imageryProvider._reload = undefined;
  1314. }
  1315. this._imageryLayersUpdatedEvent.raiseEvent();
  1316. };
  1317. GlobeSurfaceTileProvider.prototype._onLayerMoved = function (
  1318. layer,
  1319. newIndex,
  1320. oldIndex
  1321. ) {
  1322. this._layerOrderChanged = true;
  1323. this._imageryLayersUpdatedEvent.raiseEvent();
  1324. };
  1325. GlobeSurfaceTileProvider.prototype._onLayerShownOrHidden = function (
  1326. layer,
  1327. index,
  1328. show
  1329. ) {
  1330. if (show) {
  1331. this._onLayerAdded(layer, index);
  1332. } else {
  1333. this._onLayerRemoved(layer, index);
  1334. }
  1335. };
  1336. var scratchClippingPlaneMatrix = new Matrix4();
  1337. function createTileUniformMap(frameState, globeSurfaceTileProvider) {
  1338. var uniformMap = {
  1339. u_initialColor: function () {
  1340. return this.properties.initialColor;
  1341. },
  1342. u_fillHighlightColor: function () {
  1343. return this.properties.fillHighlightColor;
  1344. },
  1345. u_zoomedOutOceanSpecularIntensity: function () {
  1346. return this.properties.zoomedOutOceanSpecularIntensity;
  1347. },
  1348. u_oceanNormalMap: function () {
  1349. return this.properties.oceanNormalMap;
  1350. },
  1351. u_lightingFadeDistance: function () {
  1352. return this.properties.lightingFadeDistance;
  1353. },
  1354. u_nightFadeDistance: function () {
  1355. return this.properties.nightFadeDistance;
  1356. },
  1357. u_center3D: function () {
  1358. return this.properties.center3D;
  1359. },
  1360. u_tileRectangle: function () {
  1361. return this.properties.tileRectangle;
  1362. },
  1363. u_modifiedModelView: function () {
  1364. var viewMatrix = frameState.context.uniformState.view;
  1365. var centerEye = Matrix4.multiplyByPoint(
  1366. viewMatrix,
  1367. this.properties.rtc,
  1368. centerEyeScratch
  1369. );
  1370. Matrix4.setTranslation(viewMatrix, centerEye, modifiedModelViewScratch);
  1371. return modifiedModelViewScratch;
  1372. },
  1373. u_modifiedModelViewProjection: function () {
  1374. var viewMatrix = frameState.context.uniformState.view;
  1375. var projectionMatrix = frameState.context.uniformState.projection;
  1376. var centerEye = Matrix4.multiplyByPoint(
  1377. viewMatrix,
  1378. this.properties.rtc,
  1379. centerEyeScratch
  1380. );
  1381. Matrix4.setTranslation(
  1382. viewMatrix,
  1383. centerEye,
  1384. modifiedModelViewProjectionScratch
  1385. );
  1386. Matrix4.multiply(
  1387. projectionMatrix,
  1388. modifiedModelViewProjectionScratch,
  1389. modifiedModelViewProjectionScratch
  1390. );
  1391. return modifiedModelViewProjectionScratch;
  1392. },
  1393. u_dayTextures: function () {
  1394. return this.properties.dayTextures;
  1395. },
  1396. u_dayTextureTranslationAndScale: function () {
  1397. return this.properties.dayTextureTranslationAndScale;
  1398. },
  1399. u_dayTextureTexCoordsRectangle: function () {
  1400. return this.properties.dayTextureTexCoordsRectangle;
  1401. },
  1402. u_dayTextureUseWebMercatorT: function () {
  1403. return this.properties.dayTextureUseWebMercatorT;
  1404. },
  1405. u_dayTextureAlpha: function () {
  1406. return this.properties.dayTextureAlpha;
  1407. },
  1408. u_dayTextureNightAlpha: function () {
  1409. return this.properties.dayTextureNightAlpha;
  1410. },
  1411. u_dayTextureDayAlpha: function () {
  1412. return this.properties.dayTextureDayAlpha;
  1413. },
  1414. u_dayTextureBrightness: function () {
  1415. return this.properties.dayTextureBrightness;
  1416. },
  1417. u_dayTextureContrast: function () {
  1418. return this.properties.dayTextureContrast;
  1419. },
  1420. u_dayTextureHue: function () {
  1421. return this.properties.dayTextureHue;
  1422. },
  1423. u_dayTextureSaturation: function () {
  1424. return this.properties.dayTextureSaturation;
  1425. },
  1426. u_dayTextureOneOverGamma: function () {
  1427. return this.properties.dayTextureOneOverGamma;
  1428. },
  1429. u_dayIntensity: function () {
  1430. return this.properties.dayIntensity;
  1431. },
  1432. u_southAndNorthLatitude: function () {
  1433. return this.properties.southAndNorthLatitude;
  1434. },
  1435. u_southMercatorYAndOneOverHeight: function () {
  1436. return this.properties.southMercatorYAndOneOverHeight;
  1437. },
  1438. u_waterMask: function () {
  1439. return this.properties.waterMask;
  1440. },
  1441. u_waterMaskTranslationAndScale: function () {
  1442. return this.properties.waterMaskTranslationAndScale;
  1443. },
  1444. u_minMaxHeight: function () {
  1445. return this.properties.minMaxHeight;
  1446. },
  1447. u_scaleAndBias: function () {
  1448. return this.properties.scaleAndBias;
  1449. },
  1450. u_dayTextureSplit: function () {
  1451. return this.properties.dayTextureSplit;
  1452. },
  1453. u_dayTextureCutoutRectangles: function () {
  1454. return this.properties.dayTextureCutoutRectangles;
  1455. },
  1456. u_clippingPlanes: function () {
  1457. var clippingPlanes = globeSurfaceTileProvider._clippingPlanes;
  1458. if (defined(clippingPlanes) && defined(clippingPlanes.texture)) {
  1459. // Check in case clippingPlanes hasn't been updated yet.
  1460. return clippingPlanes.texture;
  1461. }
  1462. return frameState.context.defaultTexture;
  1463. },
  1464. u_cartographicLimitRectangle: function () {
  1465. return this.properties.localizedCartographicLimitRectangle;
  1466. },
  1467. u_clippingPlanesMatrix: function () {
  1468. var clippingPlanes = globeSurfaceTileProvider._clippingPlanes;
  1469. return defined(clippingPlanes)
  1470. ? Matrix4.multiply(
  1471. frameState.context.uniformState.view,
  1472. clippingPlanes.modelMatrix,
  1473. scratchClippingPlaneMatrix
  1474. )
  1475. : Matrix4.IDENTITY;
  1476. },
  1477. u_clippingPlanesEdgeStyle: function () {
  1478. var style = this.properties.clippingPlanesEdgeColor;
  1479. style.alpha = this.properties.clippingPlanesEdgeWidth;
  1480. return style;
  1481. },
  1482. u_minimumBrightness: function () {
  1483. return frameState.fog.minimumBrightness;
  1484. },
  1485. u_hsbShift: function () {
  1486. return this.properties.hsbShift;
  1487. },
  1488. u_colorsToAlpha: function () {
  1489. return this.properties.colorsToAlpha;
  1490. },
  1491. u_frontFaceAlphaByDistance: function () {
  1492. return this.properties.frontFaceAlphaByDistance;
  1493. },
  1494. u_backFaceAlphaByDistance: function () {
  1495. return this.properties.backFaceAlphaByDistance;
  1496. },
  1497. u_translucencyRectangle: function () {
  1498. return this.properties.localizedTranslucencyRectangle;
  1499. },
  1500. u_undergroundColor: function () {
  1501. return this.properties.undergroundColor;
  1502. },
  1503. u_undergroundColorAlphaByDistance: function () {
  1504. return this.properties.undergroundColorAlphaByDistance;
  1505. },
  1506. // make a separate object so that changes to the properties are seen on
  1507. // derived commands that combine another uniform map with this one.
  1508. properties: {
  1509. initialColor: new Cartesian4(0.0, 0.0, 0.5, 1.0),
  1510. fillHighlightColor: new Color(0.0, 0.0, 0.0, 0.0),
  1511. zoomedOutOceanSpecularIntensity: 0.5,
  1512. oceanNormalMap: undefined,
  1513. lightingFadeDistance: new Cartesian2(6500000.0, 9000000.0),
  1514. nightFadeDistance: new Cartesian2(10000000.0, 40000000.0),
  1515. hsbShift: new Cartesian3(),
  1516. center3D: undefined,
  1517. rtc: new Cartesian3(),
  1518. modifiedModelView: new Matrix4(),
  1519. tileRectangle: new Cartesian4(),
  1520. dayTextures: [],
  1521. dayTextureTranslationAndScale: [],
  1522. dayTextureTexCoordsRectangle: [],
  1523. dayTextureUseWebMercatorT: [],
  1524. dayTextureAlpha: [],
  1525. dayTextureNightAlpha: [],
  1526. dayTextureDayAlpha: [],
  1527. dayTextureBrightness: [],
  1528. dayTextureContrast: [],
  1529. dayTextureHue: [],
  1530. dayTextureSaturation: [],
  1531. dayTextureOneOverGamma: [],
  1532. dayTextureSplit: [],
  1533. dayTextureCutoutRectangles: [],
  1534. dayIntensity: 0.0,
  1535. colorsToAlpha: [],
  1536. southAndNorthLatitude: new Cartesian2(),
  1537. southMercatorYAndOneOverHeight: new Cartesian2(),
  1538. waterMask: undefined,
  1539. waterMaskTranslationAndScale: new Cartesian4(),
  1540. minMaxHeight: new Cartesian2(),
  1541. scaleAndBias: new Matrix4(),
  1542. clippingPlanesEdgeColor: Color.clone(Color.WHITE),
  1543. clippingPlanesEdgeWidth: 0.0,
  1544. localizedCartographicLimitRectangle: new Cartesian4(),
  1545. frontFaceAlphaByDistance: new Cartesian4(),
  1546. backFaceAlphaByDistance: new Cartesian4(),
  1547. localizedTranslucencyRectangle: new Cartesian4(),
  1548. undergroundColor: Color.clone(Color.TRANSPARENT),
  1549. undergroundColorAlphaByDistance: new Cartesian4(),
  1550. },
  1551. };
  1552. if (defined(globeSurfaceTileProvider.materialUniformMap)) {
  1553. return combine(uniformMap, globeSurfaceTileProvider.materialUniformMap);
  1554. }
  1555. return uniformMap;
  1556. }
  1557. function createWireframeVertexArrayIfNecessary(context, provider, tile) {
  1558. var surfaceTile = tile.data;
  1559. var mesh;
  1560. var vertexArray;
  1561. if (defined(surfaceTile.vertexArray)) {
  1562. mesh = surfaceTile.mesh;
  1563. vertexArray = surfaceTile.vertexArray;
  1564. } else if (
  1565. defined(surfaceTile.fill) &&
  1566. defined(surfaceTile.fill.vertexArray)
  1567. ) {
  1568. mesh = surfaceTile.fill.mesh;
  1569. vertexArray = surfaceTile.fill.vertexArray;
  1570. }
  1571. if (!defined(mesh) || !defined(vertexArray)) {
  1572. return;
  1573. }
  1574. if (defined(surfaceTile.wireframeVertexArray)) {
  1575. if (surfaceTile.wireframeVertexArray.mesh === mesh) {
  1576. return;
  1577. }
  1578. surfaceTile.wireframeVertexArray.destroy();
  1579. surfaceTile.wireframeVertexArray = undefined;
  1580. }
  1581. surfaceTile.wireframeVertexArray = createWireframeVertexArray(
  1582. context,
  1583. vertexArray,
  1584. mesh
  1585. );
  1586. surfaceTile.wireframeVertexArray.mesh = mesh;
  1587. }
  1588. /**
  1589. * Creates a vertex array for wireframe rendering of a terrain tile.
  1590. *
  1591. * @private
  1592. *
  1593. * @param {Context} context The context in which to create the vertex array.
  1594. * @param {VertexArray} vertexArray The existing, non-wireframe vertex array. The new vertex array
  1595. * will share vertex buffers with this existing one.
  1596. * @param {TerrainMesh} terrainMesh The terrain mesh containing non-wireframe indices.
  1597. * @returns {VertexArray} The vertex array for wireframe rendering.
  1598. */
  1599. function createWireframeVertexArray(context, vertexArray, terrainMesh) {
  1600. var indices = terrainMesh.indices;
  1601. var geometry = {
  1602. indices: indices,
  1603. primitiveType: PrimitiveType.TRIANGLES,
  1604. };
  1605. GeometryPipeline.toWireframe(geometry);
  1606. var wireframeIndices = geometry.indices;
  1607. var wireframeIndexBuffer = Buffer.createIndexBuffer({
  1608. context: context,
  1609. typedArray: wireframeIndices,
  1610. usage: BufferUsage.STATIC_DRAW,
  1611. indexDatatype: IndexDatatype.fromSizeInBytes(
  1612. wireframeIndices.BYTES_PER_ELEMENT
  1613. ),
  1614. });
  1615. return new VertexArray({
  1616. context: context,
  1617. attributes: vertexArray._attributes,
  1618. indexBuffer: wireframeIndexBuffer,
  1619. });
  1620. }
  1621. var getDebugOrientedBoundingBox;
  1622. var getDebugBoundingSphere;
  1623. var debugDestroyPrimitive;
  1624. (function () {
  1625. var instanceOBB = new GeometryInstance({
  1626. geometry: BoxOutlineGeometry.fromDimensions({
  1627. dimensions: new Cartesian3(2.0, 2.0, 2.0),
  1628. }),
  1629. });
  1630. var instanceSphere = new GeometryInstance({
  1631. geometry: new SphereOutlineGeometry({ radius: 1.0 }),
  1632. });
  1633. var modelMatrix = new Matrix4();
  1634. var previousVolume;
  1635. var primitive;
  1636. function createDebugPrimitive(instance) {
  1637. return new Primitive({
  1638. geometryInstances: instance,
  1639. appearance: new PerInstanceColorAppearance({
  1640. translucent: false,
  1641. flat: true,
  1642. }),
  1643. asynchronous: false,
  1644. });
  1645. }
  1646. getDebugOrientedBoundingBox = function (obb, color) {
  1647. if (obb === previousVolume) {
  1648. return primitive;
  1649. }
  1650. debugDestroyPrimitive();
  1651. previousVolume = obb;
  1652. modelMatrix = Matrix4.fromRotationTranslation(
  1653. obb.halfAxes,
  1654. obb.center,
  1655. modelMatrix
  1656. );
  1657. instanceOBB.modelMatrix = modelMatrix;
  1658. instanceOBB.attributes.color = ColorGeometryInstanceAttribute.fromColor(
  1659. color
  1660. );
  1661. primitive = createDebugPrimitive(instanceOBB);
  1662. return primitive;
  1663. };
  1664. getDebugBoundingSphere = function (sphere, color) {
  1665. if (sphere === previousVolume) {
  1666. return primitive;
  1667. }
  1668. debugDestroyPrimitive();
  1669. previousVolume = sphere;
  1670. modelMatrix = Matrix4.fromTranslation(sphere.center, modelMatrix);
  1671. modelMatrix = Matrix4.multiplyByUniformScale(
  1672. modelMatrix,
  1673. sphere.radius,
  1674. modelMatrix
  1675. );
  1676. instanceSphere.modelMatrix = modelMatrix;
  1677. instanceSphere.attributes.color = ColorGeometryInstanceAttribute.fromColor(
  1678. color
  1679. );
  1680. primitive = createDebugPrimitive(instanceSphere);
  1681. return primitive;
  1682. };
  1683. debugDestroyPrimitive = function () {
  1684. if (defined(primitive)) {
  1685. primitive.destroy();
  1686. primitive = undefined;
  1687. previousVolume = undefined;
  1688. }
  1689. };
  1690. })();
  1691. var otherPassesInitialColor = new Cartesian4(0.0, 0.0, 0.0, 0.0);
  1692. var surfaceShaderSetOptionsScratch = {
  1693. frameState: undefined,
  1694. surfaceTile: undefined,
  1695. numberOfDayTextures: undefined,
  1696. applyBrightness: undefined,
  1697. applyContrast: undefined,
  1698. applyHue: undefined,
  1699. applySaturation: undefined,
  1700. applyGamma: undefined,
  1701. applyAlpha: undefined,
  1702. applyDayNightAlpha: undefined,
  1703. applySplit: undefined,
  1704. showReflectiveOcean: undefined,
  1705. showOceanWaves: undefined,
  1706. enableLighting: undefined,
  1707. dynamicAtmosphereLighting: undefined,
  1708. dynamicAtmosphereLightingFromSun: undefined,
  1709. showGroundAtmosphere: undefined,
  1710. perFragmentGroundAtmosphere: undefined,
  1711. hasVertexNormals: undefined,
  1712. useWebMercatorProjection: undefined,
  1713. enableFog: undefined,
  1714. enableClippingPlanes: undefined,
  1715. clippingPlanes: undefined,
  1716. clippedByBoundaries: undefined,
  1717. hasImageryLayerCutout: undefined,
  1718. colorCorrect: undefined,
  1719. colorToAlpha: undefined,
  1720. };
  1721. var defaultUndergroundColor = Color.TRANSPARENT;
  1722. var defaultundergroundColorAlphaByDistance = new NearFarScalar();
  1723. function addDrawCommandsForTile(tileProvider, tile, frameState) {
  1724. var surfaceTile = tile.data;
  1725. if (!defined(surfaceTile.vertexArray)) {
  1726. if (surfaceTile.fill === undefined) {
  1727. // No fill was created for this tile, probably because this tile is not connected to
  1728. // any renderable tiles. So create a simple tile in the middle of the tile's possible
  1729. // height range.
  1730. surfaceTile.fill = new TerrainFillMesh(tile);
  1731. }
  1732. surfaceTile.fill.update(tileProvider, frameState);
  1733. }
  1734. var creditDisplay = frameState.creditDisplay;
  1735. var terrainData = surfaceTile.terrainData;
  1736. if (defined(terrainData) && defined(terrainData.credits)) {
  1737. var tileCredits = terrainData.credits;
  1738. for (
  1739. var tileCreditIndex = 0, tileCreditLength = tileCredits.length;
  1740. tileCreditIndex < tileCreditLength;
  1741. ++tileCreditIndex
  1742. ) {
  1743. creditDisplay.addCredit(tileCredits[tileCreditIndex]);
  1744. }
  1745. }
  1746. var maxTextures = ContextLimits.maximumTextureImageUnits;
  1747. var waterMaskTexture = surfaceTile.waterMaskTexture;
  1748. var waterMaskTranslationAndScale = surfaceTile.waterMaskTranslationAndScale;
  1749. if (!defined(waterMaskTexture) && defined(surfaceTile.fill)) {
  1750. waterMaskTexture = surfaceTile.fill.waterMaskTexture;
  1751. waterMaskTranslationAndScale =
  1752. surfaceTile.fill.waterMaskTranslationAndScale;
  1753. }
  1754. var cameraUnderground = frameState.cameraUnderground;
  1755. var globeTranslucencyState = frameState.globeTranslucencyState;
  1756. var translucent = globeTranslucencyState.translucent;
  1757. var frontFaceAlphaByDistance =
  1758. globeTranslucencyState.frontFaceAlphaByDistance;
  1759. var backFaceAlphaByDistance = globeTranslucencyState.backFaceAlphaByDistance;
  1760. var translucencyRectangle = globeTranslucencyState.rectangle;
  1761. var undergroundColor = defaultValue(
  1762. tileProvider.undergroundColor,
  1763. defaultUndergroundColor
  1764. );
  1765. var undergroundColorAlphaByDistance = defaultValue(
  1766. tileProvider.undergroundColorAlphaByDistance,
  1767. defaultundergroundColorAlphaByDistance
  1768. );
  1769. var showUndergroundColor =
  1770. isUndergroundVisible(tileProvider, frameState) &&
  1771. frameState.mode === SceneMode.SCENE3D &&
  1772. undergroundColor.alpha > 0.0 &&
  1773. (undergroundColorAlphaByDistance.nearValue > 0.0 ||
  1774. undergroundColorAlphaByDistance.farValue > 0.0);
  1775. var showReflectiveOcean =
  1776. tileProvider.hasWaterMask && defined(waterMaskTexture);
  1777. var oceanNormalMap = tileProvider.oceanNormalMap;
  1778. var showOceanWaves = showReflectiveOcean && defined(oceanNormalMap);
  1779. var hasVertexNormals =
  1780. tileProvider.terrainProvider.ready &&
  1781. tileProvider.terrainProvider.hasVertexNormals;
  1782. var enableFog = frameState.fog.enabled && !cameraUnderground;
  1783. var showGroundAtmosphere =
  1784. tileProvider.showGroundAtmosphere && frameState.mode === SceneMode.SCENE3D;
  1785. var castShadows =
  1786. ShadowMode.castShadows(tileProvider.shadows) && !translucent;
  1787. var receiveShadows =
  1788. ShadowMode.receiveShadows(tileProvider.shadows) && !translucent;
  1789. var hueShift = tileProvider.hueShift;
  1790. var saturationShift = tileProvider.saturationShift;
  1791. var brightnessShift = tileProvider.brightnessShift;
  1792. var colorCorrect = !(
  1793. CesiumMath.equalsEpsilon(hueShift, 0.0, CesiumMath.EPSILON7) &&
  1794. CesiumMath.equalsEpsilon(saturationShift, 0.0, CesiumMath.EPSILON7) &&
  1795. CesiumMath.equalsEpsilon(brightnessShift, 0.0, CesiumMath.EPSILON7)
  1796. );
  1797. var perFragmentGroundAtmosphere = false;
  1798. if (showGroundAtmosphere) {
  1799. var cameraDistance = Cartesian3.magnitude(frameState.camera.positionWC);
  1800. var fadeOutDistance = tileProvider.nightFadeOutDistance;
  1801. perFragmentGroundAtmosphere = cameraDistance > fadeOutDistance;
  1802. }
  1803. if (showReflectiveOcean) {
  1804. --maxTextures;
  1805. }
  1806. if (showOceanWaves) {
  1807. --maxTextures;
  1808. }
  1809. if (
  1810. defined(frameState.shadowState) &&
  1811. frameState.shadowState.shadowsEnabled
  1812. ) {
  1813. --maxTextures;
  1814. }
  1815. if (
  1816. defined(tileProvider.clippingPlanes) &&
  1817. tileProvider.clippingPlanes.enabled
  1818. ) {
  1819. --maxTextures;
  1820. }
  1821. maxTextures -= globeTranslucencyState.numberOfTextureUniforms;
  1822. var mesh = surfaceTile.renderedMesh;
  1823. var rtc = mesh.center;
  1824. var encoding = mesh.encoding;
  1825. // Not used in 3D.
  1826. var tileRectangle = tileRectangleScratch;
  1827. // Only used for Mercator projections.
  1828. var southLatitude = 0.0;
  1829. var northLatitude = 0.0;
  1830. var southMercatorY = 0.0;
  1831. var oneOverMercatorHeight = 0.0;
  1832. var useWebMercatorProjection = false;
  1833. if (frameState.mode !== SceneMode.SCENE3D) {
  1834. var projection = frameState.mapProjection;
  1835. var southwest = projection.project(
  1836. Rectangle.southwest(tile.rectangle),
  1837. southwestScratch
  1838. );
  1839. var northeast = projection.project(
  1840. Rectangle.northeast(tile.rectangle),
  1841. northeastScratch
  1842. );
  1843. tileRectangle.x = southwest.x;
  1844. tileRectangle.y = southwest.y;
  1845. tileRectangle.z = northeast.x;
  1846. tileRectangle.w = northeast.y;
  1847. // In 2D and Columbus View, use the center of the tile for RTC rendering.
  1848. if (frameState.mode !== SceneMode.MORPHING) {
  1849. rtc = rtcScratch;
  1850. rtc.x = 0.0;
  1851. rtc.y = (tileRectangle.z + tileRectangle.x) * 0.5;
  1852. rtc.z = (tileRectangle.w + tileRectangle.y) * 0.5;
  1853. tileRectangle.x -= rtc.y;
  1854. tileRectangle.y -= rtc.z;
  1855. tileRectangle.z -= rtc.y;
  1856. tileRectangle.w -= rtc.z;
  1857. }
  1858. if (
  1859. frameState.mode === SceneMode.SCENE2D &&
  1860. encoding.quantization === TerrainQuantization.BITS12
  1861. ) {
  1862. // In 2D, the texture coordinates of the tile are interpolated over the rectangle to get the position in the vertex shader.
  1863. // When the texture coordinates are quantized, error is introduced. This can be seen through the 1px wide cracking
  1864. // between the quantized tiles in 2D. To compensate for the error, move the expand the rectangle in each direction by
  1865. // half the error amount.
  1866. var epsilon = (1.0 / (Math.pow(2.0, 12.0) - 1.0)) * 0.5;
  1867. var widthEpsilon = (tileRectangle.z - tileRectangle.x) * epsilon;
  1868. var heightEpsilon = (tileRectangle.w - tileRectangle.y) * epsilon;
  1869. tileRectangle.x -= widthEpsilon;
  1870. tileRectangle.y -= heightEpsilon;
  1871. tileRectangle.z += widthEpsilon;
  1872. tileRectangle.w += heightEpsilon;
  1873. }
  1874. if (projection instanceof WebMercatorProjection) {
  1875. southLatitude = tile.rectangle.south;
  1876. northLatitude = tile.rectangle.north;
  1877. southMercatorY = WebMercatorProjection.geodeticLatitudeToMercatorAngle(
  1878. southLatitude
  1879. );
  1880. oneOverMercatorHeight =
  1881. 1.0 /
  1882. (WebMercatorProjection.geodeticLatitudeToMercatorAngle(northLatitude) -
  1883. southMercatorY);
  1884. useWebMercatorProjection = true;
  1885. }
  1886. }
  1887. var surfaceShaderSetOptions = surfaceShaderSetOptionsScratch;
  1888. surfaceShaderSetOptions.frameState = frameState;
  1889. surfaceShaderSetOptions.surfaceTile = surfaceTile;
  1890. surfaceShaderSetOptions.showReflectiveOcean = showReflectiveOcean;
  1891. surfaceShaderSetOptions.showOceanWaves = showOceanWaves;
  1892. surfaceShaderSetOptions.enableLighting = tileProvider.enableLighting;
  1893. surfaceShaderSetOptions.dynamicAtmosphereLighting =
  1894. tileProvider.dynamicAtmosphereLighting;
  1895. surfaceShaderSetOptions.dynamicAtmosphereLightingFromSun =
  1896. tileProvider.dynamicAtmosphereLightingFromSun;
  1897. surfaceShaderSetOptions.showGroundAtmosphere = showGroundAtmosphere;
  1898. surfaceShaderSetOptions.perFragmentGroundAtmosphere = perFragmentGroundAtmosphere;
  1899. surfaceShaderSetOptions.hasVertexNormals = hasVertexNormals;
  1900. surfaceShaderSetOptions.useWebMercatorProjection = useWebMercatorProjection;
  1901. surfaceShaderSetOptions.clippedByBoundaries = surfaceTile.clippedByBoundaries;
  1902. var tileImageryCollection = surfaceTile.imagery;
  1903. var imageryIndex = 0;
  1904. var imageryLen = tileImageryCollection.length;
  1905. var showSkirts =
  1906. tileProvider.showSkirts && !cameraUnderground && !translucent;
  1907. var backFaceCulling =
  1908. tileProvider.backFaceCulling && !cameraUnderground && !translucent;
  1909. var firstPassRenderState = backFaceCulling
  1910. ? tileProvider._renderState
  1911. : tileProvider._disableCullingRenderState;
  1912. var otherPassesRenderState = backFaceCulling
  1913. ? tileProvider._blendRenderState
  1914. : tileProvider._disableCullingBlendRenderState;
  1915. var renderState = firstPassRenderState;
  1916. var initialColor = tileProvider._firstPassInitialColor;
  1917. var context = frameState.context;
  1918. if (!defined(tileProvider._debug.boundingSphereTile)) {
  1919. debugDestroyPrimitive();
  1920. }
  1921. var materialUniformMapChanged =
  1922. tileProvider._materialUniformMap !== tileProvider.materialUniformMap;
  1923. if (materialUniformMapChanged) {
  1924. tileProvider._materialUniformMap = tileProvider.materialUniformMap;
  1925. var drawCommandsLength = tileProvider._drawCommands.length;
  1926. for (var i = 0; i < drawCommandsLength; ++i) {
  1927. tileProvider._uniformMaps[i] = createTileUniformMap(
  1928. frameState,
  1929. tileProvider
  1930. );
  1931. }
  1932. }
  1933. do {
  1934. var numberOfDayTextures = 0;
  1935. var command;
  1936. var uniformMap;
  1937. if (tileProvider._drawCommands.length <= tileProvider._usedDrawCommands) {
  1938. command = new DrawCommand();
  1939. command.owner = tile;
  1940. command.cull = false;
  1941. command.boundingVolume = new BoundingSphere();
  1942. command.orientedBoundingBox = undefined;
  1943. uniformMap = createTileUniformMap(frameState, tileProvider);
  1944. tileProvider._drawCommands.push(command);
  1945. tileProvider._uniformMaps.push(uniformMap);
  1946. } else {
  1947. command = tileProvider._drawCommands[tileProvider._usedDrawCommands];
  1948. uniformMap = tileProvider._uniformMaps[tileProvider._usedDrawCommands];
  1949. }
  1950. command.owner = tile;
  1951. ++tileProvider._usedDrawCommands;
  1952. if (tile === tileProvider._debug.boundingSphereTile) {
  1953. var obb = surfaceTile.orientedBoundingBox;
  1954. // If a debug primitive already exists for this tile, it will not be
  1955. // re-created, to avoid allocation every frame. If it were possible
  1956. // to have more than one selected tile, this would have to change.
  1957. if (defined(obb)) {
  1958. getDebugOrientedBoundingBox(obb, Color.RED).update(frameState);
  1959. } else if (defined(mesh) && defined(mesh.boundingSphere3D)) {
  1960. getDebugBoundingSphere(mesh.boundingSphere3D, Color.RED).update(
  1961. frameState
  1962. );
  1963. }
  1964. }
  1965. var uniformMapProperties = uniformMap.properties;
  1966. Cartesian4.clone(initialColor, uniformMapProperties.initialColor);
  1967. uniformMapProperties.oceanNormalMap = oceanNormalMap;
  1968. uniformMapProperties.lightingFadeDistance.x =
  1969. tileProvider.lightingFadeOutDistance;
  1970. uniformMapProperties.lightingFadeDistance.y =
  1971. tileProvider.lightingFadeInDistance;
  1972. uniformMapProperties.nightFadeDistance.x =
  1973. tileProvider.nightFadeOutDistance;
  1974. uniformMapProperties.nightFadeDistance.y = tileProvider.nightFadeInDistance;
  1975. uniformMapProperties.zoomedOutOceanSpecularIntensity =
  1976. tileProvider.zoomedOutOceanSpecularIntensity;
  1977. var frontFaceAlphaByDistanceFinal = cameraUnderground
  1978. ? backFaceAlphaByDistance
  1979. : frontFaceAlphaByDistance;
  1980. var backFaceAlphaByDistanceFinal = cameraUnderground
  1981. ? frontFaceAlphaByDistance
  1982. : backFaceAlphaByDistance;
  1983. if (defined(frontFaceAlphaByDistanceFinal)) {
  1984. Cartesian4.fromElements(
  1985. frontFaceAlphaByDistanceFinal.near,
  1986. frontFaceAlphaByDistanceFinal.nearValue,
  1987. frontFaceAlphaByDistanceFinal.far,
  1988. frontFaceAlphaByDistanceFinal.farValue,
  1989. uniformMapProperties.frontFaceAlphaByDistance
  1990. );
  1991. Cartesian4.fromElements(
  1992. backFaceAlphaByDistanceFinal.near,
  1993. backFaceAlphaByDistanceFinal.nearValue,
  1994. backFaceAlphaByDistanceFinal.far,
  1995. backFaceAlphaByDistanceFinal.farValue,
  1996. uniformMapProperties.backFaceAlphaByDistance
  1997. );
  1998. }
  1999. Cartesian4.fromElements(
  2000. undergroundColorAlphaByDistance.near,
  2001. undergroundColorAlphaByDistance.nearValue,
  2002. undergroundColorAlphaByDistance.far,
  2003. undergroundColorAlphaByDistance.farValue,
  2004. uniformMapProperties.undergroundColorAlphaByDistance
  2005. );
  2006. Color.clone(undergroundColor, uniformMapProperties.undergroundColor);
  2007. var highlightFillTile =
  2008. !defined(surfaceTile.vertexArray) &&
  2009. defined(tileProvider.fillHighlightColor) &&
  2010. tileProvider.fillHighlightColor.alpha > 0.0;
  2011. if (highlightFillTile) {
  2012. Color.clone(
  2013. tileProvider.fillHighlightColor,
  2014. uniformMapProperties.fillHighlightColor
  2015. );
  2016. }
  2017. uniformMapProperties.center3D = mesh.center;
  2018. Cartesian3.clone(rtc, uniformMapProperties.rtc);
  2019. Cartesian4.clone(tileRectangle, uniformMapProperties.tileRectangle);
  2020. uniformMapProperties.southAndNorthLatitude.x = southLatitude;
  2021. uniformMapProperties.southAndNorthLatitude.y = northLatitude;
  2022. uniformMapProperties.southMercatorYAndOneOverHeight.x = southMercatorY;
  2023. uniformMapProperties.southMercatorYAndOneOverHeight.y = oneOverMercatorHeight;
  2024. // Convert tile limiter rectangle from cartographic to texture space using the tileRectangle.
  2025. var localizedCartographicLimitRectangle = localizedCartographicLimitRectangleScratch;
  2026. var cartographicLimitRectangle = clipRectangleAntimeridian(
  2027. tile.rectangle,
  2028. tileProvider.cartographicLimitRectangle
  2029. );
  2030. var localizedTranslucencyRectangle = localizedTranslucencyRectangleScratch;
  2031. var clippedTranslucencyRectangle = clipRectangleAntimeridian(
  2032. tile.rectangle,
  2033. translucencyRectangle
  2034. );
  2035. Cartesian3.fromElements(
  2036. hueShift,
  2037. saturationShift,
  2038. brightnessShift,
  2039. uniformMapProperties.hsbShift
  2040. );
  2041. var cartographicTileRectangle = tile.rectangle;
  2042. var inverseTileWidth = 1.0 / cartographicTileRectangle.width;
  2043. var inverseTileHeight = 1.0 / cartographicTileRectangle.height;
  2044. localizedCartographicLimitRectangle.x =
  2045. (cartographicLimitRectangle.west - cartographicTileRectangle.west) *
  2046. inverseTileWidth;
  2047. localizedCartographicLimitRectangle.y =
  2048. (cartographicLimitRectangle.south - cartographicTileRectangle.south) *
  2049. inverseTileHeight;
  2050. localizedCartographicLimitRectangle.z =
  2051. (cartographicLimitRectangle.east - cartographicTileRectangle.west) *
  2052. inverseTileWidth;
  2053. localizedCartographicLimitRectangle.w =
  2054. (cartographicLimitRectangle.north - cartographicTileRectangle.south) *
  2055. inverseTileHeight;
  2056. Cartesian4.clone(
  2057. localizedCartographicLimitRectangle,
  2058. uniformMapProperties.localizedCartographicLimitRectangle
  2059. );
  2060. localizedTranslucencyRectangle.x =
  2061. (clippedTranslucencyRectangle.west - cartographicTileRectangle.west) *
  2062. inverseTileWidth;
  2063. localizedTranslucencyRectangle.y =
  2064. (clippedTranslucencyRectangle.south - cartographicTileRectangle.south) *
  2065. inverseTileHeight;
  2066. localizedTranslucencyRectangle.z =
  2067. (clippedTranslucencyRectangle.east - cartographicTileRectangle.west) *
  2068. inverseTileWidth;
  2069. localizedTranslucencyRectangle.w =
  2070. (clippedTranslucencyRectangle.north - cartographicTileRectangle.south) *
  2071. inverseTileHeight;
  2072. Cartesian4.clone(
  2073. localizedTranslucencyRectangle,
  2074. uniformMapProperties.localizedTranslucencyRectangle
  2075. );
  2076. // For performance, use fog in the shader only when the tile is in fog.
  2077. var applyFog =
  2078. enableFog &&
  2079. CesiumMath.fog(tile._distance, frameState.fog.density) >
  2080. CesiumMath.EPSILON3;
  2081. colorCorrect = colorCorrect && (applyFog || showGroundAtmosphere);
  2082. var applyBrightness = false;
  2083. var applyContrast = false;
  2084. var applyHue = false;
  2085. var applySaturation = false;
  2086. var applyGamma = false;
  2087. var applyAlpha = false;
  2088. var applyDayNightAlpha = false;
  2089. var applySplit = false;
  2090. var applyCutout = false;
  2091. var applyColorToAlpha = false;
  2092. while (numberOfDayTextures < maxTextures && imageryIndex < imageryLen) {
  2093. var tileImagery = tileImageryCollection[imageryIndex];
  2094. var imagery = tileImagery.readyImagery;
  2095. ++imageryIndex;
  2096. if (!defined(imagery) || imagery.imageryLayer.alpha === 0.0) {
  2097. continue;
  2098. }
  2099. var texture = tileImagery.useWebMercatorT
  2100. ? imagery.textureWebMercator
  2101. : imagery.texture;
  2102. //>>includeStart('debug', pragmas.debug);
  2103. if (!defined(texture)) {
  2104. // Our "ready" texture isn't actually ready. This should never happen.
  2105. //
  2106. // Side note: It IS possible for it to not be in the READY ImageryState, though.
  2107. // This can happen when a single imagery tile is shared by two terrain tiles (common)
  2108. // and one of them (A) needs a geographic version of the tile because it is near the poles,
  2109. // and the other (B) does not. B can and will transition the imagery tile to the READY state
  2110. // without reprojecting to geographic. Then, later, A will deem that same tile not-ready-yet
  2111. // because it only has the Web Mercator texture, and flip it back to the TRANSITIONING state.
  2112. // The imagery tile won't be in the READY state anymore, but it's still READY enough for B's
  2113. // purposes.
  2114. throw new DeveloperError("readyImagery is not actually ready!");
  2115. }
  2116. //>>includeEnd('debug');
  2117. var imageryLayer = imagery.imageryLayer;
  2118. if (!defined(tileImagery.textureTranslationAndScale)) {
  2119. tileImagery.textureTranslationAndScale = imageryLayer._calculateTextureTranslationAndScale(
  2120. tile,
  2121. tileImagery
  2122. );
  2123. }
  2124. uniformMapProperties.dayTextures[numberOfDayTextures] = texture;
  2125. uniformMapProperties.dayTextureTranslationAndScale[numberOfDayTextures] =
  2126. tileImagery.textureTranslationAndScale;
  2127. uniformMapProperties.dayTextureTexCoordsRectangle[numberOfDayTextures] =
  2128. tileImagery.textureCoordinateRectangle;
  2129. uniformMapProperties.dayTextureUseWebMercatorT[numberOfDayTextures] =
  2130. tileImagery.useWebMercatorT;
  2131. uniformMapProperties.dayTextureAlpha[numberOfDayTextures] =
  2132. imageryLayer.alpha;
  2133. applyAlpha =
  2134. applyAlpha ||
  2135. uniformMapProperties.dayTextureAlpha[numberOfDayTextures] !== 1.0;
  2136. uniformMapProperties.dayTextureNightAlpha[numberOfDayTextures] =
  2137. imageryLayer.nightAlpha;
  2138. applyDayNightAlpha =
  2139. applyDayNightAlpha ||
  2140. uniformMapProperties.dayTextureNightAlpha[numberOfDayTextures] !== 1.0;
  2141. uniformMapProperties.dayTextureDayAlpha[numberOfDayTextures] =
  2142. imageryLayer.dayAlpha;
  2143. applyDayNightAlpha =
  2144. applyDayNightAlpha ||
  2145. uniformMapProperties.dayTextureDayAlpha[numberOfDayTextures] !== 1.0;
  2146. uniformMapProperties.dayTextureBrightness[numberOfDayTextures] =
  2147. imageryLayer.brightness;
  2148. applyBrightness =
  2149. applyBrightness ||
  2150. uniformMapProperties.dayTextureBrightness[numberOfDayTextures] !==
  2151. ImageryLayer.DEFAULT_BRIGHTNESS;
  2152. uniformMapProperties.dayTextureContrast[numberOfDayTextures] =
  2153. imageryLayer.contrast;
  2154. applyContrast =
  2155. applyContrast ||
  2156. uniformMapProperties.dayTextureContrast[numberOfDayTextures] !==
  2157. ImageryLayer.DEFAULT_CONTRAST;
  2158. uniformMapProperties.dayTextureHue[numberOfDayTextures] =
  2159. imageryLayer.hue;
  2160. applyHue =
  2161. applyHue ||
  2162. uniformMapProperties.dayTextureHue[numberOfDayTextures] !==
  2163. ImageryLayer.DEFAULT_HUE;
  2164. uniformMapProperties.dayTextureSaturation[numberOfDayTextures] =
  2165. imageryLayer.saturation;
  2166. applySaturation =
  2167. applySaturation ||
  2168. uniformMapProperties.dayTextureSaturation[numberOfDayTextures] !==
  2169. ImageryLayer.DEFAULT_SATURATION;
  2170. uniformMapProperties.dayTextureOneOverGamma[numberOfDayTextures] =
  2171. 1.0 / imageryLayer.gamma;
  2172. applyGamma =
  2173. applyGamma ||
  2174. uniformMapProperties.dayTextureOneOverGamma[numberOfDayTextures] !==
  2175. 1.0 / ImageryLayer.DEFAULT_GAMMA;
  2176. uniformMapProperties.dayTextureSplit[numberOfDayTextures] =
  2177. imageryLayer.splitDirection;
  2178. applySplit =
  2179. applySplit ||
  2180. uniformMapProperties.dayTextureSplit[numberOfDayTextures] !== 0.0;
  2181. // Update cutout rectangle
  2182. var dayTextureCutoutRectangle =
  2183. uniformMapProperties.dayTextureCutoutRectangles[numberOfDayTextures];
  2184. if (!defined(dayTextureCutoutRectangle)) {
  2185. dayTextureCutoutRectangle = uniformMapProperties.dayTextureCutoutRectangles[
  2186. numberOfDayTextures
  2187. ] = new Cartesian4();
  2188. }
  2189. Cartesian4.clone(Cartesian4.ZERO, dayTextureCutoutRectangle);
  2190. if (defined(imageryLayer.cutoutRectangle)) {
  2191. var cutoutRectangle = clipRectangleAntimeridian(
  2192. cartographicTileRectangle,
  2193. imageryLayer.cutoutRectangle
  2194. );
  2195. var intersection = Rectangle.simpleIntersection(
  2196. cutoutRectangle,
  2197. cartographicTileRectangle,
  2198. rectangleIntersectionScratch
  2199. );
  2200. applyCutout = defined(intersection) || applyCutout;
  2201. dayTextureCutoutRectangle.x =
  2202. (cutoutRectangle.west - cartographicTileRectangle.west) *
  2203. inverseTileWidth;
  2204. dayTextureCutoutRectangle.y =
  2205. (cutoutRectangle.south - cartographicTileRectangle.south) *
  2206. inverseTileHeight;
  2207. dayTextureCutoutRectangle.z =
  2208. (cutoutRectangle.east - cartographicTileRectangle.west) *
  2209. inverseTileWidth;
  2210. dayTextureCutoutRectangle.w =
  2211. (cutoutRectangle.north - cartographicTileRectangle.south) *
  2212. inverseTileHeight;
  2213. }
  2214. // Update color to alpha
  2215. var colorToAlpha =
  2216. uniformMapProperties.colorsToAlpha[numberOfDayTextures];
  2217. if (!defined(colorToAlpha)) {
  2218. colorToAlpha = uniformMapProperties.colorsToAlpha[
  2219. numberOfDayTextures
  2220. ] = new Cartesian4();
  2221. }
  2222. var hasColorToAlpha =
  2223. defined(imageryLayer.colorToAlpha) &&
  2224. imageryLayer.colorToAlphaThreshold > 0.0;
  2225. applyColorToAlpha = applyColorToAlpha || hasColorToAlpha;
  2226. if (hasColorToAlpha) {
  2227. var color = imageryLayer.colorToAlpha;
  2228. colorToAlpha.x = color.red;
  2229. colorToAlpha.y = color.green;
  2230. colorToAlpha.z = color.blue;
  2231. colorToAlpha.w = imageryLayer.colorToAlphaThreshold;
  2232. } else {
  2233. colorToAlpha.w = -1.0;
  2234. }
  2235. if (defined(imagery.credits)) {
  2236. var credits = imagery.credits;
  2237. for (
  2238. var creditIndex = 0, creditLength = credits.length;
  2239. creditIndex < creditLength;
  2240. ++creditIndex
  2241. ) {
  2242. creditDisplay.addCredit(credits[creditIndex]);
  2243. }
  2244. }
  2245. ++numberOfDayTextures;
  2246. }
  2247. // trim texture array to the used length so we don't end up using old textures
  2248. // which might get destroyed eventually
  2249. uniformMapProperties.dayTextures.length = numberOfDayTextures;
  2250. uniformMapProperties.waterMask = waterMaskTexture;
  2251. Cartesian4.clone(
  2252. waterMaskTranslationAndScale,
  2253. uniformMapProperties.waterMaskTranslationAndScale
  2254. );
  2255. uniformMapProperties.minMaxHeight.x = encoding.minimumHeight;
  2256. uniformMapProperties.minMaxHeight.y = encoding.maximumHeight;
  2257. Matrix4.clone(encoding.matrix, uniformMapProperties.scaleAndBias);
  2258. // update clipping planes
  2259. var clippingPlanes = tileProvider._clippingPlanes;
  2260. var clippingPlanesEnabled =
  2261. defined(clippingPlanes) && clippingPlanes.enabled && tile.isClipped;
  2262. if (clippingPlanesEnabled) {
  2263. uniformMapProperties.clippingPlanesEdgeColor = Color.clone(
  2264. clippingPlanes.edgeColor,
  2265. uniformMapProperties.clippingPlanesEdgeColor
  2266. );
  2267. uniformMapProperties.clippingPlanesEdgeWidth = clippingPlanes.edgeWidth;
  2268. }
  2269. surfaceShaderSetOptions.numberOfDayTextures = numberOfDayTextures;
  2270. surfaceShaderSetOptions.applyBrightness = applyBrightness;
  2271. surfaceShaderSetOptions.applyContrast = applyContrast;
  2272. surfaceShaderSetOptions.applyHue = applyHue;
  2273. surfaceShaderSetOptions.applySaturation = applySaturation;
  2274. surfaceShaderSetOptions.applyGamma = applyGamma;
  2275. surfaceShaderSetOptions.applyAlpha = applyAlpha;
  2276. surfaceShaderSetOptions.applyDayNightAlpha = applyDayNightAlpha;
  2277. surfaceShaderSetOptions.applySplit = applySplit;
  2278. surfaceShaderSetOptions.enableFog = applyFog;
  2279. surfaceShaderSetOptions.enableClippingPlanes = clippingPlanesEnabled;
  2280. surfaceShaderSetOptions.clippingPlanes = clippingPlanes;
  2281. surfaceShaderSetOptions.hasImageryLayerCutout = applyCutout;
  2282. surfaceShaderSetOptions.colorCorrect = colorCorrect;
  2283. surfaceShaderSetOptions.highlightFillTile = highlightFillTile;
  2284. surfaceShaderSetOptions.colorToAlpha = applyColorToAlpha;
  2285. surfaceShaderSetOptions.showUndergroundColor = showUndergroundColor;
  2286. surfaceShaderSetOptions.translucent = translucent;
  2287. var count = surfaceTile.renderedMesh.indices.length;
  2288. if (!showSkirts) {
  2289. count = surfaceTile.renderedMesh.indexCountWithoutSkirts;
  2290. }
  2291. command.shaderProgram = tileProvider._surfaceShaderSet.getShaderProgram(
  2292. surfaceShaderSetOptions
  2293. );
  2294. command.castShadows = castShadows;
  2295. command.receiveShadows = receiveShadows;
  2296. command.renderState = renderState;
  2297. command.primitiveType = PrimitiveType.TRIANGLES;
  2298. command.vertexArray =
  2299. surfaceTile.vertexArray || surfaceTile.fill.vertexArray;
  2300. command.count = count;
  2301. command.uniformMap = uniformMap;
  2302. command.pass = Pass.GLOBE;
  2303. if (tileProvider._debug.wireframe) {
  2304. createWireframeVertexArrayIfNecessary(context, tileProvider, tile);
  2305. if (defined(surfaceTile.wireframeVertexArray)) {
  2306. command.vertexArray = surfaceTile.wireframeVertexArray;
  2307. command.primitiveType = PrimitiveType.LINES;
  2308. command.count = count * 2;
  2309. }
  2310. }
  2311. var boundingVolume = command.boundingVolume;
  2312. var orientedBoundingBox = command.orientedBoundingBox;
  2313. if (frameState.mode !== SceneMode.SCENE3D) {
  2314. var tileBoundingRegion = surfaceTile.tileBoundingRegion;
  2315. BoundingSphere.fromRectangleWithHeights2D(
  2316. tile.rectangle,
  2317. frameState.mapProjection,
  2318. tileBoundingRegion.minimumHeight,
  2319. tileBoundingRegion.maximumHeight,
  2320. boundingVolume
  2321. );
  2322. Cartesian3.fromElements(
  2323. boundingVolume.center.z,
  2324. boundingVolume.center.x,
  2325. boundingVolume.center.y,
  2326. boundingVolume.center
  2327. );
  2328. if (frameState.mode === SceneMode.MORPHING) {
  2329. boundingVolume = BoundingSphere.union(
  2330. mesh.boundingSphere3D,
  2331. boundingVolume,
  2332. boundingVolume
  2333. );
  2334. }
  2335. } else {
  2336. command.boundingVolume = BoundingSphere.clone(
  2337. mesh.boundingSphere3D,
  2338. boundingVolume
  2339. );
  2340. command.orientedBoundingBox = OrientedBoundingBox.clone(
  2341. surfaceTile.orientedBoundingBox,
  2342. orientedBoundingBox
  2343. );
  2344. }
  2345. command.dirty = true;
  2346. if (translucent) {
  2347. globeTranslucencyState.updateDerivedCommands(command, frameState);
  2348. }
  2349. pushCommand(command, frameState);
  2350. renderState = otherPassesRenderState;
  2351. initialColor = otherPassesInitialColor;
  2352. } while (imageryIndex < imageryLen);
  2353. }
  2354. export default GlobeSurfaceTileProvider;