GlobeSurfaceTileProvider.js 94 KB

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