智慧水务管理系统 - 精河县供水工程综合管理平台

GlobeSurfaceTileProvider.js 98KB

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