GlobeSurfaceTileProvider.js 95 KB

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