GlobeSurfaceTileProvider.js 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031
  1. /*global define*/
  2. define([
  3. '../Core/BoundingSphere',
  4. '../Core/Cartesian2',
  5. '../Core/Cartesian3',
  6. '../Core/Cartesian4',
  7. '../Core/Color',
  8. '../Core/defined',
  9. '../Core/defineProperties',
  10. '../Core/destroyObject',
  11. '../Core/DeveloperError',
  12. '../Core/Event',
  13. '../Core/FeatureDetection',
  14. '../Core/GeometryPipeline',
  15. '../Core/IndexDatatype',
  16. '../Core/Intersect',
  17. '../Core/Matrix4',
  18. '../Core/PrimitiveType',
  19. '../Core/Rectangle',
  20. '../Core/Visibility',
  21. '../Core/WebMercatorProjection',
  22. '../Renderer/BufferUsage',
  23. '../Renderer/DrawCommand',
  24. '../Scene/BlendingState',
  25. '../Scene/DepthFunction',
  26. '../Scene/Pass',
  27. '../ThirdParty/when',
  28. './GlobeSurfaceTile',
  29. './ImageryLayer',
  30. './ImageryState',
  31. './QuadtreeTileLoadState',
  32. './SceneMode'
  33. ], function(
  34. BoundingSphere,
  35. Cartesian2,
  36. Cartesian3,
  37. Cartesian4,
  38. Color,
  39. defined,
  40. defineProperties,
  41. destroyObject,
  42. DeveloperError,
  43. Event,
  44. FeatureDetection,
  45. GeometryPipeline,
  46. IndexDatatype,
  47. Intersect,
  48. Matrix4,
  49. PrimitiveType,
  50. Rectangle,
  51. Visibility,
  52. WebMercatorProjection,
  53. BufferUsage,
  54. DrawCommand,
  55. BlendingState,
  56. DepthFunction,
  57. Pass,
  58. when,
  59. GlobeSurfaceTile,
  60. ImageryLayer,
  61. ImageryState,
  62. QuadtreeTileLoadState,
  63. SceneMode) {
  64. "use strict";
  65. /**
  66. * Provides quadtree tiles representing the surface of the globe. This type is intended to be used
  67. * with {@link QuadtreePrimitive}.
  68. *
  69. * @alias GlobeSurfaceTileProvider
  70. * @constructor
  71. *
  72. * @param {TerrainProvider} options.terrainProvider The terrain provider that describes the surface geometry.
  73. * @param {ImageryLayerCollection} option.imageryLayers The collection of imagery layers describing the shading of the surface.
  74. * @param {GlobeSurfaceShaderSet} options.surfaceShaderSet The set of shaders used to render the surface.
  75. *
  76. * @private
  77. */
  78. var GlobeSurfaceTileProvider = function GlobeSurfaceTileProvider(options) {
  79. //>>includeStart('debug', pragmas.debug);
  80. if (!defined(options)) {
  81. throw new DeveloperError('options is required.');
  82. }
  83. if (!defined(options.terrainProvider)) {
  84. throw new DeveloperError('options.terrainProvider is required.');
  85. } else if (!defined(options.imageryLayers)) {
  86. throw new DeveloperError('options.imageryLayers is required.');
  87. } else if (!defined(options.surfaceShaderSet)) {
  88. throw new DeveloperError('options.surfaceShaderSet is required.');
  89. }
  90. //>>includeEnd('debug');
  91. this.lightingFadeOutDistance = 6500000.0;
  92. this.lightingFadeInDistance = 9000000.0;
  93. this.hasWaterMask = false;
  94. this.oceanNormalMap = undefined;
  95. this.zoomedOutOceanSpecularIntensity = 0.5;
  96. this.enableLighting = false;
  97. this._quadtree = undefined;
  98. this._terrainProvider = options.terrainProvider;
  99. this._imageryLayers = options.imageryLayers;
  100. this._surfaceShaderSet = options.surfaceShaderSet;
  101. this._renderState = undefined;
  102. this._blendRenderState = undefined;
  103. this._errorEvent = new Event();
  104. this._imageryLayers.layerAdded.addEventListener(GlobeSurfaceTileProvider.prototype._onLayerAdded, this);
  105. this._imageryLayers.layerRemoved.addEventListener(GlobeSurfaceTileProvider.prototype._onLayerRemoved, this);
  106. this._imageryLayers.layerMoved.addEventListener(GlobeSurfaceTileProvider.prototype._onLayerMoved, this);
  107. this._imageryLayers.layerShownOrHidden.addEventListener(GlobeSurfaceTileProvider.prototype._onLayerShownOrHidden, this);
  108. this._layerOrderChanged = false;
  109. this._tilesToRenderByTextureCount = [];
  110. this._drawCommands = [];
  111. this._uniformMaps = [];
  112. this._usedDrawCommands = 0;
  113. this._debug = {
  114. wireframe : false,
  115. boundingSphereTile : undefined
  116. };
  117. this._baseColor = undefined;
  118. this._firstPassInitialColor = undefined;
  119. this.baseColor = new Color(0.0, 0.0, 0.5, 1.0);
  120. };
  121. defineProperties(GlobeSurfaceTileProvider.prototype, {
  122. /**
  123. * Gets or sets the color of the globe when no imagery is available.
  124. * @memberof GlobeSurfaceTileProvider.prototype
  125. * @type {Color}
  126. */
  127. baseColor : {
  128. get : function() {
  129. return this._baseColor;
  130. },
  131. set : function(value) {
  132. //>>includeStart('debug', pragmas.debug);
  133. if (!defined(value)) {
  134. throw new DeveloperError('value is required.');
  135. }
  136. //>>includeEnd('debug');
  137. this._baseColor = value;
  138. this._firstPassInitialColor = Cartesian4.fromColor(value, this._firstPassInitialColor);
  139. }
  140. },
  141. /**
  142. * Gets or sets the {@link QuadtreePrimitive} for which this provider is
  143. * providing tiles. This property may be undefined if the provider is not yet associated
  144. * with a {@link QuadtreePrimitive}.
  145. * @memberof GlobeSurfaceTileProvider.prototype
  146. * @type {QuadtreePrimitive}
  147. */
  148. quadtree : {
  149. get : function() {
  150. return this._quadtree;
  151. },
  152. set : function(value) {
  153. //>>includeStart('debug', pragmas.debug);
  154. if (!defined(value)) {
  155. throw new DeveloperError('value is required.');
  156. }
  157. //>>includeEnd('debug');
  158. this._quadtree = value;
  159. }
  160. },
  161. /**
  162. * Gets a value indicating whether or not the provider is ready for use.
  163. * @memberof GlobeSurfaceTileProvider.prototype
  164. * @type {Boolean}
  165. */
  166. ready : {
  167. get : function() {
  168. return this._terrainProvider.ready && (this._imageryLayers.length === 0 || this._imageryLayers.get(0).imageryProvider.ready);
  169. }
  170. },
  171. /**
  172. * Gets the tiling scheme used by the provider. This property should
  173. * not be accessed before {@link GlobeSurfaceTileProvider#ready} returns true.
  174. * @memberof GlobeSurfaceTileProvider.prototype
  175. * @type {TilingScheme}
  176. */
  177. tilingScheme : {
  178. get : function() {
  179. return this._terrainProvider.tilingScheme;
  180. }
  181. },
  182. /**
  183. * Gets an event that is raised when the geometry provider encounters an asynchronous error. By subscribing
  184. * to the event, you will be notified of the error and can potentially recover from it. Event listeners
  185. * are passed an instance of {@link TileProviderError}.
  186. * @memberof GlobeSurfaceTileProvider.prototype
  187. * @type {Event}
  188. */
  189. errorEvent : {
  190. get : function() {
  191. return this._errorEvent;
  192. }
  193. },
  194. /**
  195. * Gets or sets the terrain provider that describes the surface geometry.
  196. * @memberof GlobeSurfaceTileProvider.prototype
  197. * @type {TerrainProvider}
  198. */
  199. terrainProvider : {
  200. get : function() {
  201. return this._terrainProvider;
  202. },
  203. set : function(terrainProvider) {
  204. if (this._terrainProvider === terrainProvider) {
  205. return;
  206. }
  207. //>>includeStart('debug', pragmas.debug);
  208. if (!defined(terrainProvider)) {
  209. throw new DeveloperError('terrainProvider is required.');
  210. }
  211. //>>includeEnd('debug');
  212. this._terrainProvider = terrainProvider;
  213. if (defined(this._quadtree)) {
  214. this._quadtree.invalidateAllTiles();
  215. }
  216. }
  217. }
  218. });
  219. function sortTileImageryByLayerIndex(a, b) {
  220. var aImagery = a.loadingImagery;
  221. if (!defined(aImagery)) {
  222. aImagery = a.readyImagery;
  223. }
  224. var bImagery = b.loadingImagery;
  225. if (!defined(bImagery)) {
  226. bImagery = b.readyImagery;
  227. }
  228. return aImagery.imageryLayer._layerIndex - bImagery.imageryLayer._layerIndex;
  229. }
  230. /**
  231. * Called at the beginning of the update cycle for each render frame, before {@link QuadtreeTileProvider#showTileThisFrame}
  232. * or any other functions.
  233. *
  234. * @param {Context} context The rendering context.
  235. * @param {FrameState} frameState The frame state.
  236. * @param {DrawCommand[]} commandList An array of rendering commands. This method may push
  237. * commands into this array.
  238. */
  239. GlobeSurfaceTileProvider.prototype.beginUpdate = function(context, frameState, commandList) {
  240. this._imageryLayers._update();
  241. if (this._layerOrderChanged) {
  242. this._layerOrderChanged = false;
  243. // Sort the TileImagery instances in each tile by the layer index.
  244. this._quadtree.forEachLoadedTile(function(tile) {
  245. tile.data.imagery.sort(sortTileImageryByLayerIndex);
  246. });
  247. }
  248. var i;
  249. var len;
  250. var tilesToRenderByTextureCount = this._tilesToRenderByTextureCount;
  251. for (i = 0, len = tilesToRenderByTextureCount.length; i < len; ++i) {
  252. var tiles = tilesToRenderByTextureCount[i];
  253. if (defined(tiles)) {
  254. tiles.length = 0;
  255. }
  256. }
  257. this._usedDrawCommands = 0;
  258. // Add credits for terrain and imagery providers.
  259. var creditDisplay = frameState.creditDisplay;
  260. if (this._terrainProvider.ready && defined(this._terrainProvider.credit)) {
  261. creditDisplay.addCredit(this._terrainProvider.credit);
  262. }
  263. var imageryLayers = this._imageryLayers;
  264. for (i = 0, len = imageryLayers.length; i < len; ++i) {
  265. var imageryProvider = imageryLayers.get(i).imageryProvider;
  266. if (imageryProvider.ready && defined(imageryProvider.credit)) {
  267. creditDisplay.addCredit(imageryProvider.credit);
  268. }
  269. }
  270. };
  271. /**
  272. * Called at the end of the update cycle for each render frame, after {@link QuadtreeTileProvider#showTileThisFrame}
  273. * and any other functions.
  274. *
  275. * @param {Context} context The rendering context.
  276. * @param {FrameState} frameState The frame state.
  277. * @param {DrawCommand[]} commandList An array of rendering commands. This method may push
  278. * commands into this array.
  279. */
  280. GlobeSurfaceTileProvider.prototype.endUpdate = function(context, frameState, commandList) {
  281. if (!defined(this._renderState)) {
  282. this._renderState = context.createRenderState({ // Write color and depth
  283. cull : {
  284. enabled : true
  285. },
  286. depthTest : {
  287. enabled : true
  288. }
  289. });
  290. }
  291. if (!defined(this._blendRenderState)) {
  292. this._blendRenderState = context.createRenderState({ // Write color and depth
  293. cull : {
  294. enabled : true
  295. },
  296. depthTest : {
  297. enabled : true,
  298. func : DepthFunction.LESS_OR_EQUAL
  299. },
  300. blending : BlendingState.ALPHA_BLEND
  301. });
  302. }
  303. this._renderState.depthTest.enabled = frameState.mode === SceneMode.SCENE3D || frameState.mode === SceneMode.COLUMBUS_VIEW;
  304. this._blendRenderState.depthTest.enabled = this._renderState.depthTest.enabled;
  305. // And the tile render commands to the command list, sorted by texture count.
  306. var tilesToRenderByTextureCount = this._tilesToRenderByTextureCount;
  307. for (var textureCountIndex = 0, textureCountLength = tilesToRenderByTextureCount.length; textureCountIndex < textureCountLength; ++textureCountIndex) {
  308. var tilesToRender = tilesToRenderByTextureCount[textureCountIndex];
  309. if (!defined(tilesToRender)) {
  310. continue;
  311. }
  312. for (var tileIndex = 0, tileLength = tilesToRender.length; tileIndex < tileLength; ++tileIndex) {
  313. addDrawCommandsForTile(this, tilesToRender[tileIndex], context, frameState, commandList);
  314. }
  315. }
  316. };
  317. /**
  318. * Gets the maximum geometric error allowed in a tile at a given level, in meters. This function should not be
  319. * called before {@link GlobeSurfaceTileProvider#ready} returns true.
  320. *
  321. * @param {Number} level The tile level for which to get the maximum geometric error.
  322. * @returns {Number} The maximum geometric error in meters.
  323. */
  324. GlobeSurfaceTileProvider.prototype.getLevelMaximumGeometricError = function(level) {
  325. return this._terrainProvider.getLevelMaximumGeometricError(level);
  326. };
  327. /**
  328. * Loads, or continues loading, a given tile. This function will continue to be called
  329. * until {@link QuadtreeTile#state} is no longer {@link QuadtreeTileLoadState#LOADING}. This function should
  330. * not be called before {@link GlobeSurfaceTileProvider#ready} returns true.
  331. *
  332. * @param {Context} context The rendering context.
  333. * @param {FrameState} frameState The frame state.
  334. * @param {QuadtreeTile} tile The tile to load.
  335. *
  336. * @exception {DeveloperError} <code>loadTile</code> must not be called before the tile provider is ready.
  337. */
  338. GlobeSurfaceTileProvider.prototype.loadTile = function(context, frameState, tile) {
  339. GlobeSurfaceTile.processStateMachine(tile, context, this._terrainProvider, this._imageryLayers);
  340. };
  341. var boundingSphereScratch = new BoundingSphere();
  342. /**
  343. * Determines the visibility of a given tile. The tile may be fully visible, partially visible, or not
  344. * visible at all. Tiles that are renderable and are at least partially visible will be shown by a call
  345. * to {@link GlobeSurfaceTileProvider#showTileThisFrame}.
  346. *
  347. * @param {QuadtreeTile} tile The tile instance.
  348. * @param {FrameState} frameState The state information about the current frame.
  349. * @param {QuadtreeOccluders} occluders The objects that may occlude this tile.
  350. *
  351. * @returns {Visibility} The visibility of the tile.
  352. */
  353. GlobeSurfaceTileProvider.prototype.computeTileVisibility = function(tile, frameState, occluders) {
  354. var surfaceTile = tile.data;
  355. var cullingVolume = frameState.cullingVolume;
  356. var boundingVolume = surfaceTile.boundingSphere3D;
  357. if (frameState.mode !== SceneMode.SCENE3D) {
  358. boundingVolume = boundingSphereScratch;
  359. BoundingSphere.fromRectangleWithHeights2D(tile.rectangle, frameState.mapProjection, surfaceTile.minimumHeight, surfaceTile.maximumHeight, boundingVolume);
  360. Cartesian3.fromElements(boundingVolume.center.z, boundingVolume.center.x, boundingVolume.center.y, boundingVolume.center);
  361. if (frameState.mode === SceneMode.MORPHING) {
  362. boundingVolume = BoundingSphere.union(surfaceTile.boundingSphere3D, boundingVolume, boundingVolume);
  363. }
  364. }
  365. var intersection = cullingVolume.computeVisibility(boundingVolume);
  366. if (intersection === Intersect.OUTSIDE) {
  367. return Visibility.NONE;
  368. }
  369. if (frameState.mode === SceneMode.SCENE3D) {
  370. var occludeePointInScaledSpace = surfaceTile.occludeePointInScaledSpace;
  371. if (!defined(occludeePointInScaledSpace)) {
  372. return intersection;
  373. }
  374. if (occluders.ellipsoid.isScaledSpacePointVisible(occludeePointInScaledSpace)) {
  375. return intersection;
  376. }
  377. return Visibility.NONE;
  378. }
  379. return intersection;
  380. };
  381. var float32ArrayScratch = FeatureDetection.supportsTypedArrays() ? new Float32Array(1) : undefined;
  382. var modifiedModelViewScratch = new Matrix4();
  383. var tileRectangleScratch = new Cartesian4();
  384. var rtcScratch = new Cartesian3();
  385. var centerEyeScratch = new Cartesian4();
  386. var southwestScratch = new Cartesian3();
  387. var northeastScratch = new Cartesian3();
  388. /**
  389. * Shows a specified tile in this frame. The provider can cause the tile to be shown by adding
  390. * render commands to the commandList, or use any other method as appropriate. The tile is not
  391. * expected to be visible next frame as well, unless this method is called next frame, too.
  392. *
  393. * @param {Object} tile The tile instance.
  394. * @param {Context} context The rendering context.
  395. * @param {FrameState} frameState The state information of the current rendering frame.
  396. * @param {DrawCommand[]} commandList The list of rendering commands. This method may add additional commands to this list.
  397. */
  398. GlobeSurfaceTileProvider.prototype.showTileThisFrame = function(tile, context, frameState, commandList) {
  399. var readyTextureCount = 0;
  400. var tileImageryCollection = tile.data.imagery;
  401. for (var i = 0, len = tileImageryCollection.length; i < len; ++i) {
  402. var tileImagery = tileImageryCollection[i];
  403. if (defined(tileImagery.readyImagery) && tileImagery.readyImagery.imageryLayer.alpha !== 0.0) {
  404. ++readyTextureCount;
  405. }
  406. }
  407. var tileSet = this._tilesToRenderByTextureCount[readyTextureCount];
  408. if (!defined(tileSet)) {
  409. tileSet = [];
  410. this._tilesToRenderByTextureCount[readyTextureCount] = tileSet;
  411. }
  412. tileSet.push(tile);
  413. var debug = this._debug;
  414. ++debug.tilesRendered;
  415. debug.texturesRendered += readyTextureCount;
  416. };
  417. var southwestCornerScratch = new Cartesian3();
  418. var northeastCornerScratch = new Cartesian3();
  419. var negativeUnitY = new Cartesian3(0.0, -1.0, 0.0);
  420. var negativeUnitZ = new Cartesian3(0.0, 0.0, -1.0);
  421. var vectorScratch = new Cartesian3();
  422. /**
  423. * Gets the distance from the camera to the closest point on the tile. This is used for level-of-detail selection.
  424. *
  425. * @param {QuadtreeTile} tile The tile instance.
  426. * @param {FrameState} frameState The state information of the current rendering frame.
  427. * @param {Cartesian3} cameraCartesianPosition The position of the camera in world coordinates.
  428. * @param {Cartographic} cameraCartographicPosition The position of the camera in cartographic / geodetic coordinates.
  429. *
  430. * @returns {Number} The distance from the camera to the closest point on the tile, in meters.
  431. */
  432. GlobeSurfaceTileProvider.prototype.computeDistanceToTile = function(tile, frameState) {
  433. var surfaceTile = tile.data;
  434. var southwestCornerCartesian = surfaceTile.southwestCornerCartesian;
  435. var northeastCornerCartesian = surfaceTile.northeastCornerCartesian;
  436. var westNormal = surfaceTile.westNormal;
  437. var southNormal = surfaceTile.southNormal;
  438. var eastNormal = surfaceTile.eastNormal;
  439. var northNormal = surfaceTile.northNormal;
  440. var maximumHeight = surfaceTile.maximumHeight;
  441. if (frameState.mode !== SceneMode.SCENE3D) {
  442. southwestCornerCartesian = frameState.mapProjection.project(Rectangle.southwest(tile.rectangle), southwestCornerScratch);
  443. southwestCornerCartesian.z = southwestCornerCartesian.y;
  444. southwestCornerCartesian.y = southwestCornerCartesian.x;
  445. southwestCornerCartesian.x = 0.0;
  446. northeastCornerCartesian = frameState.mapProjection.project(Rectangle.northeast(tile.rectangle), northeastCornerScratch);
  447. northeastCornerCartesian.z = northeastCornerCartesian.y;
  448. northeastCornerCartesian.y = northeastCornerCartesian.x;
  449. northeastCornerCartesian.x = 0.0;
  450. westNormal = negativeUnitY;
  451. eastNormal = Cartesian3.UNIT_Y;
  452. southNormal = negativeUnitZ;
  453. northNormal = Cartesian3.UNIT_Z;
  454. maximumHeight = 0.0;
  455. }
  456. var cameraCartesianPosition = frameState.camera.positionWC;
  457. var cameraCartographicPosition = frameState.camera.positionCartographic;
  458. var vectorFromSouthwestCorner = Cartesian3.subtract(cameraCartesianPosition, southwestCornerCartesian, vectorScratch);
  459. var distanceToWestPlane = Cartesian3.dot(vectorFromSouthwestCorner, westNormal);
  460. var distanceToSouthPlane = Cartesian3.dot(vectorFromSouthwestCorner, southNormal);
  461. var vectorFromNortheastCorner = Cartesian3.subtract(cameraCartesianPosition, northeastCornerCartesian, vectorScratch);
  462. var distanceToEastPlane = Cartesian3.dot(vectorFromNortheastCorner, eastNormal);
  463. var distanceToNorthPlane = Cartesian3.dot(vectorFromNortheastCorner, northNormal);
  464. var cameraHeight;
  465. if (frameState.mode === SceneMode.SCENE3D) {
  466. cameraHeight = cameraCartographicPosition.height;
  467. } else {
  468. cameraHeight = cameraCartesianPosition.x;
  469. }
  470. var distanceFromTop = cameraHeight - maximumHeight;
  471. var result = 0.0;
  472. if (distanceToWestPlane > 0.0) {
  473. result += distanceToWestPlane * distanceToWestPlane;
  474. } else if (distanceToEastPlane > 0.0) {
  475. result += distanceToEastPlane * distanceToEastPlane;
  476. }
  477. if (distanceToSouthPlane > 0.0) {
  478. result += distanceToSouthPlane * distanceToSouthPlane;
  479. } else if (distanceToNorthPlane > 0.0) {
  480. result += distanceToNorthPlane * distanceToNorthPlane;
  481. }
  482. if (distanceFromTop > 0.0) {
  483. result += distanceFromTop * distanceFromTop;
  484. }
  485. return Math.sqrt(result);
  486. };
  487. /**
  488. * Returns true if this object was destroyed; otherwise, false.
  489. * <br /><br />
  490. * If this object was destroyed, it should not be used; calling any function other than
  491. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  492. *
  493. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  494. *
  495. * @see GlobeSurfaceTileProvider#destroy
  496. */
  497. GlobeSurfaceTileProvider.prototype.isDestroyed = function() {
  498. return false;
  499. };
  500. /**
  501. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  502. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  503. * <br /><br />
  504. * Once an object is destroyed, it should not be used; calling any function other than
  505. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  506. * assign the return value (<code>undefined</code>) to the object as done in the example.
  507. *
  508. * @returns {undefined}
  509. *
  510. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  511. *
  512. * @see GlobeSurfaceTileProvider#isDestroyed
  513. *
  514. * @example
  515. * provider = provider && provider();
  516. */
  517. GlobeSurfaceTileProvider.prototype.destroy = function() {
  518. this._tileProvider = this._tileProvider && this._tileProvider.destroy();
  519. return destroyObject(this);
  520. };
  521. GlobeSurfaceTileProvider.prototype._onLayerAdded = function(layer, index) {
  522. if (layer.show) {
  523. var terrainProvider = this._terrainProvider;
  524. // create TileImagerys for this layer for all previously loaded tiles
  525. this._quadtree.forEachLoadedTile(function(tile) {
  526. if (layer._createTileImagerySkeletons(tile, terrainProvider)) {
  527. tile.state = QuadtreeTileLoadState.LOADING;
  528. }
  529. });
  530. this._layerOrderChanged = true;
  531. }
  532. };
  533. GlobeSurfaceTileProvider.prototype._onLayerRemoved = function(layer, index) {
  534. // destroy TileImagerys for this layer for all previously loaded tiles
  535. this._quadtree.forEachLoadedTile(function(tile) {
  536. var tileImageryCollection = tile.data.imagery;
  537. var startIndex = -1;
  538. var numDestroyed = 0;
  539. for (var i = 0, len = tileImageryCollection.length; i < len; ++i) {
  540. var tileImagery = tileImageryCollection[i];
  541. var imagery = tileImagery.loadingImagery;
  542. if (!defined(imagery)) {
  543. imagery = tileImagery.readyImagery;
  544. }
  545. if (imagery.imageryLayer === layer) {
  546. if (startIndex === -1) {
  547. startIndex = i;
  548. }
  549. tileImagery.freeResources();
  550. ++numDestroyed;
  551. } else if (startIndex !== -1) {
  552. // iterated past the section of TileImagerys belonging to this layer, no need to continue.
  553. break;
  554. }
  555. }
  556. if (startIndex !== -1) {
  557. tileImageryCollection.splice(startIndex, numDestroyed);
  558. }
  559. });
  560. };
  561. GlobeSurfaceTileProvider.prototype._onLayerMoved = function(layer, newIndex, oldIndex) {
  562. this._layerOrderChanged = true;
  563. };
  564. GlobeSurfaceTileProvider.prototype._onLayerShownOrHidden = function(layer, index, show) {
  565. if (show) {
  566. this._onLayerAdded(layer, index);
  567. } else {
  568. this._onLayerRemoved(layer, index);
  569. }
  570. };
  571. function createTileUniformMap() {
  572. var uniformMap = {
  573. u_initialColor : function() {
  574. return this.initialColor;
  575. },
  576. u_zoomedOutOceanSpecularIntensity : function() {
  577. return this.zoomedOutOceanSpecularIntensity;
  578. },
  579. u_oceanNormalMap : function() {
  580. return this.oceanNormalMap;
  581. },
  582. u_lightingFadeDistance : function() {
  583. return this.lightingFadeDistance;
  584. },
  585. u_center3D : function() {
  586. return this.center3D;
  587. },
  588. u_tileRectangle : function() {
  589. return this.tileRectangle;
  590. },
  591. u_modifiedModelView : function() {
  592. return this.modifiedModelView;
  593. },
  594. u_dayTextures : function() {
  595. return this.dayTextures;
  596. },
  597. u_dayTextureTranslationAndScale : function() {
  598. return this.dayTextureTranslationAndScale;
  599. },
  600. u_dayTextureTexCoordsRectangle : function() {
  601. return this.dayTextureTexCoordsRectangle;
  602. },
  603. u_dayTextureAlpha : function() {
  604. return this.dayTextureAlpha;
  605. },
  606. u_dayTextureBrightness : function() {
  607. return this.dayTextureBrightness;
  608. },
  609. u_dayTextureContrast : function() {
  610. return this.dayTextureContrast;
  611. },
  612. u_dayTextureHue : function() {
  613. return this.dayTextureHue;
  614. },
  615. u_dayTextureSaturation : function() {
  616. return this.dayTextureSaturation;
  617. },
  618. u_dayTextureOneOverGamma : function() {
  619. return this.dayTextureOneOverGamma;
  620. },
  621. u_dayIntensity : function() {
  622. return this.dayIntensity;
  623. },
  624. u_southAndNorthLatitude : function() {
  625. return this.southAndNorthLatitude;
  626. },
  627. u_southMercatorYLowAndHighAndOneOverHeight : function() {
  628. return this.southMercatorYLowAndHighAndOneOverHeight;
  629. },
  630. u_waterMask : function() {
  631. return this.waterMask;
  632. },
  633. u_waterMaskTranslationAndScale : function() {
  634. return this.waterMaskTranslationAndScale;
  635. },
  636. initialColor : new Cartesian4(0.0, 0.0, 0.5, 1.0),
  637. zoomedOutOceanSpecularIntensity : 0.5,
  638. oceanNormalMap : undefined,
  639. lightingFadeDistance : new Cartesian2(6500000.0, 9000000.0),
  640. center3D : undefined,
  641. modifiedModelView : new Matrix4(),
  642. tileRectangle : new Cartesian4(),
  643. dayTextures : [],
  644. dayTextureTranslationAndScale : [],
  645. dayTextureTexCoordsRectangle : [],
  646. dayTextureAlpha : [],
  647. dayTextureBrightness : [],
  648. dayTextureContrast : [],
  649. dayTextureHue : [],
  650. dayTextureSaturation : [],
  651. dayTextureOneOverGamma : [],
  652. dayIntensity : 0.0,
  653. southAndNorthLatitude : new Cartesian2(),
  654. southMercatorYLowAndHighAndOneOverHeight : new Cartesian3(),
  655. waterMask : undefined,
  656. waterMaskTranslationAndScale : new Cartesian4()
  657. };
  658. return uniformMap;
  659. }
  660. function createWireframeVertexArrayIfNecessary(context, provider, tile) {
  661. var surfaceTile = tile.data;
  662. if (defined(surfaceTile.wireframeVertexArray)) {
  663. return;
  664. }
  665. if (defined(surfaceTile.meshForWireframePromise)) {
  666. return;
  667. }
  668. surfaceTile.meshForWireframePromise = surfaceTile.terrainData.createMesh(provider._terrainProvider.tilingScheme, tile.x, tile.y, tile.level);
  669. if (!defined(surfaceTile.meshForWireframePromise)) {
  670. // deferrred
  671. return;
  672. }
  673. var vertexArray = surfaceTile.vertexArray;
  674. when(surfaceTile.meshForWireframePromise, function(mesh) {
  675. if (surfaceTile.vertexArray === vertexArray) {
  676. surfaceTile.wireframeVertexArray = createWireframeVertexArray(context, surfaceTile.vertexArray, mesh);
  677. }
  678. surfaceTile.meshForWireframePromise = undefined;
  679. });
  680. }
  681. /**
  682. * Creates a vertex array for wireframe rendering of a terrain tile.
  683. *
  684. * @private
  685. *
  686. * @param {Context} context The context in which to create the vertex array.
  687. * @param {VertexArray} vertexArray The existing, non-wireframe vertex array. The new vertex array
  688. * will share vertex buffers with this existing one.
  689. * @param {TerrainMesh} terrainMesh The terrain mesh containing non-wireframe indices.
  690. * @returns {VertexArray} The vertex array for wireframe rendering.
  691. */
  692. function createWireframeVertexArray(context, vertexArray, terrainMesh) {
  693. var geometry = {
  694. indices : terrainMesh.indices,
  695. primitiveType : PrimitiveType.TRIANGLES
  696. };
  697. GeometryPipeline.toWireframe(geometry);
  698. var wireframeIndices = geometry.indices;
  699. var wireframeIndexBuffer = context.createIndexBuffer(wireframeIndices, BufferUsage.STATIC_DRAW, IndexDatatype.UNSIGNED_SHORT);
  700. return context.createVertexArray(vertexArray._attributes, wireframeIndexBuffer);
  701. }
  702. var otherPassesInitialColor = new Cartesian4(0.0, 0.0, 0.0, 0.0);
  703. function addDrawCommandsForTile(tileProvider, tile, context, frameState, commandList) {
  704. var surfaceTile = tile.data;
  705. var viewMatrix = frameState.camera.viewMatrix;
  706. var maxTextures = context.maximumTextureImageUnits;
  707. var waterMaskTexture = surfaceTile.waterMaskTexture;
  708. var showReflectiveOcean = tileProvider.hasWaterMask && defined(waterMaskTexture);
  709. var oceanNormalMap = tileProvider.oceanNormalMap;
  710. var showOceanWaves = showReflectiveOcean && defined(oceanNormalMap);
  711. var hasVertexNormals = tileProvider.terrainProvider.ready && tileProvider.terrainProvider.hasVertexNormals;
  712. if (showReflectiveOcean) {
  713. --maxTextures;
  714. }
  715. if (showOceanWaves) {
  716. --maxTextures;
  717. }
  718. var rtc = surfaceTile.center;
  719. // Not used in 3D.
  720. var tileRectangle = tileRectangleScratch;
  721. // Only used for Mercator projections.
  722. var southLatitude = 0.0;
  723. var northLatitude = 0.0;
  724. var southMercatorYHigh = 0.0;
  725. var southMercatorYLow = 0.0;
  726. var oneOverMercatorHeight = 0.0;
  727. var useWebMercatorProjection = false;
  728. if (frameState.mode !== SceneMode.SCENE3D) {
  729. var projection = frameState.mapProjection;
  730. var southwest = projection.project(Rectangle.southwest(tile.rectangle), southwestScratch);
  731. var northeast = projection.project(Rectangle.northeast(tile.rectangle), northeastScratch);
  732. tileRectangle.x = southwest.x;
  733. tileRectangle.y = southwest.y;
  734. tileRectangle.z = northeast.x;
  735. tileRectangle.w = northeast.y;
  736. // In 2D and Columbus View, use the center of the tile for RTC rendering.
  737. if (frameState.mode !== SceneMode.MORPHING) {
  738. rtc = rtcScratch;
  739. rtc.x = 0.0;
  740. rtc.y = (tileRectangle.z + tileRectangle.x) * 0.5;
  741. rtc.z = (tileRectangle.w + tileRectangle.y) * 0.5;
  742. tileRectangle.x -= rtc.y;
  743. tileRectangle.y -= rtc.z;
  744. tileRectangle.z -= rtc.y;
  745. tileRectangle.w -= rtc.z;
  746. }
  747. if (projection instanceof WebMercatorProjection) {
  748. southLatitude = tile.rectangle.south;
  749. northLatitude = tile.rectangle.north;
  750. var southMercatorY = WebMercatorProjection.geodeticLatitudeToMercatorAngle(southLatitude);
  751. var northMercatorY = WebMercatorProjection.geodeticLatitudeToMercatorAngle(northLatitude);
  752. float32ArrayScratch[0] = southMercatorY;
  753. southMercatorYHigh = float32ArrayScratch[0];
  754. southMercatorYLow = southMercatorY - float32ArrayScratch[0];
  755. oneOverMercatorHeight = 1.0 / (northMercatorY - southMercatorY);
  756. useWebMercatorProjection = true;
  757. }
  758. }
  759. var centerEye = centerEyeScratch;
  760. centerEye.x = rtc.x;
  761. centerEye.y = rtc.y;
  762. centerEye.z = rtc.z;
  763. centerEye.w = 1.0;
  764. Matrix4.multiplyByVector(viewMatrix, centerEye, centerEye);
  765. Matrix4.setColumn(viewMatrix, 3, centerEye, modifiedModelViewScratch);
  766. var tileImageryCollection = surfaceTile.imagery;
  767. var imageryIndex = 0;
  768. var imageryLen = tileImageryCollection.length;
  769. var firstPassRenderState = tileProvider._renderState;
  770. var otherPassesRenderState = tileProvider._blendRenderState;
  771. var renderState = firstPassRenderState;
  772. var initialColor = tileProvider._firstPassInitialColor;
  773. do {
  774. var numberOfDayTextures = 0;
  775. var command;
  776. var uniformMap;
  777. if (tileProvider._drawCommands.length <= tileProvider._usedDrawCommands) {
  778. command = new DrawCommand();
  779. command.owner = tile;
  780. command.cull = false;
  781. command.boundingVolume = new BoundingSphere();
  782. uniformMap = createTileUniformMap();
  783. tileProvider._drawCommands.push(command);
  784. tileProvider._uniformMaps.push(uniformMap);
  785. } else {
  786. command = tileProvider._drawCommands[tileProvider._usedDrawCommands];
  787. uniformMap = tileProvider._uniformMaps[tileProvider._usedDrawCommands];
  788. }
  789. command.owner = tile;
  790. ++tileProvider._usedDrawCommands;
  791. command.debugShowBoundingVolume = (tile === tileProvider._debug.boundingSphereTile);
  792. Cartesian4.clone(initialColor, uniformMap.initialColor);
  793. uniformMap.oceanNormalMap = oceanNormalMap;
  794. uniformMap.lightingFadeDistance.x = tileProvider.lightingFadeOutDistance;
  795. uniformMap.lightingFadeDistance.y = tileProvider.lightingFadeInDistance;
  796. uniformMap.zoomedOutOceanSpecularIntensity = tileProvider.zoomedOutOceanSpecularIntensity;
  797. uniformMap.center3D = surfaceTile.center;
  798. Cartesian4.clone(tileRectangle, uniformMap.tileRectangle);
  799. uniformMap.southAndNorthLatitude.x = southLatitude;
  800. uniformMap.southAndNorthLatitude.y = northLatitude;
  801. uniformMap.southMercatorYLowAndHighAndOneOverHeight.x = southMercatorYLow;
  802. uniformMap.southMercatorYLowAndHighAndOneOverHeight.y = southMercatorYHigh;
  803. uniformMap.southMercatorYLowAndHighAndOneOverHeight.z = oneOverMercatorHeight;
  804. Matrix4.clone(modifiedModelViewScratch, uniformMap.modifiedModelView);
  805. var applyBrightness = false;
  806. var applyContrast = false;
  807. var applyHue = false;
  808. var applySaturation = false;
  809. var applyGamma = false;
  810. var applyAlpha = false;
  811. while (numberOfDayTextures < maxTextures && imageryIndex < imageryLen) {
  812. var tileImagery = tileImageryCollection[imageryIndex];
  813. var imagery = tileImagery.readyImagery;
  814. ++imageryIndex;
  815. if (!defined(imagery) || imagery.state !== ImageryState.READY || imagery.imageryLayer.alpha === 0.0) {
  816. continue;
  817. }
  818. var imageryLayer = imagery.imageryLayer;
  819. if (!defined(tileImagery.textureTranslationAndScale)) {
  820. tileImagery.textureTranslationAndScale = imageryLayer._calculateTextureTranslationAndScale(tile, tileImagery);
  821. }
  822. uniformMap.dayTextures[numberOfDayTextures] = imagery.texture;
  823. uniformMap.dayTextureTranslationAndScale[numberOfDayTextures] = tileImagery.textureTranslationAndScale;
  824. uniformMap.dayTextureTexCoordsRectangle[numberOfDayTextures] = tileImagery.textureCoordinateRectangle;
  825. uniformMap.dayTextureAlpha[numberOfDayTextures] = imageryLayer.alpha;
  826. applyAlpha = applyAlpha || uniformMap.dayTextureAlpha[numberOfDayTextures] !== 1.0;
  827. uniformMap.dayTextureBrightness[numberOfDayTextures] = imageryLayer.brightness;
  828. applyBrightness = applyBrightness || uniformMap.dayTextureBrightness[numberOfDayTextures] !== ImageryLayer.DEFAULT_BRIGHTNESS;
  829. uniformMap.dayTextureContrast[numberOfDayTextures] = imageryLayer.contrast;
  830. applyContrast = applyContrast || uniformMap.dayTextureContrast[numberOfDayTextures] !== ImageryLayer.DEFAULT_CONTRAST;
  831. uniformMap.dayTextureHue[numberOfDayTextures] = imageryLayer.hue;
  832. applyHue = applyHue || uniformMap.dayTextureHue[numberOfDayTextures] !== ImageryLayer.DEFAULT_HUE;
  833. uniformMap.dayTextureSaturation[numberOfDayTextures] = imageryLayer.saturation;
  834. applySaturation = applySaturation || uniformMap.dayTextureSaturation[numberOfDayTextures] !== ImageryLayer.DEFAULT_SATURATION;
  835. uniformMap.dayTextureOneOverGamma[numberOfDayTextures] = 1.0 / imageryLayer.gamma;
  836. applyGamma = applyGamma || uniformMap.dayTextureOneOverGamma[numberOfDayTextures] !== 1.0 / ImageryLayer.DEFAULT_GAMMA;
  837. if (defined(imagery.credits)) {
  838. var creditDisplay = frameState.creditDisplay;
  839. var credits = imagery.credits;
  840. for (var creditIndex = 0, creditLength = credits.length; creditIndex < creditLength; ++creditIndex) {
  841. creditDisplay.addCredit(credits[creditIndex]);
  842. }
  843. }
  844. ++numberOfDayTextures;
  845. }
  846. // trim texture array to the used length so we don't end up using old textures
  847. // which might get destroyed eventually
  848. uniformMap.dayTextures.length = numberOfDayTextures;
  849. uniformMap.waterMask = waterMaskTexture;
  850. Cartesian4.clone(surfaceTile.waterMaskTranslationAndScale, uniformMap.waterMaskTranslationAndScale);
  851. command.shaderProgram = tileProvider._surfaceShaderSet.getShaderProgram(context, frameState.mode, surfaceTile, numberOfDayTextures, applyBrightness, applyContrast, applyHue, applySaturation, applyGamma, applyAlpha, showReflectiveOcean, showOceanWaves, tileProvider.enableLighting, hasVertexNormals, useWebMercatorProjection);
  852. command.renderState = renderState;
  853. command.primitiveType = PrimitiveType.TRIANGLES;
  854. command.vertexArray = surfaceTile.vertexArray;
  855. command.uniformMap = uniformMap;
  856. command.pass = Pass.OPAQUE;
  857. if (tileProvider._debug.wireframe) {
  858. createWireframeVertexArrayIfNecessary(context, tileProvider, tile);
  859. if (defined(surfaceTile.wireframeVertexArray)) {
  860. command.vertexArray = surfaceTile.wireframeVertexArray;
  861. command.primitiveType = PrimitiveType.LINES;
  862. }
  863. }
  864. var boundingVolume = command.boundingVolume;
  865. if (frameState.mode !== SceneMode.SCENE3D) {
  866. BoundingSphere.fromRectangleWithHeights2D(tile.rectangle, frameState.mapProjection, surfaceTile.minimumHeight, surfaceTile.maximumHeight, boundingVolume);
  867. Cartesian3.fromElements(boundingVolume.center.z, boundingVolume.center.x, boundingVolume.center.y, boundingVolume.center);
  868. if (frameState.mode === SceneMode.MORPHING) {
  869. boundingVolume = BoundingSphere.union(surfaceTile.boundingSphere3D, boundingVolume, boundingVolume);
  870. }
  871. } else {
  872. BoundingSphere.clone(surfaceTile.boundingSphere3D, boundingVolume);
  873. }
  874. commandList.push(command);
  875. renderState = otherPassesRenderState;
  876. initialColor = otherPassesInitialColor;
  877. } while (imageryIndex < imageryLen);
  878. }
  879. return GlobeSurfaceTileProvider;
  880. });