Cesium3DTileset.js 94 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640
  1. import ApproximateTerrainHeights from "../Core/ApproximateTerrainHeights.js";
  2. import Cartesian2 from "../Core/Cartesian2.js";
  3. import Cartesian3 from "../Core/Cartesian3.js";
  4. import Cartographic from "../Core/Cartographic.js";
  5. import Check from "../Core/Check.js";
  6. import Credit from "../Core/Credit.js";
  7. import defaultValue from "../Core/defaultValue.js";
  8. import defined from "../Core/defined.js";
  9. import deprecationWarning from "../Core/deprecationWarning.js";
  10. import destroyObject from "../Core/destroyObject.js";
  11. import DeveloperError from "../Core/DeveloperError.js";
  12. import Ellipsoid from "../Core/Ellipsoid.js";
  13. import Event from "../Core/Event.js";
  14. import JulianDate from "../Core/JulianDate.js";
  15. import ManagedArray from "../Core/ManagedArray.js";
  16. import CesiumMath from "../Core/Math.js";
  17. import Matrix4 from "../Core/Matrix4.js";
  18. import Resource from "../Core/Resource.js";
  19. import RuntimeError from "../Core/RuntimeError.js";
  20. import Transforms from "../Core/Transforms.js";
  21. import ClearCommand from "../Renderer/ClearCommand.js";
  22. import Pass from "../Renderer/Pass.js";
  23. import RenderState from "../Renderer/RenderState.js";
  24. import when from "../ThirdParty/when.js";
  25. import Axis from "./Axis.js";
  26. import Cesium3DTile from "./Cesium3DTile.js";
  27. import Cesium3DTileColorBlendMode from "./Cesium3DTileColorBlendMode.js";
  28. import Cesium3DTileContentState from "./Cesium3DTileContentState.js";
  29. import Cesium3DTileOptimizations from "./Cesium3DTileOptimizations.js";
  30. import Cesium3DTilePass from "./Cesium3DTilePass.js";
  31. import Cesium3DTileRefine from "./Cesium3DTileRefine.js";
  32. import Cesium3DTilesetCache from "./Cesium3DTilesetCache.js";
  33. import Cesium3DTilesetHeatmap from "./Cesium3DTilesetHeatmap.js";
  34. import Cesium3DTilesetStatistics from "./Cesium3DTilesetStatistics.js";
  35. import Cesium3DTileStyleEngine from "./Cesium3DTileStyleEngine.js";
  36. import ClippingPlaneCollection from "./ClippingPlaneCollection.js";
  37. import LabelCollection from "./LabelCollection.js";
  38. import PointCloudEyeDomeLighting from "./PointCloudEyeDomeLighting.js";
  39. import PointCloudShading from "./PointCloudShading.js";
  40. import SceneMode from "./SceneMode.js";
  41. import ShadowMode from "./ShadowMode.js";
  42. import StencilConstants from "./StencilConstants.js";
  43. import TileBoundingRegion from "./TileBoundingRegion.js";
  44. import TileBoundingSphere from "./TileBoundingSphere.js";
  45. import TileOrientedBoundingBox from "./TileOrientedBoundingBox.js";
  46. /**
  47. * A {@link https://github.com/CesiumGS/3d-tiles/tree/master/specification|3D Tiles tileset},
  48. * used for streaming massive heterogeneous 3D geospatial datasets.
  49. *
  50. * @alias Cesium3DTileset
  51. * @constructor
  52. *
  53. * @param {Object} options Object with the following properties:
  54. * @param {Resource|String|Promise<Resource>|Promise<String>} options.url The url to a tileset JSON file.
  55. * @param {Boolean} [options.show=true] Determines if the tileset will be shown.
  56. * @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] A 4x4 transformation matrix that transforms the tileset's root tile.
  57. * @param {ShadowMode} [options.shadows=ShadowMode.ENABLED] Determines whether the tileset casts or receives shadows from light sources.
  58. * @param {Number} [options.maximumScreenSpaceError=16] The maximum screen space error used to drive level of detail refinement.
  59. * @param {Number} [options.maximumMemoryUsage=512] The maximum amount of memory in MB that can be used by the tileset.
  60. * @param {Boolean} [options.cullWithChildrenBounds=true] Optimization option. Whether to cull tiles using the union of their children bounding volumes.
  61. * @param {Boolean} [options.cullRequestsWhileMoving=true] Optimization option. Don't request tiles that will likely be unused when they come back because of the camera's movement. This optimization only applies to stationary tilesets.
  62. * @param {Number} [options.cullRequestsWhileMovingMultiplier=60.0] Optimization option. Multiplier used in culling requests while moving. Larger is more aggressive culling, smaller less aggressive culling.
  63. * @param {Boolean} [options.preloadWhenHidden=false] Preload tiles when <code>tileset.show</code> is <code>false</code>. Loads tiles as if the tileset is visible but does not render them.
  64. * @param {Boolean} [options.preloadFlightDestinations=true] Optimization option. Preload tiles at the camera's flight destination while the camera is in flight.
  65. * @param {Boolean} [options.preferLeaves=false] Optimization option. Prefer loading of leaves first.
  66. * @param {Boolean} [options.dynamicScreenSpaceError=false] Optimization option. Reduce the screen space error for tiles that are further away from the camera.
  67. * @param {Number} [options.dynamicScreenSpaceErrorDensity=0.00278] Density used to adjust the dynamic screen space error, similar to fog density.
  68. * @param {Number} [options.dynamicScreenSpaceErrorFactor=4.0] A factor used to increase the computed dynamic screen space error.
  69. * @param {Number} [options.dynamicScreenSpaceErrorHeightFalloff=0.25] A ratio of the tileset's height at which the density starts to falloff.
  70. * @param {Number} [options.progressiveResolutionHeightFraction=0.3] Optimization option. If between (0.0, 0.5], tiles at or above the screen space error for the reduced screen resolution of <code>progressiveResolutionHeightFraction*screenHeight</code> will be prioritized first. This can help get a quick layer of tiles down while full resolution tiles continue to load.
  71. * @param {Boolean} [options.foveatedScreenSpaceError=true] Optimization option. Prioritize loading tiles in the center of the screen by temporarily raising the screen space error for tiles around the edge of the screen. Screen space error returns to normal once all the tiles in the center of the screen as determined by the {@link Cesium3DTileset#foveatedConeSize} are loaded.
  72. * @param {Number} [options.foveatedConeSize=0.1] Optimization option. Used when {@link Cesium3DTileset#foveatedScreenSpaceError} is true to control the cone size that determines which tiles are deferred. Tiles that are inside this cone are loaded immediately. Tiles outside the cone are potentially deferred based on how far outside the cone they are and their screen space error. This is controlled by {@link Cesium3DTileset#foveatedInterpolationCallback} and {@link Cesium3DTileset#foveatedMinimumScreenSpaceErrorRelaxation}. Setting this to 0.0 means the cone will be the line formed by the camera position and its view direction. Setting this to 1.0 means the cone encompasses the entire field of view of the camera, disabling the effect.
  73. * @param {Number} [options.foveatedMinimumScreenSpaceErrorRelaxation=0.0] Optimization option. Used when {@link Cesium3DTileset#foveatedScreenSpaceError} is true to control the starting screen space error relaxation for tiles outside the foveated cone. The screen space error will be raised starting with tileset value up to {@link Cesium3DTileset#maximumScreenSpaceError} based on the provided {@link Cesium3DTileset#foveatedInterpolationCallback}.
  74. * @param {Cesium3DTileset.foveatedInterpolationCallback} [options.foveatedInterpolationCallback=Math.lerp] Optimization option. Used when {@link Cesium3DTileset#foveatedScreenSpaceError} is true to control how much to raise the screen space error for tiles outside the foveated cone, interpolating between {@link Cesium3DTileset#foveatedMinimumScreenSpaceErrorRelaxation} and {@link Cesium3DTileset#maximumScreenSpaceError}
  75. * @param {Number} [options.foveatedTimeDelay=0.2] Optimization option. Used when {@link Cesium3DTileset#foveatedScreenSpaceError} is true to control how long in seconds to wait after the camera stops moving before deferred tiles start loading in. This time delay prevents requesting tiles around the edges of the screen when the camera is moving. Setting this to 0.0 will immediately request all tiles in any given view.
  76. * @param {Boolean} [options.skipLevelOfDetail=false] Optimization option. Determines if level of detail skipping should be applied during the traversal.
  77. * @param {Number} [options.baseScreenSpaceError=1024] When <code>skipLevelOfDetail</code> is <code>true</code>, the screen space error that must be reached before skipping levels of detail.
  78. * @param {Number} [options.skipScreenSpaceErrorFactor=16] When <code>skipLevelOfDetail</code> is <code>true</code>, a multiplier defining the minimum screen space error to skip. Used in conjunction with <code>skipLevels</code> to determine which tiles to load.
  79. * @param {Number} [options.skipLevels=1] When <code>skipLevelOfDetail</code> is <code>true</code>, a constant defining the minimum number of levels to skip when loading tiles. When it is 0, no levels are skipped. Used in conjunction with <code>skipScreenSpaceErrorFactor</code> to determine which tiles to load.
  80. * @param {Boolean} [options.immediatelyLoadDesiredLevelOfDetail=false] When <code>skipLevelOfDetail</code> is <code>true</code>, only tiles that meet the maximum screen space error will ever be downloaded. Skipping factors are ignored and just the desired tiles are loaded.
  81. * @param {Boolean} [options.loadSiblings=false] When <code>skipLevelOfDetail</code> is <code>true</code>, determines whether siblings of visible tiles are always downloaded during traversal.
  82. * @param {ClippingPlaneCollection} [options.clippingPlanes] The {@link ClippingPlaneCollection} used to selectively disable rendering the tileset.
  83. * @param {ClassificationType} [options.classificationType] Determines whether terrain, 3D Tiles or both will be classified by this tileset. See {@link Cesium3DTileset#classificationType} for details about restrictions and limitations.
  84. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid determining the size and shape of the globe.
  85. * @param {Object} [options.pointCloudShading] Options for constructing a {@link PointCloudShading} object to control point attenuation based on geometric error and lighting.
  86. * @param {Cartesian2} [options.imageBasedLightingFactor=new Cartesian2(1.0, 1.0)] Scales the diffuse and specular image-based lighting from the earth, sky, atmosphere and star skybox.
  87. * @param {Cartesian3} [options.lightColor] The light color when shading models. When <code>undefined</code> the scene's light color is used instead.
  88. * @param {Number} [options.luminanceAtZenith=0.2] The sun's luminance at the zenith in kilo candela per meter squared to use for this model's procedural environment map.
  89. * @param {Cartesian3[]} [options.sphericalHarmonicCoefficients] The third order spherical harmonic coefficients used for the diffuse color of image-based lighting.
  90. * @param {String} [options.specularEnvironmentMaps] A URL to a KTX file that contains a cube map of the specular lighting and the convoluted specular mipmaps.
  91. * @param {Boolean} [options.backFaceCulling=true] Whether to cull back-facing geometry. When true, back face culling is determined by the glTF material's doubleSided property; when false, back face culling is disabled.
  92. * @param {String} [options.debugHeatmapTilePropertyName] The tile variable to colorize as a heatmap. All rendered tiles will be colorized relative to each other's specified variable value.
  93. * @param {Boolean} [options.debugFreezeFrame=false] For debugging only. Determines if only the tiles from last frame should be used for rendering.
  94. * @param {Boolean} [options.debugColorizeTiles=false] For debugging only. When true, assigns a random color to each tile.
  95. * @param {Boolean} [options.debugWireframe=false] For debugging only. When true, render's each tile's content as a wireframe.
  96. * @param {Boolean} [options.debugShowBoundingVolume=false] For debugging only. When true, renders the bounding volume for each tile.
  97. * @param {Boolean} [options.debugShowContentBoundingVolume=false] For debugging only. When true, renders the bounding volume for each tile's content.
  98. * @param {Boolean} [options.debugShowViewerRequestVolume=false] For debugging only. When true, renders the viewer request volume for each tile.
  99. * @param {Boolean} [options.debugShowGeometricError=false] For debugging only. When true, draws labels to indicate the geometric error of each tile.
  100. * @param {Boolean} [options.debugShowRenderingStatistics=false] For debugging only. When true, draws labels to indicate the number of commands, points, triangles and features for each tile.
  101. * @param {Boolean} [options.debugShowMemoryUsage=false] For debugging only. When true, draws labels to indicate the texture and geometry memory in megabytes used by each tile.
  102. * @param {Boolean} [options.debugShowUrl=false] For debugging only. When true, draws labels to indicate the url of each tile.
  103. *
  104. * @exception {DeveloperError} The tileset must be 3D Tiles version 0.0 or 1.0.
  105. *
  106. * @example
  107. * var tileset = scene.primitives.add(new Cesium.Cesium3DTileset({
  108. * url : 'http://localhost:8002/tilesets/Seattle/tileset.json'
  109. * }));
  110. *
  111. * @example
  112. * // Common setting for the skipLevelOfDetail optimization
  113. * var tileset = scene.primitives.add(new Cesium.Cesium3DTileset({
  114. * url : 'http://localhost:8002/tilesets/Seattle/tileset.json',
  115. * skipLevelOfDetail : true,
  116. * baseScreenSpaceError : 1024,
  117. * skipScreenSpaceErrorFactor : 16,
  118. * skipLevels : 1,
  119. * immediatelyLoadDesiredLevelOfDetail : false,
  120. * loadSiblings : false,
  121. * cullWithChildrenBounds : true
  122. * }));
  123. *
  124. * @example
  125. * // Common settings for the dynamicScreenSpaceError optimization
  126. * var tileset = scene.primitives.add(new Cesium.Cesium3DTileset({
  127. * url : 'http://localhost:8002/tilesets/Seattle/tileset.json',
  128. * dynamicScreenSpaceError : true,
  129. * dynamicScreenSpaceErrorDensity : 0.00278,
  130. * dynamicScreenSpaceErrorFactor : 4.0,
  131. * dynamicScreenSpaceErrorHeightFalloff : 0.25
  132. * }));
  133. *
  134. * @see {@link https://github.com/CesiumGS/3d-tiles/tree/master/specification|3D Tiles specification}
  135. */
  136. function Cesium3DTileset(options) {
  137. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  138. //>>includeStart('debug', pragmas.debug);
  139. Check.defined("options.url", options.url);
  140. //>>includeEnd('debug');
  141. this._url = undefined;
  142. this._basePath = undefined;
  143. this._root = undefined;
  144. this._asset = undefined; // Metadata for the entire tileset
  145. this._properties = undefined; // Metadata for per-model/point/etc properties
  146. this._geometricError = undefined; // Geometric error when the tree is not rendered at all
  147. this._extensionsUsed = undefined;
  148. this._extensions = undefined;
  149. this._gltfUpAxis = undefined;
  150. this._cache = new Cesium3DTilesetCache();
  151. this._processingQueue = [];
  152. this._selectedTiles = [];
  153. this._emptyTiles = [];
  154. this._requestedTiles = [];
  155. this._selectedTilesToStyle = [];
  156. this._loadTimestamp = undefined;
  157. this._timeSinceLoad = 0.0;
  158. this._updatedVisibilityFrame = 0;
  159. this._updatedModelMatrixFrame = 0;
  160. this._modelMatrixChanged = false;
  161. this._previousModelMatrix = undefined;
  162. this._extras = undefined;
  163. this._credits = undefined;
  164. this._cullWithChildrenBounds = defaultValue(
  165. options.cullWithChildrenBounds,
  166. true
  167. );
  168. this._allTilesAdditive = true;
  169. this._hasMixedContent = false;
  170. this._stencilClearCommand = undefined;
  171. this._backfaceCommands = new ManagedArray();
  172. this._maximumScreenSpaceError = defaultValue(
  173. options.maximumScreenSpaceError,
  174. 16
  175. );
  176. this._maximumMemoryUsage = defaultValue(options.maximumMemoryUsage, 512);
  177. this._styleEngine = new Cesium3DTileStyleEngine();
  178. this._modelMatrix = defined(options.modelMatrix)
  179. ? Matrix4.clone(options.modelMatrix)
  180. : Matrix4.clone(Matrix4.IDENTITY);
  181. this._statistics = new Cesium3DTilesetStatistics();
  182. this._statisticsLast = new Cesium3DTilesetStatistics();
  183. this._statisticsPerPass = new Array(Cesium3DTilePass.NUMBER_OF_PASSES);
  184. for (var i = 0; i < Cesium3DTilePass.NUMBER_OF_PASSES; ++i) {
  185. this._statisticsPerPass[i] = new Cesium3DTilesetStatistics();
  186. }
  187. this._requestedTilesInFlight = [];
  188. this._maximumPriority = {
  189. foveatedFactor: -Number.MAX_VALUE,
  190. depth: -Number.MAX_VALUE,
  191. distance: -Number.MAX_VALUE,
  192. reverseScreenSpaceError: -Number.MAX_VALUE,
  193. };
  194. this._minimumPriority = {
  195. foveatedFactor: Number.MAX_VALUE,
  196. depth: Number.MAX_VALUE,
  197. distance: Number.MAX_VALUE,
  198. reverseScreenSpaceError: Number.MAX_VALUE,
  199. };
  200. this._heatmap = new Cesium3DTilesetHeatmap(
  201. options.debugHeatmapTilePropertyName
  202. );
  203. /**
  204. * Optimization option. Don't request tiles that will likely be unused when they come back because of the camera's movement. This optimization only applies to stationary tilesets.
  205. *
  206. * @type {Boolean}
  207. * @default true
  208. */
  209. this.cullRequestsWhileMoving = defaultValue(
  210. options.cullRequestsWhileMoving,
  211. true
  212. );
  213. this._cullRequestsWhileMoving = false;
  214. /**
  215. * Optimization option. Multiplier used in culling requests while moving. Larger is more aggressive culling, smaller less aggressive culling.
  216. *
  217. * @type {Number}
  218. * @default 60.0
  219. */
  220. this.cullRequestsWhileMovingMultiplier = defaultValue(
  221. options.cullRequestsWhileMovingMultiplier,
  222. 60.0
  223. );
  224. /**
  225. * Optimization option. If between (0.0, 0.5], tiles at or above the screen space error for the reduced screen resolution of <code>progressiveResolutionHeightFraction*screenHeight</code> will be prioritized first. This can help get a quick layer of tiles down while full resolution tiles continue to load.
  226. *
  227. * @type {Number}
  228. * @default 0.3
  229. */
  230. this.progressiveResolutionHeightFraction = CesiumMath.clamp(
  231. defaultValue(options.progressiveResolutionHeightFraction, 0.3),
  232. 0.0,
  233. 0.5
  234. );
  235. /**
  236. * Optimization option. Prefer loading of leaves first.
  237. *
  238. * @type {Boolean}
  239. * @default false
  240. */
  241. this.preferLeaves = defaultValue(options.preferLeaves, false);
  242. this._tilesLoaded = false;
  243. this._initialTilesLoaded = false;
  244. this._tileDebugLabels = undefined;
  245. this._readyPromise = when.defer();
  246. this._classificationType = options.classificationType;
  247. this._ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84);
  248. this._initialClippingPlanesOriginMatrix = Matrix4.IDENTITY; // Computed from the tileset JSON.
  249. this._clippingPlanesOriginMatrix = undefined; // Combines the above with any run-time transforms.
  250. this._clippingPlanesOriginMatrixDirty = true;
  251. /**
  252. * Preload tiles when <code>tileset.show</code> is <code>false</code>. Loads tiles as if the tileset is visible but does not render them.
  253. *
  254. * @type {Boolean}
  255. * @default false
  256. */
  257. this.preloadWhenHidden = defaultValue(options.preloadWhenHidden, false);
  258. /**
  259. * Optimization option. Fetch tiles at the camera's flight destination while the camera is in flight.
  260. *
  261. * @type {Boolean}
  262. * @default true
  263. */
  264. this.preloadFlightDestinations = defaultValue(
  265. options.preloadFlightDestinations,
  266. true
  267. );
  268. this._pass = undefined; // Cesium3DTilePass
  269. /**
  270. * Optimization option. Whether the tileset should refine based on a dynamic screen space error. Tiles that are further
  271. * away will be rendered with lower detail than closer tiles. This improves performance by rendering fewer
  272. * tiles and making less requests, but may result in a slight drop in visual quality for tiles in the distance.
  273. * The algorithm is biased towards "street views" where the camera is close to the ground plane of the tileset and looking
  274. * at the horizon. In addition results are more accurate for tightly fitting bounding volumes like box and region.
  275. *
  276. * @type {Boolean}
  277. * @default false
  278. */
  279. this.dynamicScreenSpaceError = defaultValue(
  280. options.dynamicScreenSpaceError,
  281. false
  282. );
  283. /**
  284. * Optimization option. Prioritize loading tiles in the center of the screen by temporarily raising the
  285. * screen space error for tiles around the edge of the screen. Screen space error returns to normal once all
  286. * the tiles in the center of the screen as determined by the {@link Cesium3DTileset#foveatedConeSize} are loaded.
  287. *
  288. * @type {Boolean}
  289. * @default true
  290. */
  291. this.foveatedScreenSpaceError = defaultValue(
  292. options.foveatedScreenSpaceError,
  293. true
  294. );
  295. this._foveatedConeSize = defaultValue(options.foveatedConeSize, 0.1);
  296. this._foveatedMinimumScreenSpaceErrorRelaxation = defaultValue(
  297. options.foveatedMinimumScreenSpaceErrorRelaxation,
  298. 0.0
  299. );
  300. /**
  301. * Gets or sets a callback to control how much to raise the screen space error for tiles outside the foveated cone,
  302. * interpolating between {@link Cesium3DTileset#foveatedMinimumScreenSpaceErrorRelaxation} and {@link Cesium3DTileset#maximumScreenSpaceError}.
  303. *
  304. * @type {Cesium3DTileset.foveatedInterpolationCallback}
  305. */
  306. this.foveatedInterpolationCallback = defaultValue(
  307. options.foveatedInterpolationCallback,
  308. CesiumMath.lerp
  309. );
  310. /**
  311. * Optimization option. Used when {@link Cesium3DTileset#foveatedScreenSpaceError} is true to control
  312. * how long in seconds to wait after the camera stops moving before deferred tiles start loading in.
  313. * This time delay prevents requesting tiles around the edges of the screen when the camera is moving.
  314. * Setting this to 0.0 will immediately request all tiles in any given view.
  315. *
  316. * @type {Number}
  317. * @default 0.2
  318. */
  319. this.foveatedTimeDelay = defaultValue(options.foveatedTimeDelay, 0.2);
  320. /**
  321. * A scalar that determines the density used to adjust the dynamic screen space error, similar to {@link Fog}. Increasing this
  322. * value has the effect of increasing the maximum screen space error for all tiles, but in a non-linear fashion.
  323. * The error starts at 0.0 and increases exponentially until a midpoint is reached, and then approaches 1.0 asymptotically.
  324. * This has the effect of keeping high detail in the closer tiles and lower detail in the further tiles, with all tiles
  325. * beyond a certain distance all roughly having an error of 1.0.
  326. * <p>
  327. * The dynamic error is in the range [0.0, 1.0) and is multiplied by <code>dynamicScreenSpaceErrorFactor</code> to produce the
  328. * final dynamic error. This dynamic error is then subtracted from the tile's actual screen space error.
  329. * </p>
  330. * <p>
  331. * Increasing <code>dynamicScreenSpaceErrorDensity</code> has the effect of moving the error midpoint closer to the camera.
  332. * It is analogous to moving fog closer to the camera.
  333. * </p>
  334. *
  335. * @type {Number}
  336. * @default 0.00278
  337. */
  338. this.dynamicScreenSpaceErrorDensity = 0.00278;
  339. /**
  340. * A factor used to increase the screen space error of tiles for dynamic screen space error. As this value increases less tiles
  341. * are requested for rendering and tiles in the distance will have lower detail. If set to zero, the feature will be disabled.
  342. *
  343. * @type {Number}
  344. * @default 4.0
  345. */
  346. this.dynamicScreenSpaceErrorFactor = 4.0;
  347. /**
  348. * A ratio of the tileset's height at which the density starts to falloff. If the camera is below this height the
  349. * full computed density is applied, otherwise the density falls off. This has the effect of higher density at
  350. * street level views.
  351. * <p>
  352. * Valid values are between 0.0 and 1.0.
  353. * </p>
  354. *
  355. * @type {Number}
  356. * @default 0.25
  357. */
  358. this.dynamicScreenSpaceErrorHeightFalloff = 0.25;
  359. this._dynamicScreenSpaceErrorComputedDensity = 0.0; // Updated based on the camera position and direction
  360. /**
  361. * Determines whether the tileset casts or receives shadows from light sources.
  362. * <p>
  363. * Enabling shadows has a performance impact. A tileset that casts shadows must be rendered twice, once from the camera and again from the light's point of view.
  364. * </p>
  365. * <p>
  366. * Shadows are rendered only when {@link Viewer#shadows} is <code>true</code>.
  367. * </p>
  368. *
  369. * @type {ShadowMode}
  370. * @default ShadowMode.ENABLED
  371. */
  372. this.shadows = defaultValue(options.shadows, ShadowMode.ENABLED);
  373. /**
  374. * Determines if the tileset will be shown.
  375. *
  376. * @type {Boolean}
  377. * @default true
  378. */
  379. this.show = defaultValue(options.show, true);
  380. /**
  381. * Defines how per-feature colors set from the Cesium API or declarative styling blend with the source colors from
  382. * the original feature, e.g. glTF material or per-point color in the tile.
  383. *
  384. * @type {Cesium3DTileColorBlendMode}
  385. * @default Cesium3DTileColorBlendMode.HIGHLIGHT
  386. */
  387. this.colorBlendMode = Cesium3DTileColorBlendMode.HIGHLIGHT;
  388. /**
  389. * Defines the value used to linearly interpolate between the source color and feature color when the {@link Cesium3DTileset#colorBlendMode} is <code>MIX</code>.
  390. * A value of 0.0 results in the source color while a value of 1.0 results in the feature color, with any value in-between
  391. * resulting in a mix of the source color and feature color.
  392. *
  393. * @type {Number}
  394. * @default 0.5
  395. */
  396. this.colorBlendAmount = 0.5;
  397. /**
  398. * Options for controlling point size based on geometric error and eye dome lighting.
  399. * @type {PointCloudShading}
  400. */
  401. this.pointCloudShading = new PointCloudShading(options.pointCloudShading);
  402. this._pointCloudEyeDomeLighting = new PointCloudEyeDomeLighting();
  403. /**
  404. * The event fired to indicate progress of loading new tiles. This event is fired when a new tile
  405. * is requested, when a requested tile is finished downloading, and when a downloaded tile has been
  406. * processed and is ready to render.
  407. * <p>
  408. * The number of pending tile requests, <code>numberOfPendingRequests</code>, and number of tiles
  409. * processing, <code>numberOfTilesProcessing</code> are passed to the event listener.
  410. * </p>
  411. * <p>
  412. * This event is fired at the end of the frame after the scene is rendered.
  413. * </p>
  414. *
  415. * @type {Event}
  416. * @default new Event()
  417. *
  418. * @example
  419. * tileset.loadProgress.addEventListener(function(numberOfPendingRequests, numberOfTilesProcessing) {
  420. * if ((numberOfPendingRequests === 0) && (numberOfTilesProcessing === 0)) {
  421. * console.log('Stopped loading');
  422. * return;
  423. * }
  424. *
  425. * console.log('Loading: requests: ' + numberOfPendingRequests + ', processing: ' + numberOfTilesProcessing);
  426. * });
  427. */
  428. this.loadProgress = new Event();
  429. /**
  430. * The event fired to indicate that all tiles that meet the screen space error this frame are loaded. The tileset
  431. * is completely loaded for this view.
  432. * <p>
  433. * This event is fired at the end of the frame after the scene is rendered.
  434. * </p>
  435. *
  436. * @type {Event}
  437. * @default new Event()
  438. *
  439. * @example
  440. * tileset.allTilesLoaded.addEventListener(function() {
  441. * console.log('All tiles are loaded');
  442. * });
  443. *
  444. * @see Cesium3DTileset#tilesLoaded
  445. */
  446. this.allTilesLoaded = new Event();
  447. /**
  448. * The event fired to indicate that all tiles that meet the screen space error this frame are loaded. This event
  449. * is fired once when all tiles in the initial view are loaded.
  450. * <p>
  451. * This event is fired at the end of the frame after the scene is rendered.
  452. * </p>
  453. *
  454. * @type {Event}
  455. * @default new Event()
  456. *
  457. * @example
  458. * tileset.initialTilesLoaded.addEventListener(function() {
  459. * console.log('Initial tiles are loaded');
  460. * });
  461. *
  462. * @see Cesium3DTileset#allTilesLoaded
  463. */
  464. this.initialTilesLoaded = new Event();
  465. /**
  466. * The event fired to indicate that a tile's content was loaded.
  467. * <p>
  468. * The loaded {@link Cesium3DTile} is passed to the event listener.
  469. * </p>
  470. * <p>
  471. * This event is fired during the tileset traversal while the frame is being rendered
  472. * so that updates to the tile take effect in the same frame. Do not create or modify
  473. * Cesium entities or primitives during the event listener.
  474. * </p>
  475. *
  476. * @type {Event}
  477. * @default new Event()
  478. *
  479. * @example
  480. * tileset.tileLoad.addEventListener(function(tile) {
  481. * console.log('A tile was loaded.');
  482. * });
  483. */
  484. this.tileLoad = new Event();
  485. /**
  486. * The event fired to indicate that a tile's content was unloaded.
  487. * <p>
  488. * The unloaded {@link Cesium3DTile} is passed to the event listener.
  489. * </p>
  490. * <p>
  491. * This event is fired immediately before the tile's content is unloaded while the frame is being
  492. * rendered so that the event listener has access to the tile's content. Do not create
  493. * or modify Cesium entities or primitives during the event listener.
  494. * </p>
  495. *
  496. * @type {Event}
  497. * @default new Event()
  498. *
  499. * @example
  500. * tileset.tileUnload.addEventListener(function(tile) {
  501. * console.log('A tile was unloaded from the cache.');
  502. * });
  503. *
  504. * @see Cesium3DTileset#maximumMemoryUsage
  505. * @see Cesium3DTileset#trimLoadedTiles
  506. */
  507. this.tileUnload = new Event();
  508. /**
  509. * The event fired to indicate that a tile's content failed to load.
  510. * <p>
  511. * If there are no event listeners, error messages will be logged to the console.
  512. * </p>
  513. * <p>
  514. * The error object passed to the listener contains two properties:
  515. * <ul>
  516. * <li><code>url</code>: the url of the failed tile.</li>
  517. * <li><code>message</code>: the error message.</li>
  518. * </ul>
  519. *
  520. * @type {Event}
  521. * @default new Event()
  522. *
  523. * @example
  524. * tileset.tileFailed.addEventListener(function(error) {
  525. * console.log('An error occurred loading tile: ' + error.url);
  526. * console.log('Error: ' + error.message);
  527. * });
  528. */
  529. this.tileFailed = new Event();
  530. /**
  531. * This event fires once for each visible tile in a frame. This can be used to manually
  532. * style a tileset.
  533. * <p>
  534. * The visible {@link Cesium3DTile} is passed to the event listener.
  535. * </p>
  536. * <p>
  537. * This event is fired during the tileset traversal while the frame is being rendered
  538. * so that updates to the tile take effect in the same frame. Do not create or modify
  539. * Cesium entities or primitives during the event listener.
  540. * </p>
  541. *
  542. * @type {Event}
  543. * @default new Event()
  544. *
  545. * @example
  546. * tileset.tileVisible.addEventListener(function(tile) {
  547. * if (tile.content instanceof Cesium.Batched3DModel3DTileContent) {
  548. * console.log('A Batched 3D Model tile is visible.');
  549. * }
  550. * });
  551. *
  552. * @example
  553. * // Apply a red style and then manually set random colors for every other feature when the tile becomes visible.
  554. * tileset.style = new Cesium.Cesium3DTileStyle({
  555. * color : 'color("red")'
  556. * });
  557. * tileset.tileVisible.addEventListener(function(tile) {
  558. * var content = tile.content;
  559. * var featuresLength = content.featuresLength;
  560. * for (var i = 0; i < featuresLength; i+=2) {
  561. * content.getFeature(i).color = Cesium.Color.fromRandom();
  562. * }
  563. * });
  564. */
  565. this.tileVisible = new Event();
  566. /**
  567. * Optimization option. Determines if level of detail skipping should be applied during the traversal.
  568. * <p>
  569. * The common strategy for replacement-refinement traversal is to store all levels of the tree in memory and require
  570. * all children to be loaded before the parent can refine. With this optimization levels of the tree can be skipped
  571. * entirely and children can be rendered alongside their parents. The tileset requires significantly less memory when
  572. * using this optimization.
  573. * </p>
  574. *
  575. * @type {Boolean}
  576. * @default false
  577. */
  578. this.skipLevelOfDetail = defaultValue(options.skipLevelOfDetail, false);
  579. this._skipLevelOfDetail = this.skipLevelOfDetail;
  580. this._disableSkipLevelOfDetail = false;
  581. /**
  582. * The screen space error that must be reached before skipping levels of detail.
  583. * <p>
  584. * Only used when {@link Cesium3DTileset#skipLevelOfDetail} is <code>true</code>.
  585. * </p>
  586. *
  587. * @type {Number}
  588. * @default 1024
  589. */
  590. this.baseScreenSpaceError = defaultValue(options.baseScreenSpaceError, 1024);
  591. /**
  592. * Multiplier defining the minimum screen space error to skip.
  593. * For example, if a tile has screen space error of 100, no tiles will be loaded unless they
  594. * are leaves or have a screen space error <code><= 100 / skipScreenSpaceErrorFactor</code>.
  595. * <p>
  596. * Only used when {@link Cesium3DTileset#skipLevelOfDetail} is <code>true</code>.
  597. * </p>
  598. *
  599. * @type {Number}
  600. * @default 16
  601. */
  602. this.skipScreenSpaceErrorFactor = defaultValue(
  603. options.skipScreenSpaceErrorFactor,
  604. 16
  605. );
  606. /**
  607. * Constant defining the minimum number of levels to skip when loading tiles. When it is 0, no levels are skipped.
  608. * For example, if a tile is level 1, no tiles will be loaded unless they are at level greater than 2.
  609. * <p>
  610. * Only used when {@link Cesium3DTileset#skipLevelOfDetail} is <code>true</code>.
  611. * </p>
  612. *
  613. * @type {Number}
  614. * @default 1
  615. */
  616. this.skipLevels = defaultValue(options.skipLevels, 1);
  617. /**
  618. * When true, only tiles that meet the maximum screen space error will ever be downloaded.
  619. * Skipping factors are ignored and just the desired tiles are loaded.
  620. * <p>
  621. * Only used when {@link Cesium3DTileset#skipLevelOfDetail} is <code>true</code>.
  622. * </p>
  623. *
  624. * @type {Boolean}
  625. * @default false
  626. */
  627. this.immediatelyLoadDesiredLevelOfDetail = defaultValue(
  628. options.immediatelyLoadDesiredLevelOfDetail,
  629. false
  630. );
  631. /**
  632. * Determines whether siblings of visible tiles are always downloaded during traversal.
  633. * This may be useful for ensuring that tiles are already available when the viewer turns left/right.
  634. * <p>
  635. * Only used when {@link Cesium3DTileset#skipLevelOfDetail} is <code>true</code>.
  636. * </p>
  637. *
  638. * @type {Boolean}
  639. * @default false
  640. */
  641. this.loadSiblings = defaultValue(options.loadSiblings, false);
  642. this._clippingPlanes = undefined;
  643. this.clippingPlanes = options.clippingPlanes;
  644. this._imageBasedLightingFactor = new Cartesian2(1.0, 1.0);
  645. Cartesian2.clone(
  646. options.imageBasedLightingFactor,
  647. this._imageBasedLightingFactor
  648. );
  649. /**
  650. * The light color when shading models. When <code>undefined</code> the scene's light color is used instead.
  651. * <p>
  652. * For example, disabling additional light sources by setting <code>model.imageBasedLightingFactor = new Cartesian2(0.0, 0.0)</code> will make the
  653. * model much darker. Here, increasing the intensity of the light source will make the model brighter.
  654. * </p>
  655. *
  656. * @type {Cartesian3}
  657. * @default undefined
  658. */
  659. this.lightColor = options.lightColor;
  660. /**
  661. * The sun's luminance at the zenith in kilo candela per meter squared to use for this model's procedural environment map.
  662. * This is used when {@link Cesium3DTileset#specularEnvironmentMaps} and {@link Cesium3DTileset#sphericalHarmonicCoefficients} are not defined.
  663. *
  664. * @type Number
  665. *
  666. * @default 0.2
  667. *
  668. */
  669. this.luminanceAtZenith = defaultValue(options.luminanceAtZenith, 0.2);
  670. /**
  671. * The third order spherical harmonic coefficients used for the diffuse color of image-based lighting. When <code>undefined</code>, a diffuse irradiance
  672. * computed from the atmosphere color is used.
  673. * <p>
  674. * There are nine <code>Cartesian3</code> coefficients.
  675. * The order of the coefficients is: L<sub>00</sub>, L<sub>1-1</sub>, L<sub>10</sub>, L<sub>11</sub>, L<sub>2-2</sub>, L<sub>2-1</sub>, L<sub>20</sub>, L<sub>21</sub>, L<sub>22</sub>
  676. * </p>
  677. *
  678. * These values can be obtained by preprocessing the environment map using the <code>cmgen</code> tool of
  679. * {@link https://github.com/google/filament/releases|Google's Filament project}. This will also generate a KTX file that can be
  680. * supplied to {@link Cesium3DTileset#specularEnvironmentMaps}.
  681. *
  682. * @type {Cartesian3[]}
  683. * @demo {@link https://sandcastle.cesium.com/index.html?src=Image-Based Lighting.html|Sandcastle Image Based Lighting Demo}
  684. * @see {@link https://graphics.stanford.edu/papers/envmap/envmap.pdf|An Efficient Representation for Irradiance Environment Maps}
  685. */
  686. this.sphericalHarmonicCoefficients = options.sphericalHarmonicCoefficients;
  687. /**
  688. * A URL to a KTX file that contains a cube map of the specular lighting and the convoluted specular mipmaps.
  689. *
  690. * @demo {@link https://sandcastle.cesium.com/index.html?src=Image-Based Lighting.html|Sandcastle Image Based Lighting Demo}
  691. * @type {String}
  692. * @see Cesium3DTileset#sphericalHarmonicCoefficients
  693. */
  694. this.specularEnvironmentMaps = options.specularEnvironmentMaps;
  695. /**
  696. * Whether to cull back-facing geometry. When true, back face culling is determined
  697. * by the glTF material's doubleSided property; when false, back face culling is disabled.
  698. *
  699. * @type {Boolean}
  700. * @default true
  701. */
  702. this.backFaceCulling = defaultValue(options.backFaceCulling, true);
  703. /**
  704. * This property is for debugging only; it is not optimized for production use.
  705. * <p>
  706. * Determines if only the tiles from last frame should be used for rendering. This
  707. * effectively "freezes" the tileset to the previous frame so it is possible to zoom
  708. * out and see what was rendered.
  709. * </p>
  710. *
  711. * @type {Boolean}
  712. * @default false
  713. */
  714. this.debugFreezeFrame = defaultValue(options.debugFreezeFrame, false);
  715. /**
  716. * This property is for debugging only; it is not optimized for production use.
  717. * <p>
  718. * When true, assigns a random color to each tile. This is useful for visualizing
  719. * what features belong to what tiles, especially with additive refinement where features
  720. * from parent tiles may be interleaved with features from child tiles.
  721. * </p>
  722. *
  723. * @type {Boolean}
  724. * @default false
  725. */
  726. this.debugColorizeTiles = defaultValue(options.debugColorizeTiles, false);
  727. /**
  728. * This property is for debugging only; it is not optimized for production use.
  729. * <p>
  730. * When true, renders each tile's content as a wireframe.
  731. * </p>
  732. *
  733. * @type {Boolean}
  734. * @default false
  735. */
  736. this.debugWireframe = defaultValue(options.debugWireframe, false);
  737. /**
  738. * This property is for debugging only; it is not optimized for production use.
  739. * <p>
  740. * When true, renders the bounding volume for each visible tile. The bounding volume is
  741. * white if the tile has a content bounding volume or is empty; otherwise, it is red. Tiles that don't meet the
  742. * screen space error and are still refining to their descendants are yellow.
  743. * </p>
  744. *
  745. * @type {Boolean}
  746. * @default false
  747. */
  748. this.debugShowBoundingVolume = defaultValue(
  749. options.debugShowBoundingVolume,
  750. false
  751. );
  752. /**
  753. * This property is for debugging only; it is not optimized for production use.
  754. * <p>
  755. * When true, renders the bounding volume for each visible tile's content. The bounding volume is
  756. * blue if the tile has a content bounding volume; otherwise it is red.
  757. * </p>
  758. *
  759. * @type {Boolean}
  760. * @default false
  761. */
  762. this.debugShowContentBoundingVolume = defaultValue(
  763. options.debugShowContentBoundingVolume,
  764. false
  765. );
  766. /**
  767. * This property is for debugging only; it is not optimized for production use.
  768. * <p>
  769. * When true, renders the viewer request volume for each tile.
  770. * </p>
  771. *
  772. * @type {Boolean}
  773. * @default false
  774. */
  775. this.debugShowViewerRequestVolume = defaultValue(
  776. options.debugShowViewerRequestVolume,
  777. false
  778. );
  779. this._tileDebugLabels = undefined;
  780. this.debugPickedTileLabelOnly = false;
  781. this.debugPickedTile = undefined;
  782. this.debugPickPosition = undefined;
  783. /**
  784. * This property is for debugging only; it is not optimized for production use.
  785. * <p>
  786. * When true, draws labels to indicate the geometric error of each tile.
  787. * </p>
  788. *
  789. * @type {Boolean}
  790. * @default false
  791. */
  792. this.debugShowGeometricError = defaultValue(
  793. options.debugShowGeometricError,
  794. false
  795. );
  796. /**
  797. * This property is for debugging only; it is not optimized for production use.
  798. * <p>
  799. * When true, draws labels to indicate the number of commands, points, triangles and features of each tile.
  800. * </p>
  801. *
  802. * @type {Boolean}
  803. * @default false
  804. */
  805. this.debugShowRenderingStatistics = defaultValue(
  806. options.debugShowRenderingStatistics,
  807. false
  808. );
  809. /**
  810. * This property is for debugging only; it is not optimized for production use.
  811. * <p>
  812. * When true, draws labels to indicate the geometry and texture memory usage of each tile.
  813. * </p>
  814. *
  815. * @type {Boolean}
  816. * @default false
  817. */
  818. this.debugShowMemoryUsage = defaultValue(options.debugShowMemoryUsage, false);
  819. /**
  820. * This property is for debugging only; it is not optimized for production use.
  821. * <p>
  822. * When true, draws labels to indicate the url of each tile.
  823. * </p>
  824. *
  825. * @type {Boolean}
  826. * @default false
  827. */
  828. this.debugShowUrl = defaultValue(options.debugShowUrl, false);
  829. var that = this;
  830. var resource;
  831. when(options.url)
  832. .then(function (url) {
  833. var basePath;
  834. resource = Resource.createIfNeeded(url);
  835. // ion resources have a credits property we can use for additional attribution.
  836. that._credits = resource.credits;
  837. if (resource.extension === "json") {
  838. basePath = resource.getBaseUri(true);
  839. } else if (resource.isDataUri) {
  840. basePath = "";
  841. }
  842. that._url = resource.url;
  843. that._basePath = basePath;
  844. return Cesium3DTileset.loadJson(resource);
  845. })
  846. .then(function (tilesetJson) {
  847. that._root = that.loadTileset(resource, tilesetJson);
  848. var gltfUpAxis = defined(tilesetJson.asset.gltfUpAxis)
  849. ? Axis.fromName(tilesetJson.asset.gltfUpAxis)
  850. : Axis.Y;
  851. var asset = tilesetJson.asset;
  852. that._asset = asset;
  853. that._properties = tilesetJson.properties;
  854. that._geometricError = tilesetJson.geometricError;
  855. that._extensionsUsed = tilesetJson.extensionsUsed;
  856. that._extensions = tilesetJson.extensions;
  857. that._gltfUpAxis = gltfUpAxis;
  858. that._extras = tilesetJson.extras;
  859. var extras = asset.extras;
  860. if (
  861. defined(extras) &&
  862. defined(extras.cesium) &&
  863. defined(extras.cesium.credits)
  864. ) {
  865. var extraCredits = extras.cesium.credits;
  866. var credits = that._credits;
  867. if (!defined(credits)) {
  868. credits = [];
  869. that._credits = credits;
  870. }
  871. for (var i = 0; i < extraCredits.length; ++i) {
  872. var credit = extraCredits[i];
  873. credits.push(new Credit(credit.html, credit.showOnScreen));
  874. }
  875. }
  876. // Save the original, untransformed bounding volume position so we can apply
  877. // the tile transform and model matrix at run time
  878. var boundingVolume = that._root.createBoundingVolume(
  879. tilesetJson.root.boundingVolume,
  880. Matrix4.IDENTITY
  881. );
  882. var clippingPlanesOrigin = boundingVolume.boundingSphere.center;
  883. // If this origin is above the surface of the earth
  884. // we want to apply an ENU orientation as our best guess of orientation.
  885. // Otherwise, we assume it gets its position/orientation completely from the
  886. // root tile transform and the tileset's model matrix
  887. var originCartographic = that._ellipsoid.cartesianToCartographic(
  888. clippingPlanesOrigin
  889. );
  890. if (
  891. defined(originCartographic) &&
  892. originCartographic.height >
  893. ApproximateTerrainHeights._defaultMinTerrainHeight
  894. ) {
  895. that._initialClippingPlanesOriginMatrix = Transforms.eastNorthUpToFixedFrame(
  896. clippingPlanesOrigin
  897. );
  898. }
  899. that._clippingPlanesOriginMatrix = Matrix4.clone(
  900. that._initialClippingPlanesOriginMatrix
  901. );
  902. that._readyPromise.resolve(that);
  903. })
  904. .otherwise(function (error) {
  905. that._readyPromise.reject(error);
  906. });
  907. }
  908. Object.defineProperties(Cesium3DTileset.prototype, {
  909. /**
  910. * NOTE: This getter exists so that `Picking.js` can differentiate between
  911. * PrimitiveCollection and Cesium3DTileset objects without inflating
  912. * the size of the module via `instanceof Cesium3DTileset`
  913. * @private
  914. */
  915. isCesium3DTileset: {
  916. get: function () {
  917. return true;
  918. },
  919. },
  920. /**
  921. * Gets the tileset's asset object property, which contains metadata about the tileset.
  922. * <p>
  923. * See the {@link https://github.com/CesiumGS/3d-tiles/tree/master/specification#reference-asset|asset schema reference}
  924. * in the 3D Tiles spec for the full set of properties.
  925. * </p>
  926. *
  927. * @memberof Cesium3DTileset.prototype
  928. *
  929. * @type {Object}
  930. * @readonly
  931. *
  932. * @exception {DeveloperError} The tileset is not loaded. Use Cesium3DTileset.readyPromise or wait for Cesium3DTileset.ready to be true.
  933. */
  934. asset: {
  935. get: function () {
  936. //>>includeStart('debug', pragmas.debug);
  937. if (!this.ready) {
  938. throw new DeveloperError(
  939. "The tileset is not loaded. Use Cesium3DTileset.readyPromise or wait for Cesium3DTileset.ready to be true."
  940. );
  941. }
  942. //>>includeEnd('debug');
  943. return this._asset;
  944. },
  945. },
  946. /**
  947. * Gets the tileset's extensions object property.
  948. *
  949. * @memberof Cesium3DTileset.prototype
  950. *
  951. * @type {Object}
  952. * @readonly
  953. *
  954. * @exception {DeveloperError} The tileset is not loaded. Use Cesium3DTileset.readyPromise or wait for Cesium3DTileset.ready to be true.
  955. */
  956. extensions: {
  957. get: function () {
  958. //>>includeStart('debug', pragmas.debug);
  959. if (!this.ready) {
  960. throw new DeveloperError(
  961. "The tileset is not loaded. Use Cesium3DTileset.readyPromise or wait for Cesium3DTileset.ready to be true."
  962. );
  963. }
  964. //>>includeEnd('debug');
  965. return this._extensions;
  966. },
  967. },
  968. /**
  969. * The {@link ClippingPlaneCollection} used to selectively disable rendering the tileset.
  970. *
  971. * @memberof Cesium3DTileset.prototype
  972. *
  973. * @type {ClippingPlaneCollection}
  974. */
  975. clippingPlanes: {
  976. get: function () {
  977. return this._clippingPlanes;
  978. },
  979. set: function (value) {
  980. ClippingPlaneCollection.setOwner(value, this, "_clippingPlanes");
  981. },
  982. },
  983. /**
  984. * Gets the tileset's properties dictionary object, which contains metadata about per-feature properties.
  985. * <p>
  986. * See the {@link https://github.com/CesiumGS/3d-tiles/tree/master/specification#reference-properties|properties schema reference}
  987. * in the 3D Tiles spec for the full set of properties.
  988. * </p>
  989. *
  990. * @memberof Cesium3DTileset.prototype
  991. *
  992. * @type {Object}
  993. * @readonly
  994. *
  995. * @exception {DeveloperError} The tileset is not loaded. Use Cesium3DTileset.readyPromise or wait for Cesium3DTileset.ready to be true.
  996. *
  997. * @example
  998. * console.log('Maximum building height: ' + tileset.properties.height.maximum);
  999. * console.log('Minimum building height: ' + tileset.properties.height.minimum);
  1000. *
  1001. * @see Cesium3DTileFeature#getProperty
  1002. * @see Cesium3DTileFeature#setProperty
  1003. */
  1004. properties: {
  1005. get: function () {
  1006. //>>includeStart('debug', pragmas.debug);
  1007. if (!this.ready) {
  1008. throw new DeveloperError(
  1009. "The tileset is not loaded. Use Cesium3DTileset.readyPromise or wait for Cesium3DTileset.ready to be true."
  1010. );
  1011. }
  1012. //>>includeEnd('debug');
  1013. return this._properties;
  1014. },
  1015. },
  1016. /**
  1017. * When <code>true</code>, the tileset's root tile is loaded and the tileset is ready to render.
  1018. * This is set to <code>true</code> right before {@link Cesium3DTileset#readyPromise} is resolved.
  1019. *
  1020. * @memberof Cesium3DTileset.prototype
  1021. *
  1022. * @type {Boolean}
  1023. * @readonly
  1024. *
  1025. * @default false
  1026. */
  1027. ready: {
  1028. get: function () {
  1029. return defined(this._root);
  1030. },
  1031. },
  1032. /**
  1033. * Gets the promise that will be resolved when the tileset's root tile is loaded and the tileset is ready to render.
  1034. * <p>
  1035. * This promise is resolved at the end of the frame before the first frame the tileset is rendered in.
  1036. * </p>
  1037. *
  1038. * @memberof Cesium3DTileset.prototype
  1039. *
  1040. * @type {Promise.<Cesium3DTileset>}
  1041. * @readonly
  1042. *
  1043. * @example
  1044. * tileset.readyPromise.then(function(tileset) {
  1045. * // tile.properties is not defined until readyPromise resolves.
  1046. * var properties = tileset.properties;
  1047. * if (Cesium.defined(properties)) {
  1048. * for (var name in properties) {
  1049. * console.log(properties[name]);
  1050. * }
  1051. * }
  1052. * });
  1053. */
  1054. readyPromise: {
  1055. get: function () {
  1056. return this._readyPromise.promise;
  1057. },
  1058. },
  1059. /**
  1060. * When <code>true</code>, all tiles that meet the screen space error this frame are loaded. The tileset is
  1061. * completely loaded for this view.
  1062. *
  1063. * @memberof Cesium3DTileset.prototype
  1064. *
  1065. * @type {Boolean}
  1066. * @readonly
  1067. *
  1068. * @default false
  1069. *
  1070. * @see Cesium3DTileset#allTilesLoaded
  1071. */
  1072. tilesLoaded: {
  1073. get: function () {
  1074. return this._tilesLoaded;
  1075. },
  1076. },
  1077. /**
  1078. * The url to a tileset JSON file.
  1079. *
  1080. * @memberof Cesium3DTileset.prototype
  1081. *
  1082. * @type {String}
  1083. * @readonly
  1084. */
  1085. url: {
  1086. get: function () {
  1087. return this._url;
  1088. },
  1089. },
  1090. /**
  1091. * The base path that non-absolute paths in tileset JSON file are relative to.
  1092. *
  1093. * @memberof Cesium3DTileset.prototype
  1094. *
  1095. * @type {String}
  1096. * @readonly
  1097. * @deprecated
  1098. */
  1099. basePath: {
  1100. get: function () {
  1101. deprecationWarning(
  1102. "Cesium3DTileset.basePath",
  1103. "Cesium3DTileset.basePath has been deprecated. All tiles are relative to the url of the tileset JSON file that contains them. Use the url property instead."
  1104. );
  1105. return this._basePath;
  1106. },
  1107. },
  1108. /**
  1109. * The style, defined using the
  1110. * {@link https://github.com/CesiumGS/3d-tiles/tree/master/specification/Styling|3D Tiles Styling language},
  1111. * applied to each feature in the tileset.
  1112. * <p>
  1113. * Assign <code>undefined</code> to remove the style, which will restore the visual
  1114. * appearance of the tileset to its default when no style was applied.
  1115. * </p>
  1116. * <p>
  1117. * The style is applied to a tile before the {@link Cesium3DTileset#tileVisible}
  1118. * event is raised, so code in <code>tileVisible</code> can manually set a feature's
  1119. * properties (e.g. color and show) after the style is applied. When
  1120. * a new style is assigned any manually set properties are overwritten.
  1121. * </p>
  1122. *
  1123. * @memberof Cesium3DTileset.prototype
  1124. *
  1125. * @type {Cesium3DTileStyle|undefined}
  1126. *
  1127. * @default undefined
  1128. *
  1129. * @example
  1130. * tileset.style = new Cesium.Cesium3DTileStyle({
  1131. * color : {
  1132. * conditions : [
  1133. * ['${Height} >= 100', 'color("purple", 0.5)'],
  1134. * ['${Height} >= 50', 'color("red")'],
  1135. * ['true', 'color("blue")']
  1136. * ]
  1137. * },
  1138. * show : '${Height} > 0',
  1139. * meta : {
  1140. * description : '"Building id ${id} has height ${Height}."'
  1141. * }
  1142. * });
  1143. *
  1144. * @see {@link https://github.com/CesiumGS/3d-tiles/tree/master/specification/Styling|3D Tiles Styling language}
  1145. */
  1146. style: {
  1147. get: function () {
  1148. return this._styleEngine.style;
  1149. },
  1150. set: function (value) {
  1151. this._styleEngine.style = value;
  1152. },
  1153. },
  1154. /**
  1155. * The maximum screen space error used to drive level of detail refinement. This value helps determine when a tile
  1156. * refines to its descendants, and therefore plays a major role in balancing performance with visual quality.
  1157. * <p>
  1158. * A tile's screen space error is roughly equivalent to the number of pixels wide that would be drawn if a sphere with a
  1159. * radius equal to the tile's <b>geometric error</b> were rendered at the tile's position. If this value exceeds
  1160. * <code>maximumScreenSpaceError</code> the tile refines to its descendants.
  1161. * </p>
  1162. * <p>
  1163. * Depending on the tileset, <code>maximumScreenSpaceError</code> may need to be tweaked to achieve the right balance.
  1164. * Higher values provide better performance but lower visual quality.
  1165. * </p>
  1166. *
  1167. * @memberof Cesium3DTileset.prototype
  1168. *
  1169. * @type {Number}
  1170. * @default 16
  1171. *
  1172. * @exception {DeveloperError} <code>maximumScreenSpaceError</code> must be greater than or equal to zero.
  1173. */
  1174. maximumScreenSpaceError: {
  1175. get: function () {
  1176. return this._maximumScreenSpaceError;
  1177. },
  1178. set: function (value) {
  1179. //>>includeStart('debug', pragmas.debug);
  1180. Check.typeOf.number.greaterThanOrEquals(
  1181. "maximumScreenSpaceError",
  1182. value,
  1183. 0
  1184. );
  1185. //>>includeEnd('debug');
  1186. this._maximumScreenSpaceError = value;
  1187. },
  1188. },
  1189. /**
  1190. * The maximum amount of GPU memory (in MB) that may be used to cache tiles. This value is estimated from
  1191. * geometry, textures, and batch table textures of loaded tiles. For point clouds, this value also
  1192. * includes per-point metadata.
  1193. * <p>
  1194. * Tiles not in view are unloaded to enforce this.
  1195. * </p>
  1196. * <p>
  1197. * If decreasing this value results in unloading tiles, the tiles are unloaded the next frame.
  1198. * </p>
  1199. * <p>
  1200. * If tiles sized more than <code>maximumMemoryUsage</code> are needed
  1201. * to meet the desired screen space error, determined by {@link Cesium3DTileset#maximumScreenSpaceError},
  1202. * for the current view, then the memory usage of the tiles loaded will exceed
  1203. * <code>maximumMemoryUsage</code>. For example, if the maximum is 256 MB, but
  1204. * 300 MB of tiles are needed to meet the screen space error, then 300 MB of tiles may be loaded. When
  1205. * these tiles go out of view, they will be unloaded.
  1206. * </p>
  1207. *
  1208. * @memberof Cesium3DTileset.prototype
  1209. *
  1210. * @type {Number}
  1211. * @default 512
  1212. *
  1213. * @exception {DeveloperError} <code>maximumMemoryUsage</code> must be greater than or equal to zero.
  1214. * @see Cesium3DTileset#totalMemoryUsageInBytes
  1215. */
  1216. maximumMemoryUsage: {
  1217. get: function () {
  1218. return this._maximumMemoryUsage;
  1219. },
  1220. set: function (value) {
  1221. //>>includeStart('debug', pragmas.debug);
  1222. Check.typeOf.number.greaterThanOrEquals("value", value, 0);
  1223. //>>includeEnd('debug');
  1224. this._maximumMemoryUsage = value;
  1225. },
  1226. },
  1227. /**
  1228. * The root tile.
  1229. *
  1230. * @memberOf Cesium3DTileset.prototype
  1231. *
  1232. * @type {Cesium3DTile}
  1233. * @readonly
  1234. *
  1235. * @exception {DeveloperError} The tileset is not loaded. Use Cesium3DTileset.readyPromise or wait for Cesium3DTileset.ready to be true.
  1236. */
  1237. root: {
  1238. get: function () {
  1239. //>>includeStart('debug', pragmas.debug);
  1240. if (!this.ready) {
  1241. throw new DeveloperError(
  1242. "The tileset is not loaded. Use Cesium3DTileset.readyPromise or wait for Cesium3DTileset.ready to be true."
  1243. );
  1244. }
  1245. //>>includeEnd('debug');
  1246. return this._root;
  1247. },
  1248. },
  1249. /**
  1250. * The tileset's bounding sphere.
  1251. *
  1252. * @memberof Cesium3DTileset.prototype
  1253. *
  1254. * @type {BoundingSphere}
  1255. * @readonly
  1256. *
  1257. * @exception {DeveloperError} The tileset is not loaded. Use Cesium3DTileset.readyPromise or wait for Cesium3DTileset.ready to be true.
  1258. *
  1259. * @example
  1260. * var tileset = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
  1261. * url : 'http://localhost:8002/tilesets/Seattle/tileset.json'
  1262. * }));
  1263. *
  1264. * tileset.readyPromise.then(function(tileset) {
  1265. * // Set the camera to view the newly added tileset
  1266. * viewer.camera.viewBoundingSphere(tileset.boundingSphere, new Cesium.HeadingPitchRange(0, -0.5, 0));
  1267. * });
  1268. */
  1269. boundingSphere: {
  1270. get: function () {
  1271. //>>includeStart('debug', pragmas.debug);
  1272. if (!this.ready) {
  1273. throw new DeveloperError(
  1274. "The tileset is not loaded. Use Cesium3DTileset.readyPromise or wait for Cesium3DTileset.ready to be true."
  1275. );
  1276. }
  1277. //>>includeEnd('debug');
  1278. this._root.updateTransform(this._modelMatrix);
  1279. return this._root.boundingSphere;
  1280. },
  1281. },
  1282. /**
  1283. * A 4x4 transformation matrix that transforms the entire tileset.
  1284. *
  1285. * @memberof Cesium3DTileset.prototype
  1286. *
  1287. * @type {Matrix4}
  1288. * @default Matrix4.IDENTITY
  1289. *
  1290. * @example
  1291. * // Adjust a tileset's height from the globe's surface.
  1292. * var heightOffset = 20.0;
  1293. * var boundingSphere = tileset.boundingSphere;
  1294. * var cartographic = Cesium.Cartographic.fromCartesian(boundingSphere.center);
  1295. * var surface = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, 0.0);
  1296. * var offset = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, heightOffset);
  1297. * var translation = Cesium.Cartesian3.subtract(offset, surface, new Cesium.Cartesian3());
  1298. * tileset.modelMatrix = Cesium.Matrix4.fromTranslation(translation);
  1299. */
  1300. modelMatrix: {
  1301. get: function () {
  1302. return this._modelMatrix;
  1303. },
  1304. set: function (value) {
  1305. this._modelMatrix = Matrix4.clone(value, this._modelMatrix);
  1306. },
  1307. },
  1308. /**
  1309. * Returns the time, in milliseconds, since the tileset was loaded and first updated.
  1310. *
  1311. * @memberof Cesium3DTileset.prototype
  1312. *
  1313. * @type {Number}
  1314. * @readonly
  1315. */
  1316. timeSinceLoad: {
  1317. get: function () {
  1318. return this._timeSinceLoad;
  1319. },
  1320. },
  1321. /**
  1322. * The total amount of GPU memory in bytes used by the tileset. This value is estimated from
  1323. * geometry, texture, and batch table textures of loaded tiles. For point clouds, this value also
  1324. * includes per-point metadata.
  1325. *
  1326. * @memberof Cesium3DTileset.prototype
  1327. *
  1328. * @type {Number}
  1329. * @readonly
  1330. *
  1331. * @see Cesium3DTileset#maximumMemoryUsage
  1332. */
  1333. totalMemoryUsageInBytes: {
  1334. get: function () {
  1335. var statistics = this._statistics;
  1336. return (
  1337. statistics.texturesByteLength +
  1338. statistics.geometryByteLength +
  1339. statistics.batchTableByteLength
  1340. );
  1341. },
  1342. },
  1343. /**
  1344. * @private
  1345. */
  1346. clippingPlanesOriginMatrix: {
  1347. get: function () {
  1348. if (!defined(this._clippingPlanesOriginMatrix)) {
  1349. return Matrix4.IDENTITY;
  1350. }
  1351. if (this._clippingPlanesOriginMatrixDirty) {
  1352. Matrix4.multiply(
  1353. this.root.computedTransform,
  1354. this._initialClippingPlanesOriginMatrix,
  1355. this._clippingPlanesOriginMatrix
  1356. );
  1357. this._clippingPlanesOriginMatrixDirty = false;
  1358. }
  1359. return this._clippingPlanesOriginMatrix;
  1360. },
  1361. },
  1362. /**
  1363. * @private
  1364. */
  1365. styleEngine: {
  1366. get: function () {
  1367. return this._styleEngine;
  1368. },
  1369. },
  1370. /**
  1371. * @private
  1372. */
  1373. statistics: {
  1374. get: function () {
  1375. return this._statistics;
  1376. },
  1377. },
  1378. /**
  1379. * Determines whether terrain, 3D Tiles or both will be classified by this tileset.
  1380. * <p>
  1381. * This option is only applied to tilesets containing batched 3D models, geometry data, or vector data. Even when undefined, vector data and geometry data
  1382. * must render as classifications and will default to rendering on both terrain and other 3D Tiles tilesets.
  1383. * </p>
  1384. * <p>
  1385. * When enabled for batched 3D model tilesets, there are a few requirements/limitations on the glTF:
  1386. * <ul>
  1387. * <li>POSITION and _BATCHID semantics are required.</li>
  1388. * <li>All indices with the same batch id must occupy contiguous sections of the index buffer.</li>
  1389. * <li>All shaders and techniques are ignored. The generated shader simply multiplies the position by the model-view-projection matrix.</li>
  1390. * <li>The only supported extensions are CESIUM_RTC and WEB3D_quantized_attributes.</li>
  1391. * <li>Only one node is supported.</li>
  1392. * <li>Only one mesh per node is supported.</li>
  1393. * <li>Only one primitive per mesh is supported.</li>
  1394. * </ul>
  1395. * </p>
  1396. *
  1397. * @memberof Cesium3DTileset.prototype
  1398. *
  1399. * @type {ClassificationType}
  1400. * @default undefined
  1401. *
  1402. * @experimental This feature is using part of the 3D Tiles spec that is not final and is subject to change without Cesium's standard deprecation policy.
  1403. * @readonly
  1404. */
  1405. classificationType: {
  1406. get: function () {
  1407. return this._classificationType;
  1408. },
  1409. },
  1410. /**
  1411. * Gets an ellipsoid describing the shape of the globe.
  1412. *
  1413. * @memberof Cesium3DTileset.prototype
  1414. *
  1415. * @type {Ellipsoid}
  1416. * @readonly
  1417. */
  1418. ellipsoid: {
  1419. get: function () {
  1420. return this._ellipsoid;
  1421. },
  1422. },
  1423. /**
  1424. * Optimization option. Used when {@link Cesium3DTileset#foveatedScreenSpaceError} is true to control the cone size that determines which tiles are deferred.
  1425. * Tiles that are inside this cone are loaded immediately. Tiles outside the cone are potentially deferred based on how far outside the cone they are and {@link Cesium3DTileset#foveatedInterpolationCallback} and {@link Cesium3DTileset#foveatedMinimumScreenSpaceErrorRelaxation}.
  1426. * Setting this to 0.0 means the cone will be the line formed by the camera position and its view direction. Setting this to 1.0 means the cone encompasses the entire field of view of the camera, essentially disabling the effect.
  1427. *
  1428. * @memberof Cesium3DTileset.prototype
  1429. *
  1430. * @type {Number}
  1431. * @default 0.3
  1432. */
  1433. foveatedConeSize: {
  1434. get: function () {
  1435. return this._foveatedConeSize;
  1436. },
  1437. set: function (value) {
  1438. //>>includeStart('debug', pragmas.debug);
  1439. Check.typeOf.number.greaterThanOrEquals("foveatedConeSize", value, 0.0);
  1440. Check.typeOf.number.lessThanOrEquals("foveatedConeSize", value, 1.0);
  1441. //>>includeEnd('debug');
  1442. this._foveatedConeSize = value;
  1443. },
  1444. },
  1445. /**
  1446. * Optimization option. Used when {@link Cesium3DTileset#foveatedScreenSpaceError} is true to control the starting screen space error relaxation for tiles outside the foveated cone.
  1447. * The screen space error will be raised starting with this value up to {@link Cesium3DTileset#maximumScreenSpaceError} based on the provided {@link Cesium3DTileset#foveatedInterpolationCallback}.
  1448. *
  1449. * @memberof Cesium3DTileset.prototype
  1450. *
  1451. * @type {Number}
  1452. * @default 0.0
  1453. */
  1454. foveatedMinimumScreenSpaceErrorRelaxation: {
  1455. get: function () {
  1456. return this._foveatedMinimumScreenSpaceErrorRelaxation;
  1457. },
  1458. set: function (value) {
  1459. //>>includeStart('debug', pragmas.debug);
  1460. Check.typeOf.number.greaterThanOrEquals(
  1461. "foveatedMinimumScreenSpaceErrorRelaxation",
  1462. value,
  1463. 0.0
  1464. );
  1465. Check.typeOf.number.lessThanOrEquals(
  1466. "foveatedMinimumScreenSpaceErrorRelaxation",
  1467. value,
  1468. this.maximumScreenSpaceError
  1469. );
  1470. //>>includeEnd('debug');
  1471. this._foveatedMinimumScreenSpaceErrorRelaxation = value;
  1472. },
  1473. },
  1474. /**
  1475. * Returns the <code>extras</code> property at the top-level of the tileset JSON, which contains application specific metadata.
  1476. * Returns <code>undefined</code> if <code>extras</code> does not exist.
  1477. *
  1478. * @memberof Cesium3DTileset.prototype
  1479. *
  1480. * @exception {DeveloperError} The tileset is not loaded. Use Cesium3DTileset.readyPromise or wait for Cesium3DTileset.ready to be true.
  1481. *
  1482. * @type {*}
  1483. * @readonly
  1484. *
  1485. * @see {@link https://github.com/CesiumGS/3d-tiles/tree/master/specification#specifying-extensions-and-application-specific-extras|Extras in the 3D Tiles specification.}
  1486. */
  1487. extras: {
  1488. get: function () {
  1489. //>>includeStart('debug', pragmas.debug);
  1490. if (!this.ready) {
  1491. throw new DeveloperError(
  1492. "The tileset is not loaded. Use Cesium3DTileset.readyPromise or wait for Cesium3DTileset.ready to be true."
  1493. );
  1494. }
  1495. //>>includeEnd('debug');
  1496. return this._extras;
  1497. },
  1498. },
  1499. /**
  1500. * Cesium adds lighting from the earth, sky, atmosphere, and star skybox. This cartesian is used to scale the final
  1501. * diffuse and specular lighting contribution from those sources to the final color. A value of 0.0 will disable those light sources.
  1502. *
  1503. * @memberof Cesium3DTileset.prototype
  1504. *
  1505. * @type {Cartesian2}
  1506. * @default Cartesian2(1.0, 1.0)
  1507. */
  1508. imageBasedLightingFactor: {
  1509. get: function () {
  1510. return this._imageBasedLightingFactor;
  1511. },
  1512. set: function (value) {
  1513. //>>includeStart('debug', pragmas.debug);
  1514. Check.typeOf.object("imageBasedLightingFactor", value);
  1515. Check.typeOf.number.greaterThanOrEquals(
  1516. "imageBasedLightingFactor.x",
  1517. value.x,
  1518. 0.0
  1519. );
  1520. Check.typeOf.number.lessThanOrEquals(
  1521. "imageBasedLightingFactor.x",
  1522. value.x,
  1523. 1.0
  1524. );
  1525. Check.typeOf.number.greaterThanOrEquals(
  1526. "imageBasedLightingFactor.y",
  1527. value.y,
  1528. 0.0
  1529. );
  1530. Check.typeOf.number.lessThanOrEquals(
  1531. "imageBasedLightingFactor.y",
  1532. value.y,
  1533. 1.0
  1534. );
  1535. //>>includeEnd('debug');
  1536. Cartesian2.clone(value, this._imageBasedLightingFactor);
  1537. },
  1538. },
  1539. });
  1540. /**
  1541. * Provides a hook to override the method used to request the tileset json
  1542. * useful when fetching tilesets from remote servers
  1543. * @param {Resource|String} tilesetUrl The url of the json file to be fetched
  1544. * @returns {Promise.<Object>} A promise that resolves with the fetched json data
  1545. */
  1546. Cesium3DTileset.loadJson = function (tilesetUrl) {
  1547. var resource = Resource.createIfNeeded(tilesetUrl);
  1548. return resource.fetchJson();
  1549. };
  1550. /**
  1551. * Marks the tileset's {@link Cesium3DTileset#style} as dirty, which forces all
  1552. * features to re-evaluate the style in the next frame each is visible.
  1553. */
  1554. Cesium3DTileset.prototype.makeStyleDirty = function () {
  1555. this._styleEngine.makeDirty();
  1556. };
  1557. /**
  1558. * Loads the main tileset JSON file or a tileset JSON file referenced from a tile.
  1559. *
  1560. * @private
  1561. */
  1562. Cesium3DTileset.prototype.loadTileset = function (
  1563. resource,
  1564. tilesetJson,
  1565. parentTile
  1566. ) {
  1567. var asset = tilesetJson.asset;
  1568. if (!defined(asset)) {
  1569. throw new RuntimeError("Tileset must have an asset property.");
  1570. }
  1571. if (asset.version !== "0.0" && asset.version !== "1.0") {
  1572. throw new RuntimeError("The tileset must be 3D Tiles version 0.0 or 1.0.");
  1573. }
  1574. var statistics = this._statistics;
  1575. var tilesetVersion = asset.tilesetVersion;
  1576. if (defined(tilesetVersion)) {
  1577. // Append the tileset version to the resource
  1578. this._basePath += "?v=" + tilesetVersion;
  1579. resource.setQueryParameters({ v: tilesetVersion });
  1580. }
  1581. // A tileset JSON file referenced from a tile may exist in a different directory than the root tileset.
  1582. // Get the basePath relative to the external tileset.
  1583. var rootTile = new Cesium3DTile(this, resource, tilesetJson.root, parentTile);
  1584. // If there is a parentTile, add the root of the currently loading tileset
  1585. // to parentTile's children, and update its _depth.
  1586. if (defined(parentTile)) {
  1587. parentTile.children.push(rootTile);
  1588. rootTile._depth = parentTile._depth + 1;
  1589. }
  1590. var stack = [];
  1591. stack.push(rootTile);
  1592. while (stack.length > 0) {
  1593. var tile = stack.pop();
  1594. ++statistics.numberOfTilesTotal;
  1595. this._allTilesAdditive =
  1596. this._allTilesAdditive && tile.refine === Cesium3DTileRefine.ADD;
  1597. var children = tile._header.children;
  1598. if (defined(children)) {
  1599. var length = children.length;
  1600. for (var i = 0; i < length; ++i) {
  1601. var childHeader = children[i];
  1602. var childTile = new Cesium3DTile(this, resource, childHeader, tile);
  1603. tile.children.push(childTile);
  1604. childTile._depth = tile._depth + 1;
  1605. stack.push(childTile);
  1606. }
  1607. }
  1608. if (this._cullWithChildrenBounds) {
  1609. Cesium3DTileOptimizations.checkChildrenWithinParent(tile);
  1610. }
  1611. }
  1612. return rootTile;
  1613. };
  1614. var scratchPositionNormal = new Cartesian3();
  1615. var scratchCartographic = new Cartographic();
  1616. var scratchMatrix = new Matrix4();
  1617. var scratchCenter = new Cartesian3();
  1618. var scratchPosition = new Cartesian3();
  1619. var scratchDirection = new Cartesian3();
  1620. function updateDynamicScreenSpaceError(tileset, frameState) {
  1621. var up;
  1622. var direction;
  1623. var height;
  1624. var minimumHeight;
  1625. var maximumHeight;
  1626. var camera = frameState.camera;
  1627. var root = tileset._root;
  1628. var tileBoundingVolume = root.contentBoundingVolume;
  1629. if (tileBoundingVolume instanceof TileBoundingRegion) {
  1630. up = Cartesian3.normalize(camera.positionWC, scratchPositionNormal);
  1631. direction = camera.directionWC;
  1632. height = camera.positionCartographic.height;
  1633. minimumHeight = tileBoundingVolume.minimumHeight;
  1634. maximumHeight = tileBoundingVolume.maximumHeight;
  1635. } else {
  1636. // Transform camera position and direction into the local coordinate system of the tileset
  1637. var transformLocal = Matrix4.inverseTransformation(
  1638. root.computedTransform,
  1639. scratchMatrix
  1640. );
  1641. var ellipsoid = frameState.mapProjection.ellipsoid;
  1642. var boundingVolume = tileBoundingVolume.boundingVolume;
  1643. var centerLocal = Matrix4.multiplyByPoint(
  1644. transformLocal,
  1645. boundingVolume.center,
  1646. scratchCenter
  1647. );
  1648. if (Cartesian3.magnitude(centerLocal) > ellipsoid.minimumRadius) {
  1649. // The tileset is defined in WGS84. Approximate the minimum and maximum height.
  1650. var centerCartographic = Cartographic.fromCartesian(
  1651. centerLocal,
  1652. ellipsoid,
  1653. scratchCartographic
  1654. );
  1655. up = Cartesian3.normalize(camera.positionWC, scratchPositionNormal);
  1656. direction = camera.directionWC;
  1657. height = camera.positionCartographic.height;
  1658. minimumHeight = 0.0;
  1659. maximumHeight = centerCartographic.height * 2.0;
  1660. } else {
  1661. // The tileset is defined in local coordinates (z-up)
  1662. var positionLocal = Matrix4.multiplyByPoint(
  1663. transformLocal,
  1664. camera.positionWC,
  1665. scratchPosition
  1666. );
  1667. up = Cartesian3.UNIT_Z;
  1668. direction = Matrix4.multiplyByPointAsVector(
  1669. transformLocal,
  1670. camera.directionWC,
  1671. scratchDirection
  1672. );
  1673. direction = Cartesian3.normalize(direction, direction);
  1674. height = positionLocal.z;
  1675. if (tileBoundingVolume instanceof TileOrientedBoundingBox) {
  1676. // Assuming z-up, the last component stores the half-height of the box
  1677. var boxHeight = root._header.boundingVolume.box[11];
  1678. minimumHeight = centerLocal.z - boxHeight;
  1679. maximumHeight = centerLocal.z + boxHeight;
  1680. } else if (tileBoundingVolume instanceof TileBoundingSphere) {
  1681. var radius = boundingVolume.radius;
  1682. minimumHeight = centerLocal.z - radius;
  1683. maximumHeight = centerLocal.z + radius;
  1684. }
  1685. }
  1686. }
  1687. // The range where the density starts to lessen. Start at the quarter height of the tileset.
  1688. var heightFalloff = tileset.dynamicScreenSpaceErrorHeightFalloff;
  1689. var heightClose =
  1690. minimumHeight + (maximumHeight - minimumHeight) * heightFalloff;
  1691. var heightFar = maximumHeight;
  1692. var t = CesiumMath.clamp(
  1693. (height - heightClose) / (heightFar - heightClose),
  1694. 0.0,
  1695. 1.0
  1696. );
  1697. // Increase density as the camera tilts towards the horizon
  1698. var dot = Math.abs(Cartesian3.dot(direction, up));
  1699. var horizonFactor = 1.0 - dot;
  1700. // Weaken the horizon factor as the camera height increases, implying the camera is further away from the tileset.
  1701. // The goal is to increase density for the "street view", not when viewing the tileset from a distance.
  1702. horizonFactor = horizonFactor * (1.0 - t);
  1703. var density = tileset.dynamicScreenSpaceErrorDensity;
  1704. density *= horizonFactor;
  1705. tileset._dynamicScreenSpaceErrorComputedDensity = density;
  1706. }
  1707. ///////////////////////////////////////////////////////////////////////////
  1708. function requestContent(tileset, tile) {
  1709. if (tile.hasEmptyContent) {
  1710. return;
  1711. }
  1712. var statistics = tileset._statistics;
  1713. var expired = tile.contentExpired;
  1714. var requested = tile.requestContent();
  1715. if (!requested) {
  1716. ++statistics.numberOfAttemptedRequests;
  1717. return;
  1718. }
  1719. if (expired) {
  1720. if (tile.hasTilesetContent) {
  1721. destroySubtree(tileset, tile);
  1722. } else {
  1723. statistics.decrementLoadCounts(tile.content);
  1724. --statistics.numberOfTilesWithContentReady;
  1725. }
  1726. }
  1727. ++statistics.numberOfPendingRequests;
  1728. tileset._requestedTilesInFlight.push(tile);
  1729. tile.contentReadyToProcessPromise.then(addToProcessingQueue(tileset, tile));
  1730. tile.contentReadyPromise
  1731. .then(handleTileSuccess(tileset, tile))
  1732. .otherwise(handleTileFailure(tileset, tile));
  1733. }
  1734. function sortRequestByPriority(a, b) {
  1735. return a._priority - b._priority;
  1736. }
  1737. /**
  1738. * Perform any pass invariant tasks here. Called after the render pass.
  1739. * @private
  1740. */
  1741. Cesium3DTileset.prototype.postPassesUpdate = function (frameState) {
  1742. if (!this.ready) {
  1743. return;
  1744. }
  1745. cancelOutOfViewRequests(this, frameState);
  1746. raiseLoadProgressEvent(this, frameState);
  1747. this._cache.unloadTiles(this, unloadTile);
  1748. };
  1749. /**
  1750. * Perform any pass invariant tasks here. Called before any passes are executed.
  1751. * @private
  1752. */
  1753. Cesium3DTileset.prototype.prePassesUpdate = function (frameState) {
  1754. if (!this.ready) {
  1755. return;
  1756. }
  1757. processTiles(this, frameState);
  1758. // Update clipping planes
  1759. var clippingPlanes = this._clippingPlanes;
  1760. this._clippingPlanesOriginMatrixDirty = true;
  1761. if (defined(clippingPlanes) && clippingPlanes.enabled) {
  1762. clippingPlanes.update(frameState);
  1763. }
  1764. if (!defined(this._loadTimestamp)) {
  1765. this._loadTimestamp = JulianDate.clone(frameState.time);
  1766. }
  1767. this._timeSinceLoad = Math.max(
  1768. JulianDate.secondsDifference(frameState.time, this._loadTimestamp) * 1000,
  1769. 0.0
  1770. );
  1771. this._skipLevelOfDetail =
  1772. this.skipLevelOfDetail &&
  1773. !defined(this._classificationType) &&
  1774. !this._disableSkipLevelOfDetail &&
  1775. !this._allTilesAdditive;
  1776. if (this.dynamicScreenSpaceError) {
  1777. updateDynamicScreenSpaceError(this, frameState);
  1778. }
  1779. if (frameState.newFrame) {
  1780. this._cache.reset();
  1781. }
  1782. };
  1783. function cancelOutOfViewRequests(tileset, frameState) {
  1784. var requestedTilesInFlight = tileset._requestedTilesInFlight;
  1785. var removeCount = 0;
  1786. var length = requestedTilesInFlight.length;
  1787. for (var i = 0; i < length; ++i) {
  1788. var tile = requestedTilesInFlight[i];
  1789. // NOTE: This is framerate dependant so make sure the threshold check is small
  1790. var outOfView = frameState.frameNumber - tile._touchedFrame >= 1;
  1791. if (tile._contentState !== Cesium3DTileContentState.LOADING) {
  1792. // No longer fetching from host, don't need to track it anymore. Gets marked as LOADING in Cesium3DTile::requestContent().
  1793. ++removeCount;
  1794. continue;
  1795. } else if (outOfView) {
  1796. // RequestScheduler will take care of cancelling it
  1797. tile._request.cancel();
  1798. ++removeCount;
  1799. continue;
  1800. }
  1801. if (removeCount > 0) {
  1802. requestedTilesInFlight[i - removeCount] = tile;
  1803. }
  1804. }
  1805. requestedTilesInFlight.length -= removeCount;
  1806. }
  1807. function requestTiles(tileset, isAsync) {
  1808. // Sort requests by priority before making any requests.
  1809. // This makes it less likely that requests will be cancelled after being issued.
  1810. var requestedTiles = tileset._requestedTiles;
  1811. var length = requestedTiles.length;
  1812. requestedTiles.sort(sortRequestByPriority);
  1813. for (var i = 0; i < length; ++i) {
  1814. requestContent(tileset, requestedTiles[i]);
  1815. }
  1816. }
  1817. function addToProcessingQueue(tileset, tile) {
  1818. return function () {
  1819. tileset._processingQueue.push(tile);
  1820. --tileset._statistics.numberOfPendingRequests;
  1821. ++tileset._statistics.numberOfTilesProcessing;
  1822. };
  1823. }
  1824. function handleTileFailure(tileset, tile) {
  1825. return function (error) {
  1826. var url = tile._contentResource.url;
  1827. var message = defined(error.message) ? error.message : error.toString();
  1828. if (tileset.tileFailed.numberOfListeners > 0) {
  1829. tileset.tileFailed.raiseEvent({
  1830. url: url,
  1831. message: message,
  1832. });
  1833. } else {
  1834. console.log("A 3D tile failed to load: " + url);
  1835. console.log("Error: " + message);
  1836. }
  1837. };
  1838. }
  1839. function handleTileSuccess(tileset, tile) {
  1840. return function () {
  1841. --tileset._statistics.numberOfTilesProcessing;
  1842. if (!tile.hasTilesetContent) {
  1843. // RESEARCH_IDEA: ability to unload tiles (without content) for an
  1844. // external tileset when all the tiles are unloaded.
  1845. tileset._statistics.incrementLoadCounts(tile.content);
  1846. ++tileset._statistics.numberOfTilesWithContentReady;
  1847. ++tileset._statistics.numberOfLoadedTilesTotal;
  1848. // Add to the tile cache. Previously expired tiles are already in the cache and won't get re-added.
  1849. tileset._cache.add(tile);
  1850. }
  1851. tileset.tileLoad.raiseEvent(tile);
  1852. };
  1853. }
  1854. function filterProcessingQueue(tileset) {
  1855. var tiles = tileset._processingQueue;
  1856. var length = tiles.length;
  1857. var removeCount = 0;
  1858. for (var i = 0; i < length; ++i) {
  1859. var tile = tiles[i];
  1860. if (tile._contentState !== Cesium3DTileContentState.PROCESSING) {
  1861. ++removeCount;
  1862. continue;
  1863. }
  1864. if (removeCount > 0) {
  1865. tiles[i - removeCount] = tile;
  1866. }
  1867. }
  1868. tiles.length -= removeCount;
  1869. }
  1870. function processTiles(tileset, frameState) {
  1871. filterProcessingQueue(tileset);
  1872. var tiles = tileset._processingQueue;
  1873. var length = tiles.length;
  1874. // Process tiles in the PROCESSING state so they will eventually move to the READY state.
  1875. for (var i = 0; i < length; ++i) {
  1876. tiles[i].process(tileset, frameState);
  1877. }
  1878. }
  1879. ///////////////////////////////////////////////////////////////////////////
  1880. var scratchCartesian = new Cartesian3();
  1881. var stringOptions = {
  1882. maximumFractionDigits: 3,
  1883. };
  1884. function formatMemoryString(memorySizeInBytes) {
  1885. var memoryInMegabytes = memorySizeInBytes / 1048576;
  1886. if (memoryInMegabytes < 1.0) {
  1887. return memoryInMegabytes.toLocaleString(undefined, stringOptions);
  1888. }
  1889. return Math.round(memoryInMegabytes).toLocaleString();
  1890. }
  1891. function computeTileLabelPosition(tile) {
  1892. var boundingVolume = tile.boundingVolume.boundingVolume;
  1893. var halfAxes = boundingVolume.halfAxes;
  1894. var radius = boundingVolume.radius;
  1895. var position = Cartesian3.clone(boundingVolume.center, scratchCartesian);
  1896. if (defined(halfAxes)) {
  1897. position.x += 0.75 * (halfAxes[0] + halfAxes[3] + halfAxes[6]);
  1898. position.y += 0.75 * (halfAxes[1] + halfAxes[4] + halfAxes[7]);
  1899. position.z += 0.75 * (halfAxes[2] + halfAxes[5] + halfAxes[8]);
  1900. } else if (defined(radius)) {
  1901. var normal = Cartesian3.normalize(boundingVolume.center, scratchCartesian);
  1902. normal = Cartesian3.multiplyByScalar(
  1903. normal,
  1904. 0.75 * radius,
  1905. scratchCartesian
  1906. );
  1907. position = Cartesian3.add(normal, boundingVolume.center, scratchCartesian);
  1908. }
  1909. return position;
  1910. }
  1911. function addTileDebugLabel(tile, tileset, position) {
  1912. var labelString = "";
  1913. var attributes = 0;
  1914. if (tileset.debugShowGeometricError) {
  1915. labelString += "\nGeometric error: " + tile.geometricError;
  1916. attributes++;
  1917. }
  1918. if (tileset.debugShowRenderingStatistics) {
  1919. labelString += "\nCommands: " + tile.commandsLength;
  1920. attributes++;
  1921. // Don't display number of points or triangles if 0.
  1922. var numberOfPoints = tile.content.pointsLength;
  1923. if (numberOfPoints > 0) {
  1924. labelString += "\nPoints: " + tile.content.pointsLength;
  1925. attributes++;
  1926. }
  1927. var numberOfTriangles = tile.content.trianglesLength;
  1928. if (numberOfTriangles > 0) {
  1929. labelString += "\nTriangles: " + tile.content.trianglesLength;
  1930. attributes++;
  1931. }
  1932. labelString += "\nFeatures: " + tile.content.featuresLength;
  1933. attributes++;
  1934. }
  1935. if (tileset.debugShowMemoryUsage) {
  1936. labelString +=
  1937. "\nTexture Memory: " +
  1938. formatMemoryString(tile.content.texturesByteLength);
  1939. labelString +=
  1940. "\nGeometry Memory: " +
  1941. formatMemoryString(tile.content.geometryByteLength);
  1942. attributes += 2;
  1943. }
  1944. if (tileset.debugShowUrl) {
  1945. labelString += "\nUrl: " + tile._header.content.uri;
  1946. attributes++;
  1947. }
  1948. var newLabel = {
  1949. text: labelString.substring(1),
  1950. position: position,
  1951. font: 19 - attributes + "px sans-serif",
  1952. showBackground: true,
  1953. disableDepthTestDistance: Number.POSITIVE_INFINITY,
  1954. };
  1955. return tileset._tileDebugLabels.add(newLabel);
  1956. }
  1957. function updateTileDebugLabels(tileset, frameState) {
  1958. var i;
  1959. var tile;
  1960. var selectedTiles = tileset._selectedTiles;
  1961. var selectedLength = selectedTiles.length;
  1962. var emptyTiles = tileset._emptyTiles;
  1963. var emptyLength = emptyTiles.length;
  1964. tileset._tileDebugLabels.removeAll();
  1965. if (tileset.debugPickedTileLabelOnly) {
  1966. if (defined(tileset.debugPickedTile)) {
  1967. var position = defined(tileset.debugPickPosition)
  1968. ? tileset.debugPickPosition
  1969. : computeTileLabelPosition(tileset.debugPickedTile);
  1970. var label = addTileDebugLabel(tileset.debugPickedTile, tileset, position);
  1971. label.pixelOffset = new Cartesian2(15, -15); // Offset to avoid picking the label.
  1972. }
  1973. } else {
  1974. for (i = 0; i < selectedLength; ++i) {
  1975. tile = selectedTiles[i];
  1976. addTileDebugLabel(tile, tileset, computeTileLabelPosition(tile));
  1977. }
  1978. for (i = 0; i < emptyLength; ++i) {
  1979. tile = emptyTiles[i];
  1980. if (tile.hasTilesetContent) {
  1981. addTileDebugLabel(tile, tileset, computeTileLabelPosition(tile));
  1982. }
  1983. }
  1984. }
  1985. tileset._tileDebugLabels.update(frameState);
  1986. }
  1987. function updateTiles(tileset, frameState, passOptions) {
  1988. tileset._styleEngine.applyStyle(tileset, passOptions);
  1989. var isRender = passOptions.isRender;
  1990. var statistics = tileset._statistics;
  1991. var commandList = frameState.commandList;
  1992. var numberOfInitialCommands = commandList.length;
  1993. var selectedTiles = tileset._selectedTiles;
  1994. var selectedLength = selectedTiles.length;
  1995. var emptyTiles = tileset._emptyTiles;
  1996. var emptyLength = emptyTiles.length;
  1997. var tileVisible = tileset.tileVisible;
  1998. var i;
  1999. var tile;
  2000. var bivariateVisibilityTest =
  2001. tileset._skipLevelOfDetail &&
  2002. tileset._hasMixedContent &&
  2003. frameState.context.stencilBuffer &&
  2004. selectedLength > 0;
  2005. tileset._backfaceCommands.length = 0;
  2006. if (bivariateVisibilityTest) {
  2007. if (!defined(tileset._stencilClearCommand)) {
  2008. tileset._stencilClearCommand = new ClearCommand({
  2009. stencil: 0,
  2010. pass: Pass.CESIUM_3D_TILE,
  2011. renderState: RenderState.fromCache({
  2012. stencilMask: StencilConstants.SKIP_LOD_MASK,
  2013. }),
  2014. });
  2015. }
  2016. commandList.push(tileset._stencilClearCommand);
  2017. }
  2018. var lengthBeforeUpdate = commandList.length;
  2019. for (i = 0; i < selectedLength; ++i) {
  2020. tile = selectedTiles[i];
  2021. // Raise the tileVisible event before update in case the tileVisible event
  2022. // handler makes changes that update needs to apply to WebGL resources
  2023. if (isRender) {
  2024. tileVisible.raiseEvent(tile);
  2025. }
  2026. tile.update(tileset, frameState, passOptions);
  2027. statistics.incrementSelectionCounts(tile.content);
  2028. ++statistics.selected;
  2029. }
  2030. for (i = 0; i < emptyLength; ++i) {
  2031. tile = emptyTiles[i];
  2032. tile.update(tileset, frameState, passOptions);
  2033. }
  2034. var addedCommandsLength = commandList.length - lengthBeforeUpdate;
  2035. tileset._backfaceCommands.trim();
  2036. if (bivariateVisibilityTest) {
  2037. /*
  2038. * Consider 'effective leaf' tiles as selected tiles that have no selected descendants. They may have children,
  2039. * but they are currently our effective leaves because they do not have selected descendants. These tiles
  2040. * are those where with tile._finalResolution === true.
  2041. * Let 'unresolved' tiles be those with tile._finalResolution === false.
  2042. *
  2043. * 1. Render just the backfaces of unresolved tiles in order to lay down z
  2044. * 2. Render all frontfaces wherever tile._selectionDepth > stencilBuffer.
  2045. * Replace stencilBuffer with tile._selectionDepth, when passing the z test.
  2046. * Because children are always drawn before ancestors {@link Cesium3DTilesetTraversal#traverseAndSelect},
  2047. * this effectively draws children first and does not draw ancestors if a descendant has already
  2048. * been drawn at that pixel.
  2049. * Step 1 prevents child tiles from appearing on top when they are truly behind ancestor content.
  2050. * If they are behind the backfaces of the ancestor, then they will not be drawn.
  2051. *
  2052. * NOTE: Step 2 sometimes causes visual artifacts when backfacing child content has some faces that
  2053. * partially face the camera and are inside of the ancestor content. Because they are inside, they will
  2054. * not be culled by the depth writes in Step 1, and because they partially face the camera, the stencil tests
  2055. * will draw them on top of the ancestor content.
  2056. *
  2057. * NOTE: Because we always render backfaces of unresolved tiles, if the camera is looking at the backfaces
  2058. * of an object, they will always be drawn while loading, even if backface culling is enabled.
  2059. */
  2060. var backfaceCommands = tileset._backfaceCommands.values;
  2061. var backfaceCommandsLength = backfaceCommands.length;
  2062. commandList.length += backfaceCommandsLength;
  2063. // copy commands to the back of the commandList
  2064. for (i = addedCommandsLength - 1; i >= 0; --i) {
  2065. commandList[lengthBeforeUpdate + backfaceCommandsLength + i] =
  2066. commandList[lengthBeforeUpdate + i];
  2067. }
  2068. // move backface commands to the front of the commandList
  2069. for (i = 0; i < backfaceCommandsLength; ++i) {
  2070. commandList[lengthBeforeUpdate + i] = backfaceCommands[i];
  2071. }
  2072. }
  2073. // Number of commands added by each update above
  2074. addedCommandsLength = commandList.length - numberOfInitialCommands;
  2075. statistics.numberOfCommands = addedCommandsLength;
  2076. // Only run EDL if simple attenuation is on
  2077. if (
  2078. isRender &&
  2079. tileset.pointCloudShading.attenuation &&
  2080. tileset.pointCloudShading.eyeDomeLighting &&
  2081. addedCommandsLength > 0
  2082. ) {
  2083. tileset._pointCloudEyeDomeLighting.update(
  2084. frameState,
  2085. numberOfInitialCommands,
  2086. tileset.pointCloudShading,
  2087. tileset.boundingSphere
  2088. );
  2089. }
  2090. if (isRender) {
  2091. if (
  2092. tileset.debugShowGeometricError ||
  2093. tileset.debugShowRenderingStatistics ||
  2094. tileset.debugShowMemoryUsage ||
  2095. tileset.debugShowUrl
  2096. ) {
  2097. if (!defined(tileset._tileDebugLabels)) {
  2098. tileset._tileDebugLabels = new LabelCollection();
  2099. }
  2100. updateTileDebugLabels(tileset, frameState);
  2101. } else {
  2102. tileset._tileDebugLabels =
  2103. tileset._tileDebugLabels && tileset._tileDebugLabels.destroy();
  2104. }
  2105. }
  2106. }
  2107. var scratchStack = [];
  2108. function destroySubtree(tileset, tile) {
  2109. var root = tile;
  2110. var stack = scratchStack;
  2111. stack.push(tile);
  2112. while (stack.length > 0) {
  2113. tile = stack.pop();
  2114. var children = tile.children;
  2115. var length = children.length;
  2116. for (var i = 0; i < length; ++i) {
  2117. stack.push(children[i]);
  2118. }
  2119. if (tile !== root) {
  2120. destroyTile(tileset, tile);
  2121. --tileset._statistics.numberOfTilesTotal;
  2122. }
  2123. }
  2124. root.children = [];
  2125. }
  2126. function unloadTile(tileset, tile) {
  2127. tileset.tileUnload.raiseEvent(tile);
  2128. tileset._statistics.decrementLoadCounts(tile.content);
  2129. --tileset._statistics.numberOfTilesWithContentReady;
  2130. tile.unloadContent();
  2131. }
  2132. function destroyTile(tileset, tile) {
  2133. tileset._cache.unloadTile(tileset, tile, unloadTile);
  2134. tile.destroy();
  2135. }
  2136. /**
  2137. * Unloads all tiles that weren't selected the previous frame. This can be used to
  2138. * explicitly manage the tile cache and reduce the total number of tiles loaded below
  2139. * {@link Cesium3DTileset#maximumMemoryUsage}.
  2140. * <p>
  2141. * Tile unloads occur at the next frame to keep all the WebGL delete calls
  2142. * within the render loop.
  2143. * </p>
  2144. */
  2145. Cesium3DTileset.prototype.trimLoadedTiles = function () {
  2146. this._cache.trim();
  2147. };
  2148. ///////////////////////////////////////////////////////////////////////////
  2149. function raiseLoadProgressEvent(tileset, frameState) {
  2150. var statistics = tileset._statistics;
  2151. var statisticsLast = tileset._statisticsLast;
  2152. var numberOfPendingRequests = statistics.numberOfPendingRequests;
  2153. var numberOfTilesProcessing = statistics.numberOfTilesProcessing;
  2154. var lastNumberOfPendingRequest = statisticsLast.numberOfPendingRequests;
  2155. var lastNumberOfTilesProcessing = statisticsLast.numberOfTilesProcessing;
  2156. Cesium3DTilesetStatistics.clone(statistics, statisticsLast);
  2157. var progressChanged =
  2158. numberOfPendingRequests !== lastNumberOfPendingRequest ||
  2159. numberOfTilesProcessing !== lastNumberOfTilesProcessing;
  2160. if (progressChanged) {
  2161. frameState.afterRender.push(function () {
  2162. tileset.loadProgress.raiseEvent(
  2163. numberOfPendingRequests,
  2164. numberOfTilesProcessing
  2165. );
  2166. });
  2167. }
  2168. tileset._tilesLoaded =
  2169. statistics.numberOfPendingRequests === 0 &&
  2170. statistics.numberOfTilesProcessing === 0 &&
  2171. statistics.numberOfAttemptedRequests === 0;
  2172. // Events are raised (added to the afterRender queue) here since promises
  2173. // may resolve outside of the update loop that then raise events, e.g.,
  2174. // model's readyPromise.
  2175. if (progressChanged && tileset._tilesLoaded) {
  2176. frameState.afterRender.push(function () {
  2177. tileset.allTilesLoaded.raiseEvent();
  2178. });
  2179. if (!tileset._initialTilesLoaded) {
  2180. tileset._initialTilesLoaded = true;
  2181. frameState.afterRender.push(function () {
  2182. tileset.initialTilesLoaded.raiseEvent();
  2183. });
  2184. }
  2185. }
  2186. }
  2187. function resetMinimumMaximum(tileset) {
  2188. tileset._heatmap.resetMinimumMaximum();
  2189. tileset._minimumPriority.depth = Number.MAX_VALUE;
  2190. tileset._maximumPriority.depth = -Number.MAX_VALUE;
  2191. tileset._minimumPriority.foveatedFactor = Number.MAX_VALUE;
  2192. tileset._maximumPriority.foveatedFactor = -Number.MAX_VALUE;
  2193. tileset._minimumPriority.distance = Number.MAX_VALUE;
  2194. tileset._maximumPriority.distance = -Number.MAX_VALUE;
  2195. tileset._minimumPriority.reverseScreenSpaceError = Number.MAX_VALUE;
  2196. tileset._maximumPriority.reverseScreenSpaceError = -Number.MAX_VALUE;
  2197. }
  2198. function detectModelMatrixChanged(tileset, frameState) {
  2199. if (
  2200. frameState.frameNumber !== tileset._updatedModelMatrixFrame ||
  2201. !defined(tileset._previousModelMatrix)
  2202. ) {
  2203. tileset._updatedModelMatrixFrame = frameState.frameNumber;
  2204. tileset._modelMatrixChanged = !Matrix4.equals(
  2205. tileset.modelMatrix,
  2206. tileset._previousModelMatrix
  2207. );
  2208. tileset._previousModelMatrix = Matrix4.clone(
  2209. tileset.modelMatrix,
  2210. tileset._previousModelMatrix
  2211. );
  2212. }
  2213. }
  2214. ///////////////////////////////////////////////////////////////////////////
  2215. function update(tileset, frameState, passStatistics, passOptions) {
  2216. if (frameState.mode === SceneMode.MORPHING) {
  2217. return false;
  2218. }
  2219. if (!tileset.ready) {
  2220. return false;
  2221. }
  2222. var statistics = tileset._statistics;
  2223. statistics.clear();
  2224. var isRender = passOptions.isRender;
  2225. // Resets the visibility check for each pass
  2226. ++tileset._updatedVisibilityFrame;
  2227. // Update any tracked min max values
  2228. resetMinimumMaximum(tileset);
  2229. detectModelMatrixChanged(tileset, frameState);
  2230. tileset._cullRequestsWhileMoving =
  2231. tileset.cullRequestsWhileMoving && !tileset._modelMatrixChanged;
  2232. var ready = passOptions.traversal.selectTiles(tileset, frameState);
  2233. if (passOptions.requestTiles) {
  2234. requestTiles(tileset);
  2235. }
  2236. updateTiles(tileset, frameState, passOptions);
  2237. // Update pass statistics
  2238. Cesium3DTilesetStatistics.clone(statistics, passStatistics);
  2239. if (isRender) {
  2240. var credits = tileset._credits;
  2241. if (defined(credits) && statistics.selected !== 0) {
  2242. var length = credits.length;
  2243. for (var i = 0; i < length; ++i) {
  2244. frameState.creditDisplay.addCredit(credits[i]);
  2245. }
  2246. }
  2247. }
  2248. return ready;
  2249. }
  2250. /**
  2251. * @private
  2252. */
  2253. Cesium3DTileset.prototype.update = function (frameState) {
  2254. this.updateForPass(frameState, frameState.tilesetPassState);
  2255. };
  2256. /**
  2257. * @private
  2258. */
  2259. Cesium3DTileset.prototype.updateForPass = function (
  2260. frameState,
  2261. tilesetPassState
  2262. ) {
  2263. //>>includeStart('debug', pragmas.debug);
  2264. Check.typeOf.object("frameState", frameState);
  2265. Check.typeOf.object("tilesetPassState", tilesetPassState);
  2266. //>>includeEnd('debug');
  2267. var pass = tilesetPassState.pass;
  2268. if (
  2269. (pass === Cesium3DTilePass.PRELOAD &&
  2270. (!this.preloadWhenHidden || this.show)) ||
  2271. (pass === Cesium3DTilePass.PRELOAD_FLIGHT &&
  2272. (!this.preloadFlightDestinations ||
  2273. (!this.show && !this.preloadWhenHidden))) ||
  2274. (pass === Cesium3DTilePass.REQUEST_RENDER_MODE_DEFER_CHECK &&
  2275. ((!this._cullRequestsWhileMoving && this.foveatedTimeDelay <= 0) ||
  2276. !this.show))
  2277. ) {
  2278. return;
  2279. }
  2280. var originalCommandList = frameState.commandList;
  2281. var originalCamera = frameState.camera;
  2282. var originalCullingVolume = frameState.cullingVolume;
  2283. tilesetPassState.ready = false;
  2284. var passOptions = Cesium3DTilePass.getPassOptions(pass);
  2285. var ignoreCommands = passOptions.ignoreCommands;
  2286. var commandList = defaultValue(
  2287. tilesetPassState.commandList,
  2288. originalCommandList
  2289. );
  2290. var commandStart = commandList.length;
  2291. frameState.commandList = commandList;
  2292. frameState.camera = defaultValue(tilesetPassState.camera, originalCamera);
  2293. frameState.cullingVolume = defaultValue(
  2294. tilesetPassState.cullingVolume,
  2295. originalCullingVolume
  2296. );
  2297. var passStatistics = this._statisticsPerPass[pass];
  2298. if (this.show || ignoreCommands) {
  2299. this._pass = pass;
  2300. tilesetPassState.ready = update(
  2301. this,
  2302. frameState,
  2303. passStatistics,
  2304. passOptions
  2305. );
  2306. }
  2307. if (ignoreCommands) {
  2308. commandList.length = commandStart;
  2309. }
  2310. frameState.commandList = originalCommandList;
  2311. frameState.camera = originalCamera;
  2312. frameState.cullingVolume = originalCullingVolume;
  2313. };
  2314. /**
  2315. * <code>true</code> if the tileset JSON file lists the extension in extensionsUsed; otherwise, <code>false</code>.
  2316. * @param {String} extensionName The name of the extension to check.
  2317. *
  2318. * @returns {Boolean} <code>true</code> if the tileset JSON file lists the extension in extensionsUsed; otherwise, <code>false</code>.
  2319. */
  2320. Cesium3DTileset.prototype.hasExtension = function (extensionName) {
  2321. if (!defined(this._extensionsUsed)) {
  2322. return false;
  2323. }
  2324. return this._extensionsUsed.indexOf(extensionName) > -1;
  2325. };
  2326. /**
  2327. * Returns true if this object was destroyed; otherwise, false.
  2328. * <br /><br />
  2329. * If this object was destroyed, it should not be used; calling any function other than
  2330. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  2331. *
  2332. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  2333. *
  2334. * @see Cesium3DTileset#destroy
  2335. */
  2336. Cesium3DTileset.prototype.isDestroyed = function () {
  2337. return false;
  2338. };
  2339. /**
  2340. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  2341. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  2342. * <br /><br />
  2343. * Once an object is destroyed, it should not be used; calling any function other than
  2344. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  2345. * assign the return value (<code>undefined</code>) to the object as done in the example.
  2346. *
  2347. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  2348. *
  2349. * @example
  2350. * tileset = tileset && tileset.destroy();
  2351. *
  2352. * @see Cesium3DTileset#isDestroyed
  2353. */
  2354. Cesium3DTileset.prototype.destroy = function () {
  2355. this._tileDebugLabels =
  2356. this._tileDebugLabels && this._tileDebugLabels.destroy();
  2357. this._clippingPlanes = this._clippingPlanes && this._clippingPlanes.destroy();
  2358. // Traverse the tree and destroy all tiles
  2359. if (defined(this._root)) {
  2360. var stack = scratchStack;
  2361. stack.push(this._root);
  2362. while (stack.length > 0) {
  2363. var tile = stack.pop();
  2364. tile.destroy();
  2365. var children = tile.children;
  2366. var length = children.length;
  2367. for (var i = 0; i < length; ++i) {
  2368. stack.push(children[i]);
  2369. }
  2370. }
  2371. }
  2372. this._root = undefined;
  2373. return destroyObject(this);
  2374. };
  2375. /**
  2376. * Optimization option. Used as a callback when {@link Cesium3DTileset#foveatedScreenSpaceError} is true to control how much to raise the screen space error for tiles outside the foveated cone,
  2377. * interpolating between {@link Cesium3DTileset#foveatedMinimumScreenSpaceErrorRelaxation} and {@link Cesium3DTileset#maximumScreenSpaceError}.
  2378. *
  2379. * @callback Cesium3DTileset.foveatedInterpolationCallback
  2380. * @default Math.lerp
  2381. *
  2382. * @param {Number} p The start value to interpolate.
  2383. * @param {Number} q The end value to interpolate.
  2384. * @param {Number} time The time of interpolation generally in the range <code>[0.0, 1.0]</code>.
  2385. * @returns {Number} The interpolated value.
  2386. */
  2387. export default Cesium3DTileset;