1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939 |
- import BoundingSphere from '../Core/BoundingSphere.js';
- import BoxOutlineGeometry from '../Core/BoxOutlineGeometry.js';
- import Cartesian2 from '../Core/Cartesian2.js';
- import Cartesian3 from '../Core/Cartesian3.js';
- import Cartesian4 from '../Core/Cartesian4.js';
- import Cartographic from '../Core/Cartographic.js';
- import Color from '../Core/Color.js';
- import ColorGeometryInstanceAttribute from '../Core/ColorGeometryInstanceAttribute.js';
- import combine from '../Core/combine.js';
- import defaultValue from '../Core/defaultValue.js';
- import defined from '../Core/defined.js';
- import defineProperties from '../Core/defineProperties.js';
- import destroyObject from '../Core/destroyObject.js';
- import DeveloperError from '../Core/DeveloperError.js';
- import Event from '../Core/Event.js';
- import GeometryInstance from '../Core/GeometryInstance.js';
- import GeometryPipeline from '../Core/GeometryPipeline.js';
- import IndexDatatype from '../Core/IndexDatatype.js';
- import Intersect from '../Core/Intersect.js';
- import CesiumMath from '../Core/Math.js';
- import Matrix4 from '../Core/Matrix4.js';
- import OrientedBoundingBox from '../Core/OrientedBoundingBox.js';
- import OrthographicFrustum from '../Core/OrthographicFrustum.js';
- import PrimitiveType from '../Core/PrimitiveType.js';
- import Rectangle from '../Core/Rectangle.js';
- import SphereOutlineGeometry from '../Core/SphereOutlineGeometry.js';
- import TerrainQuantization from '../Core/TerrainQuantization.js';
- import Visibility from '../Core/Visibility.js';
- import WebMercatorProjection from '../Core/WebMercatorProjection.js';
- import Buffer from '../Renderer/Buffer.js';
- import BufferUsage from '../Renderer/BufferUsage.js';
- import ContextLimits from '../Renderer/ContextLimits.js';
- import DrawCommand from '../Renderer/DrawCommand.js';
- import Pass from '../Renderer/Pass.js';
- import RenderState from '../Renderer/RenderState.js';
- import VertexArray from '../Renderer/VertexArray.js';
- import BlendingState from './BlendingState.js';
- import ClippingPlaneCollection from './ClippingPlaneCollection.js';
- import DepthFunction from './DepthFunction.js';
- import GlobeSurfaceTile from './GlobeSurfaceTile.js';
- import ImageryLayer from './ImageryLayer.js';
- import ImageryState from './ImageryState.js';
- import PerInstanceColorAppearance from './PerInstanceColorAppearance.js';
- import Primitive from './Primitive.js';
- import QuadtreeTileLoadState from './QuadtreeTileLoadState.js';
- import SceneMode from './SceneMode.js';
- import ShadowMode from './ShadowMode.js';
- import TerrainFillMesh from './TerrainFillMesh.js';
- import TerrainState from './TerrainState.js';
- import TileBoundingRegion from './TileBoundingRegion.js';
- import TileSelectionResult from './TileSelectionResult.js';
- /**
- * Provides quadtree tiles representing the surface of the globe. This type is intended to be used
- * with {@link QuadtreePrimitive}.
- *
- * @alias GlobeSurfaceTileProvider
- * @constructor
- *
- * @param {TerrainProvider} options.terrainProvider The terrain provider that describes the surface geometry.
- * @param {ImageryLayerCollection} option.imageryLayers The collection of imagery layers describing the shading of the surface.
- * @param {GlobeSurfaceShaderSet} options.surfaceShaderSet The set of shaders used to render the surface.
- *
- * @private
- */
- function GlobeSurfaceTileProvider(options) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(options)) {
- throw new DeveloperError('options is required.');
- }
- if (!defined(options.terrainProvider)) {
- throw new DeveloperError('options.terrainProvider is required.');
- } else if (!defined(options.imageryLayers)) {
- throw new DeveloperError('options.imageryLayers is required.');
- } else if (!defined(options.surfaceShaderSet)) {
- throw new DeveloperError('options.surfaceShaderSet is required.');
- }
- //>>includeEnd('debug');
- this.lightingFadeOutDistance = 6500000.0;
- this.lightingFadeInDistance = 9000000.0;
- this.hasWaterMask = false;
- this.oceanNormalMap = undefined;
- this.zoomedOutOceanSpecularIntensity = 0.5;
- this.enableLighting = false;
- this.showGroundAtmosphere = false;
- this.shadows = ShadowMode.RECEIVE_ONLY;
- /**
- * The color to use to highlight terrain fill tiles. If undefined, fill tiles are not
- * highlighted at all. The alpha value is used to alpha blend with the tile's
- * actual color. Because terrain fill tiles do not represent the actual terrain surface,
- * it may be useful in some applications to indicate visually that they are not to be trusted.
- * @type {Color}
- * @default undefined
- */
- this.fillHighlightColor = undefined;
- this.hueShift = 0.0;
- this.saturationShift = 0.0;
- this.brightnessShift = 0.0;
- this._quadtree = undefined;
- this._terrainProvider = options.terrainProvider;
- this._imageryLayers = options.imageryLayers;
- this._surfaceShaderSet = options.surfaceShaderSet;
- this._renderState = undefined;
- this._blendRenderState = undefined;
- this._errorEvent = new Event();
- this._imageryLayers.layerAdded.addEventListener(GlobeSurfaceTileProvider.prototype._onLayerAdded, this);
- this._imageryLayers.layerRemoved.addEventListener(GlobeSurfaceTileProvider.prototype._onLayerRemoved, this);
- this._imageryLayers.layerMoved.addEventListener(GlobeSurfaceTileProvider.prototype._onLayerMoved, this);
- this._imageryLayers.layerShownOrHidden.addEventListener(GlobeSurfaceTileProvider.prototype._onLayerShownOrHidden, this);
- this._imageryLayersUpdatedEvent = new Event();
- this._layerOrderChanged = false;
- this._tilesToRenderByTextureCount = [];
- this._drawCommands = [];
- this._uniformMaps = [];
- this._usedDrawCommands = 0;
- this._vertexArraysToDestroy = [];
- this._debug = {
- wireframe : false,
- boundingSphereTile : undefined
- };
- this._baseColor = undefined;
- this._firstPassInitialColor = undefined;
- this.baseColor = new Color(0.0, 0.0, 0.5, 1.0);
- /**
- * A property specifying a {@link ClippingPlaneCollection} used to selectively disable rendering on the outside of each plane.
- * @type {ClippingPlaneCollection}
- * @private
- */
- this._clippingPlanes = undefined;
- /**
- * A property specifying a {@link Rectangle} used to selectively limit terrain and imagery rendering.
- * @type {Rectangle}
- */
- this.cartographicLimitRectangle = Rectangle.clone(Rectangle.MAX_VALUE);
- this._hasLoadedTilesThisFrame = false;
- this._hasFillTilesThisFrame = false;
- }
- defineProperties(GlobeSurfaceTileProvider.prototype, {
- /**
- * Gets or sets the color of the globe when no imagery is available.
- * @memberof GlobeSurfaceTileProvider.prototype
- * @type {Color}
- */
- baseColor : {
- get : function() {
- return this._baseColor;
- },
- set : function(value) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(value)) {
- throw new DeveloperError('value is required.');
- }
- //>>includeEnd('debug');
- this._baseColor = value;
- this._firstPassInitialColor = Cartesian4.fromColor(value, this._firstPassInitialColor);
- }
- },
- /**
- * Gets or sets the {@link QuadtreePrimitive} for which this provider is
- * providing tiles. This property may be undefined if the provider is not yet associated
- * with a {@link QuadtreePrimitive}.
- * @memberof GlobeSurfaceTileProvider.prototype
- * @type {QuadtreePrimitive}
- */
- quadtree : {
- get : function() {
- return this._quadtree;
- },
- set : function(value) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(value)) {
- throw new DeveloperError('value is required.');
- }
- //>>includeEnd('debug');
- this._quadtree = value;
- }
- },
- /**
- * Gets a value indicating whether or not the provider is ready for use.
- * @memberof GlobeSurfaceTileProvider.prototype
- * @type {Boolean}
- */
- ready : {
- get : function() {
- return this._terrainProvider.ready && (this._imageryLayers.length === 0 || this._imageryLayers.get(0).imageryProvider.ready);
- }
- },
- /**
- * Gets the tiling scheme used by the provider. This property should
- * not be accessed before {@link GlobeSurfaceTileProvider#ready} returns true.
- * @memberof GlobeSurfaceTileProvider.prototype
- * @type {TilingScheme}
- */
- tilingScheme : {
- get : function() {
- return this._terrainProvider.tilingScheme;
- }
- },
- /**
- * Gets an event that is raised when the geometry provider encounters an asynchronous error. By subscribing
- * to the event, you will be notified of the error and can potentially recover from it. Event listeners
- * are passed an instance of {@link TileProviderError}.
- * @memberof GlobeSurfaceTileProvider.prototype
- * @type {Event}
- */
- errorEvent : {
- get : function() {
- return this._errorEvent;
- }
- },
- /**
- * Gets an event that is raised when an imagery layer is added, shown, hidden, moved, or removed.
- * @memberof GlobeSurfaceTileProvider.prototype
- * @type {Event}
- */
- imageryLayersUpdatedEvent : {
- get : function() {
- return this._imageryLayersUpdatedEvent;
- }
- },
- /**
- * Gets or sets the terrain provider that describes the surface geometry.
- * @memberof GlobeSurfaceTileProvider.prototype
- * @type {TerrainProvider}
- */
- terrainProvider : {
- get : function() {
- return this._terrainProvider;
- },
- set : function(terrainProvider) {
- if (this._terrainProvider === terrainProvider) {
- return;
- }
- //>>includeStart('debug', pragmas.debug);
- if (!defined(terrainProvider)) {
- throw new DeveloperError('terrainProvider is required.');
- }
- //>>includeEnd('debug');
- this._terrainProvider = terrainProvider;
- if (defined(this._quadtree)) {
- this._quadtree.invalidateAllTiles();
- }
- }
- },
- /**
- * The {@link ClippingPlaneCollection} used to selectively disable rendering the tileset.
- *
- * @type {ClippingPlaneCollection}
- *
- * @private
- */
- clippingPlanes : {
- get : function() {
- return this._clippingPlanes;
- },
- set : function(value) {
- ClippingPlaneCollection.setOwner(value, this, '_clippingPlanes');
- }
- }
- });
- function sortTileImageryByLayerIndex(a, b) {
- var aImagery = a.loadingImagery;
- if (!defined(aImagery)) {
- aImagery = a.readyImagery;
- }
- var bImagery = b.loadingImagery;
- if (!defined(bImagery)) {
- bImagery = b.readyImagery;
- }
- return aImagery.imageryLayer._layerIndex - bImagery.imageryLayer._layerIndex;
- }
- /**
- * Make updates to the tile provider that are not involved in rendering. Called before the render update cycle.
- */
- GlobeSurfaceTileProvider.prototype.update = function(frameState) {
- // update collection: imagery indices, base layers, raise layer show/hide event
- this._imageryLayers._update();
- };
- function updateCredits(surface, frameState) {
- var creditDisplay = frameState.creditDisplay;
- if (surface._terrainProvider.ready && defined(surface._terrainProvider.credit)) {
- creditDisplay.addCredit(surface._terrainProvider.credit);
- }
- var imageryLayers = surface._imageryLayers;
- for (var i = 0, len = imageryLayers.length; i < len; ++i) {
- var imageryProvider = imageryLayers.get(i).imageryProvider;
- if (imageryProvider.ready && defined(imageryProvider.credit)) {
- creditDisplay.addCredit(imageryProvider.credit);
- }
- }
- }
- /**
- * Called at the beginning of each render frame, before {@link QuadtreeTileProvider#showTileThisFrame}
- * @param {FrameState} frameState The frame state.
- */
- GlobeSurfaceTileProvider.prototype.initialize = function(frameState) {
- // update each layer for texture reprojection.
- this._imageryLayers.queueReprojectionCommands(frameState);
- if (this._layerOrderChanged) {
- this._layerOrderChanged = false;
- // Sort the TileImagery instances in each tile by the layer index.
- this._quadtree.forEachLoadedTile(function(tile) {
- tile.data.imagery.sort(sortTileImageryByLayerIndex);
- });
- }
- // Add credits for terrain and imagery providers.
- updateCredits(this, frameState);
- var vertexArraysToDestroy = this._vertexArraysToDestroy;
- var length = vertexArraysToDestroy.length;
- for (var j = 0; j < length; ++j) {
- GlobeSurfaceTile._freeVertexArray(vertexArraysToDestroy[j]);
- }
- vertexArraysToDestroy.length = 0;
- };
- /**
- * Called at the beginning of the update cycle for each render frame, before {@link QuadtreeTileProvider#showTileThisFrame}
- * or any other functions.
- *
- * @param {FrameState} frameState The frame state.
- */
- GlobeSurfaceTileProvider.prototype.beginUpdate = function(frameState) {
- var tilesToRenderByTextureCount = this._tilesToRenderByTextureCount;
- for (var i = 0, len = tilesToRenderByTextureCount.length; i < len; ++i) {
- var tiles = tilesToRenderByTextureCount[i];
- if (defined(tiles)) {
- tiles.length = 0;
- }
- }
- // update clipping planes
- var clippingPlanes = this._clippingPlanes;
- if (defined(clippingPlanes) && clippingPlanes.enabled) {
- clippingPlanes.update(frameState);
- }
- this._usedDrawCommands = 0;
- this._hasLoadedTilesThisFrame = false;
- this._hasFillTilesThisFrame = false;
- };
- /**
- * Called at the end of the update cycle for each render frame, after {@link QuadtreeTileProvider#showTileThisFrame}
- * and any other functions.
- *
- * @param {FrameState} frameState The frame state.
- */
- GlobeSurfaceTileProvider.prototype.endUpdate = function(frameState) {
- if (!defined(this._renderState)) {
- this._renderState = RenderState.fromCache({ // Write color and depth
- cull : {
- enabled : true
- },
- depthTest : {
- enabled : true,
- func : DepthFunction.LESS
- }
- });
- this._blendRenderState = RenderState.fromCache({ // Write color and depth
- cull : {
- enabled : true
- },
- depthTest : {
- enabled : true,
- func : DepthFunction.LESS_OR_EQUAL
- },
- blending : BlendingState.ALPHA_BLEND
- });
- }
- // If this frame has a mix of loaded and fill tiles, we need to propagate
- // loaded heights to the fill tiles.
- if (this._hasFillTilesThisFrame && this._hasLoadedTilesThisFrame) {
- TerrainFillMesh.updateFillTiles(this, this._quadtree._tilesToRender, frameState, this._vertexArraysToDestroy);
- }
- // Add the tile render commands to the command list, sorted by texture count.
- var tilesToRenderByTextureCount = this._tilesToRenderByTextureCount;
- for (var textureCountIndex = 0, textureCountLength = tilesToRenderByTextureCount.length; textureCountIndex < textureCountLength; ++textureCountIndex) {
- var tilesToRender = tilesToRenderByTextureCount[textureCountIndex];
- if (!defined(tilesToRender)) {
- continue;
- }
- for (var tileIndex = 0, tileLength = tilesToRender.length; tileIndex < tileLength; ++tileIndex) {
- addDrawCommandsForTile(this, tilesToRender[tileIndex], frameState);
- }
- }
- };
- /**
- * Adds draw commands for tiles rendered in the previous frame for a pick pass.
- *
- * @param {FrameState} frameState The frame state.
- */
- GlobeSurfaceTileProvider.prototype.updateForPick = function(frameState) {
- // Add the tile pick commands from the tiles drawn last frame.
- var drawCommands = this._drawCommands;
- for (var i = 0, length = this._usedDrawCommands; i < length; ++i) {
- frameState.commandList.push(drawCommands[i]);
- }
- };
- /**
- * Cancels any imagery re-projections in the queue.
- */
- GlobeSurfaceTileProvider.prototype.cancelReprojections = function() {
- this._imageryLayers.cancelReprojections();
- };
- /**
- * Gets the maximum geometric error allowed in a tile at a given level, in meters. This function should not be
- * called before {@link GlobeSurfaceTileProvider#ready} returns true.
- *
- * @param {Number} level The tile level for which to get the maximum geometric error.
- * @returns {Number} The maximum geometric error in meters.
- */
- GlobeSurfaceTileProvider.prototype.getLevelMaximumGeometricError = function(level) {
- return this._terrainProvider.getLevelMaximumGeometricError(level);
- };
- /**
- * Loads, or continues loading, a given tile. This function will continue to be called
- * until {@link QuadtreeTile#state} is no longer {@link QuadtreeTileLoadState#LOADING}. This function should
- * not be called before {@link GlobeSurfaceTileProvider#ready} returns true.
- *
- * @param {FrameState} frameState The frame state.
- * @param {QuadtreeTile} tile The tile to load.
- *
- * @exception {DeveloperError} <code>loadTile</code> must not be called before the tile provider is ready.
- */
- GlobeSurfaceTileProvider.prototype.loadTile = function(frameState, tile) {
- // We don't want to load imagery until we're certain that the terrain tiles are actually visible.
- // So if our bounding volume isn't accurate because it came from another tile, load terrain only
- // initially. If we load some terrain and suddenly have a more accurate bounding volume and the
- // tile is _still_ visible, give the tile a chance to load imagery immediately rather than
- // waiting for next frame.
- var surfaceTile = tile.data;
- var terrainOnly = true;
- var terrainStateBefore;
- if (defined(surfaceTile)) {
- terrainOnly = surfaceTile.boundingVolumeSourceTile !== tile || tile._lastSelectionResult === TileSelectionResult.CULLED_BUT_NEEDED;
- terrainStateBefore = surfaceTile.terrainState;
- }
- GlobeSurfaceTile.processStateMachine(tile, frameState, this.terrainProvider, this._imageryLayers, this._vertexArraysToDestroy, terrainOnly);
- surfaceTile = tile.data;
- if (terrainOnly && terrainStateBefore !== tile.data.terrainState) {
- // Terrain state changed. If:
- // a) The tile is visible, and
- // b) The bounding volume is accurate (updated as a side effect of computing visibility)
- // Then we'll load imagery, too.
- if (this.computeTileVisibility(tile, frameState, this.quadtree.occluders) && surfaceTile.boundingVolumeSourceTile === tile) {
- terrainOnly = false;
- GlobeSurfaceTile.processStateMachine(tile, frameState, this.terrainProvider, this._imageryLayers, this._vertexArraysToDestroy, terrainOnly);
- }
- }
- };
- var boundingSphereScratch = new BoundingSphere();
- var rectangleIntersectionScratch = new Rectangle();
- var splitCartographicLimitRectangleScratch = new Rectangle();
- var rectangleCenterScratch = new Cartographic();
- // cartographicLimitRectangle may span the IDL, but tiles never will.
- function clipRectangleAntimeridian(tileRectangle, cartographicLimitRectangle) {
- if (cartographicLimitRectangle.west < cartographicLimitRectangle.east) {
- return cartographicLimitRectangle;
- }
- var splitRectangle = Rectangle.clone(cartographicLimitRectangle, splitCartographicLimitRectangleScratch);
- var tileCenter = Rectangle.center(tileRectangle, rectangleCenterScratch);
- if (tileCenter.longitude > 0.0) {
- splitRectangle.east = CesiumMath.PI;
- } else {
- splitRectangle.west = -CesiumMath.PI;
- }
- return splitRectangle;
- }
- /**
- * Determines the visibility of a given tile. The tile may be fully visible, partially visible, or not
- * visible at all. Tiles that are renderable and are at least partially visible will be shown by a call
- * to {@link GlobeSurfaceTileProvider#showTileThisFrame}.
- *
- * @param {QuadtreeTile} tile The tile instance.
- * @param {FrameState} frameState The state information about the current frame.
- * @param {QuadtreeOccluders} occluders The objects that may occlude this tile.
- *
- * @returns {Visibility} The visibility of the tile.
- */
- GlobeSurfaceTileProvider.prototype.computeTileVisibility = function(tile, frameState, occluders) {
- var distance = this.computeDistanceToTile(tile, frameState);
- tile._distance = distance;
- if (frameState.fog.enabled) {
- if (CesiumMath.fog(distance, frameState.fog.density) >= 1.0) {
- // Tile is completely in fog so return that it is not visible.
- return Visibility.NONE;
- }
- }
- var surfaceTile = tile.data;
- var tileBoundingRegion = surfaceTile.tileBoundingRegion;
- if (surfaceTile.boundingVolumeSourceTile === undefined) {
- // We have no idea where this tile is, so let's just call it partially visible.
- return Visibility.PARTIAL;
- }
- var cullingVolume = frameState.cullingVolume;
- var boundingVolume = surfaceTile.orientedBoundingBox;
- if (!defined(boundingVolume) && defined(surfaceTile.renderedMesh)) {
- boundingVolume = surfaceTile.renderedMesh.boundingSphere3D;
- }
- // Check if the tile is outside the limit area in cartographic space
- surfaceTile.clippedByBoundaries = false;
- var clippedCartographicLimitRectangle = clipRectangleAntimeridian(tile.rectangle, this.cartographicLimitRectangle);
- var areaLimitIntersection = Rectangle.simpleIntersection(clippedCartographicLimitRectangle, tile.rectangle, rectangleIntersectionScratch);
- if (!defined(areaLimitIntersection)) {
- return Visibility.NONE;
- }
- if (!Rectangle.equals(areaLimitIntersection, tile.rectangle)) {
- surfaceTile.clippedByBoundaries = true;
- }
- if (frameState.mode !== SceneMode.SCENE3D) {
- boundingVolume = boundingSphereScratch;
- BoundingSphere.fromRectangleWithHeights2D(tile.rectangle, frameState.mapProjection, tileBoundingRegion.minimumHeight, tileBoundingRegion.maximumHeight, boundingVolume);
- Cartesian3.fromElements(boundingVolume.center.z, boundingVolume.center.x, boundingVolume.center.y, boundingVolume.center);
- if (frameState.mode === SceneMode.MORPHING && defined(surfaceTile.renderedMesh)) {
- boundingVolume = BoundingSphere.union(surfaceTile.renderedMesh.boundingSphere3D, boundingVolume, boundingVolume);
- }
- }
- if (!defined(boundingVolume)) {
- return Intersect.INTERSECTING;
- }
- var clippingPlanes = this._clippingPlanes;
- if (defined(clippingPlanes) && clippingPlanes.enabled) {
- var planeIntersection = clippingPlanes.computeIntersectionWithBoundingVolume(boundingVolume);
- tile.isClipped = (planeIntersection !== Intersect.INSIDE);
- if (planeIntersection === Intersect.OUTSIDE) {
- return Visibility.NONE;
- }
- }
- var intersection = cullingVolume.computeVisibility(boundingVolume);
- if (intersection === Intersect.OUTSIDE) {
- return Visibility.NONE;
- }
- var ortho3D = frameState.mode === SceneMode.SCENE3D && frameState.camera.frustum instanceof OrthographicFrustum;
- if (frameState.mode === SceneMode.SCENE3D && !ortho3D && defined(occluders)) {
- var occludeePointInScaledSpace = surfaceTile.occludeePointInScaledSpace;
- if (!defined(occludeePointInScaledSpace)) {
- return intersection;
- }
- if (occluders.ellipsoid.isScaledSpacePointVisible(occludeePointInScaledSpace)) {
- return intersection;
- }
- return Visibility.NONE;
- }
- return intersection;
- };
- /**
- * Determines if the given tile can be refined
- * @param {QuadtreeTile} tile The tile to check.
- * @returns {boolean} True if the tile can be refined, false if it cannot.
- */
- GlobeSurfaceTileProvider.prototype.canRefine = function(tile) {
- // Only allow refinement it we know whether or not the children of this tile exist.
- // For a tileset with `availability`, we'll always be able to refine.
- // We can ask for availability of _any_ child tile because we only need to confirm
- // that we get a yes or no answer, it doesn't matter what the answer is.
- if (defined(tile.data.terrainData)) {
- return true;
- }
- var childAvailable = this.terrainProvider.getTileDataAvailable(tile.x * 2, tile.y * 2, tile.level + 1);
- return childAvailable !== undefined;
- };
- var readyImageryScratch = [];
- var canRenderTraversalStack = [];
- /**
- * Determines if the given not-fully-loaded tile can be rendered without losing detail that
- * was present last frame as a result of rendering descendant tiles. This method will only be
- * called if this tile's descendants were rendered last frame. If the tile is fully loaded,
- * it is assumed that this method will return true and it will not be called.
- * @param {QuadtreeTile} tile The tile to check.
- * @returns {boolean} True if the tile can be rendered without losing detail.
- */
- GlobeSurfaceTileProvider.prototype.canRenderWithoutLosingDetail = function(tile, frameState) {
- var surfaceTile = tile.data;
- var readyImagery = readyImageryScratch;
- readyImagery.length = this._imageryLayers.length;
- var terrainReady = false;
- var initialImageryState = false;
- var imagery;
- if (defined(surfaceTile)) {
- // We can render even with non-ready terrain as long as all our rendered descendants
- // are missing terrain geometry too. i.e. if we rendered fills for more detailed tiles
- // last frame, it's ok to render a fill for this tile this frame.
- terrainReady = surfaceTile.terrainState === TerrainState.READY;
- // Initially assume all imagery layers are ready, unless imagery hasn't been initialized at all.
- initialImageryState = true;
- imagery = surfaceTile.imagery;
- }
- var i;
- var len;
- for (i = 0, len = readyImagery.length; i < len; ++i) {
- readyImagery[i] = initialImageryState;
- }
- if (defined(imagery)) {
- for (i = 0, len = imagery.length; i < len; ++i) {
- var tileImagery = imagery[i];
- var loadingImagery = tileImagery.loadingImagery;
- var isReady = !defined(loadingImagery) || loadingImagery.state === ImageryState.FAILED || loadingImagery.state === ImageryState.INVALID;
- var layerIndex = (tileImagery.loadingImagery || tileImagery.readyImagery).imageryLayer._layerIndex;
- // For a layer to be ready, all tiles belonging to that layer must be ready.
- readyImagery[layerIndex] = isReady && readyImagery[layerIndex];
- }
- }
- var lastFrame = this.quadtree._lastSelectionFrameNumber;
- // Traverse the descendants looking for one with terrain or imagery that is not loaded on this tile.
- var stack = canRenderTraversalStack;
- stack.length = 0;
- stack.push(tile.southwestChild, tile.southeastChild, tile.northwestChild, tile.northeastChild);
- while (stack.length > 0) {
- var descendant = stack.pop();
- var lastFrameSelectionResult = descendant._lastSelectionResultFrame === lastFrame ? descendant._lastSelectionResult : TileSelectionResult.NONE;
- if (lastFrameSelectionResult === TileSelectionResult.RENDERED) {
- var descendantSurface = descendant.data;
- if (!defined(descendantSurface)) {
- // Descendant has no data, so it can't block rendering.
- continue;
- }
- if (!terrainReady && descendant.data.terrainState === TerrainState.READY) {
- // Rendered descendant has real terrain, but we don't. Rendering is blocked.
- return false;
- }
- var descendantImagery = descendant.data.imagery;
- for (i = 0, len = descendantImagery.length; i < len; ++i) {
- var descendantTileImagery = descendantImagery[i];
- var descendantLoadingImagery = descendantTileImagery.loadingImagery;
- var descendantIsReady = !defined(descendantLoadingImagery) || descendantLoadingImagery.state === ImageryState.FAILED || descendantLoadingImagery.state === ImageryState.INVALID;
- var descendantLayerIndex = (descendantTileImagery.loadingImagery || descendantTileImagery.readyImagery).imageryLayer._layerIndex;
- // If this imagery tile of a descendant is ready but the layer isn't ready in this tile,
- // then rendering is blocked.
- if (descendantIsReady && !readyImagery[descendantLayerIndex]) {
- return false;
- }
- }
- } else if (lastFrameSelectionResult === TileSelectionResult.REFINED) {
- stack.push(descendant.southwestChild, descendant.southeastChild, descendant.northwestChild, descendant.northeastChild);
- }
- }
- return true;
- };
- var tileDirectionScratch = new Cartesian3();
- /**
- * Determines the priority for loading this tile. Lower priority values load sooner.
- * @param {QuadtreeTile} tile The tile.
- * @param {FrameState} frameState The frame state.
- * @returns {Number} The load priority value.
- */
- GlobeSurfaceTileProvider.prototype.computeTileLoadPriority = function(tile, frameState) {
- var surfaceTile = tile.data;
- if (surfaceTile === undefined) {
- return 0.0;
- }
- var obb = surfaceTile.orientedBoundingBox;
- if (obb === undefined) {
- return 0.0;
- }
- var cameraPosition = frameState.camera.positionWC;
- var cameraDirection = frameState.camera.directionWC;
- var tileDirection = Cartesian3.subtract(obb.center, cameraPosition, tileDirectionScratch);
- var magnitude = Cartesian3.magnitude(tileDirection);
- if (magnitude < CesiumMath.EPSILON5) {
- return 0.0;
- }
- Cartesian3.divideByScalar(tileDirection, magnitude, tileDirection);
- return (1.0 - Cartesian3.dot(tileDirection, cameraDirection)) * tile._distance;
- };
- var modifiedModelViewScratch = new Matrix4();
- var modifiedModelViewProjectionScratch = new Matrix4();
- var tileRectangleScratch = new Cartesian4();
- var localizedCartographicLimitRectangleScratch = new Cartesian4();
- var rtcScratch = new Cartesian3();
- var centerEyeScratch = new Cartesian3();
- var southwestScratch = new Cartesian3();
- var northeastScratch = new Cartesian3();
- /**
- * Shows a specified tile in this frame. The provider can cause the tile to be shown by adding
- * render commands to the commandList, or use any other method as appropriate. The tile is not
- * expected to be visible next frame as well, unless this method is called next frame, too.
- *
- * @param {QuadtreeTile} tile The tile instance.
- * @param {FrameState} frameState The state information of the current rendering frame.
- */
- GlobeSurfaceTileProvider.prototype.showTileThisFrame = function(tile, frameState) {
- var readyTextureCount = 0;
- var tileImageryCollection = tile.data.imagery;
- for (var i = 0, len = tileImageryCollection.length; i < len; ++i) {
- var tileImagery = tileImageryCollection[i];
- if (defined(tileImagery.readyImagery) && tileImagery.readyImagery.imageryLayer.alpha !== 0.0) {
- ++readyTextureCount;
- }
- }
- var tileSet = this._tilesToRenderByTextureCount[readyTextureCount];
- if (!defined(tileSet)) {
- tileSet = [];
- this._tilesToRenderByTextureCount[readyTextureCount] = tileSet;
- }
- tileSet.push(tile);
- var surfaceTile = tile.data;
- if (!defined(surfaceTile.vertexArray)) {
- this._hasFillTilesThisFrame = true;
- } else {
- this._hasLoadedTilesThisFrame = true;
- }
- var debug = this._debug;
- ++debug.tilesRendered;
- debug.texturesRendered += readyTextureCount;
- };
- var cornerPositionsScratch = [new Cartesian3(), new Cartesian3(), new Cartesian3(), new Cartesian3()];
- function computeOccludeePoint(tileProvider, center, rectangle, height, result) {
- var ellipsoidalOccluder = tileProvider.quadtree._occluders.ellipsoid;
- var ellipsoid = ellipsoidalOccluder.ellipsoid;
- var cornerPositions = cornerPositionsScratch;
- Cartesian3.fromRadians(rectangle.west, rectangle.south, height, ellipsoid, cornerPositions[0]);
- Cartesian3.fromRadians(rectangle.east, rectangle.south, height, ellipsoid, cornerPositions[1]);
- Cartesian3.fromRadians(rectangle.west, rectangle.north, height, ellipsoid, cornerPositions[2]);
- Cartesian3.fromRadians(rectangle.east, rectangle.north, height, ellipsoid, cornerPositions[3]);
- return ellipsoidalOccluder.computeHorizonCullingPoint(center, cornerPositions, result);
- }
- /**
- * Gets the distance from the camera to the closest point on the tile. This is used for level-of-detail selection.
- *
- * @param {QuadtreeTile} tile The tile instance.
- * @param {FrameState} frameState The state information of the current rendering frame.
- *
- * @returns {Number} The distance from the camera to the closest point on the tile, in meters.
- */
- GlobeSurfaceTileProvider.prototype.computeDistanceToTile = function(tile, frameState) {
- // The distance should be:
- // 1. the actual distance to the tight-fitting bounding volume, or
- // 2. a distance that is equal to or greater than the actual distance to the tight-fitting bounding volume.
- //
- // When we don't know the min/max heights for a tile, but we do know the min/max of an ancestor tile, we can
- // build a tight-fitting bounding volume horizontally, but not vertically. The min/max heights from the
- // ancestor will likely form a volume that is much bigger than it needs to be. This means that the volume may
- // be deemed to be much closer to the camera than it really is, causing us to select tiles that are too detailed.
- // Loading too-detailed tiles is super expensive, so we don't want to do that. We don't know where the child
- // tile really lies within the parent range of heights, but we _do_ know the child tile can't be any closer than
- // the ancestor height surface (min or max) that is _farthest away_ from the camera. So if we compute distance
- // based that conservative metric, we may end up loading tiles that are not detailed enough, but that's much
- // better (faster) than loading tiles that are too detailed.
- var heightSource = updateTileBoundingRegion(tile, this.terrainProvider, frameState);
- var surfaceTile = tile.data;
- var tileBoundingRegion = surfaceTile.tileBoundingRegion;
- if (heightSource === undefined) {
- // Can't find any min/max heights anywhere? Ok, let's just say the
- // tile is really far away so we'll load and render it rather than
- // refining.
- return 9999999999.0;
- } else if (surfaceTile.boundingVolumeSourceTile !== heightSource) {
- // Heights are from a new source tile, so update the bounding volume.
- surfaceTile.boundingVolumeSourceTile = heightSource;
- var rectangle = tile.rectangle;
- if (defined(rectangle) && rectangle.width < CesiumMath.PI_OVER_TWO + CesiumMath.EPSILON5) {
- surfaceTile.orientedBoundingBox = OrientedBoundingBox.fromRectangle(
- tile.rectangle,
- tileBoundingRegion.minimumHeight,
- tileBoundingRegion.maximumHeight,
- tile.tilingScheme.ellipsoid,
- surfaceTile.orientedBoundingBox);
- surfaceTile.occludeePointInScaledSpace = computeOccludeePoint(this, surfaceTile.orientedBoundingBox.center, tile.rectangle, tileBoundingRegion.maximumHeight, surfaceTile.occludeePointInScaledSpace);
- }
- }
- var min = tileBoundingRegion.minimumHeight;
- var max = tileBoundingRegion.maximumHeight;
- if (surfaceTile.boundingVolumeSourceTile !== tile) {
- var cameraHeight = frameState.camera.positionCartographic.height;
- var distanceToMin = Math.abs(cameraHeight - min);
- var distanceToMax = Math.abs(cameraHeight - max);
- if (distanceToMin > distanceToMax) {
- tileBoundingRegion.minimumHeight = min;
- tileBoundingRegion.maximumHeight = min;
- } else {
- tileBoundingRegion.minimumHeight = max;
- tileBoundingRegion.maximumHeight = max;
- }
- }
- var result = tileBoundingRegion.distanceToCamera(frameState);
- tileBoundingRegion.minimumHeight = min;
- tileBoundingRegion.maximumHeight = max;
- return result;
- };
- function updateTileBoundingRegion(tile, terrainProvider, frameState) {
- var surfaceTile = tile.data;
- if (surfaceTile === undefined) {
- surfaceTile = tile.data = new GlobeSurfaceTile();
- }
- if (surfaceTile.tileBoundingRegion === undefined) {
- surfaceTile.tileBoundingRegion = new TileBoundingRegion({
- computeBoundingVolumes : false,
- rectangle : tile.rectangle,
- ellipsoid : tile.tilingScheme.ellipsoid,
- minimumHeight : 0.0,
- maximumHeight : 0.0
- });
- }
- var terrainData = surfaceTile.terrainData;
- var mesh = surfaceTile.mesh;
- var tileBoundingRegion = surfaceTile.tileBoundingRegion;
- if (mesh !== undefined && mesh.minimumHeight !== undefined && mesh.maximumHeight !== undefined) {
- // We have tight-fitting min/max heights from the mesh.
- tileBoundingRegion.minimumHeight = mesh.minimumHeight;
- tileBoundingRegion.maximumHeight = mesh.maximumHeight;
- return tile;
- }
- if (terrainData !== undefined && terrainData._minimumHeight !== undefined && terrainData._maximumHeight !== undefined) {
- // We have tight-fitting min/max heights from the terrain data.
- tileBoundingRegion.minimumHeight = terrainData._minimumHeight * frameState.terrainExaggeration;
- tileBoundingRegion.maximumHeight = terrainData._maximumHeight * frameState.terrainExaggeration;
- return tile;
- }
- // No accurate min/max heights available, so we're stuck with min/max heights from an ancestor tile.
- tileBoundingRegion.minimumHeight = Number.NaN;
- tileBoundingRegion.maximumHeight = Number.NaN;
- var ancestor = tile.parent;
- while (ancestor !== undefined) {
- var ancestorSurfaceTile = ancestor.data;
- if (ancestorSurfaceTile !== undefined) {
- var ancestorMesh = ancestorSurfaceTile.mesh;
- if (ancestorMesh !== undefined && ancestorMesh.minimumHeight !== undefined && ancestorMesh.maximumHeight !== undefined) {
- tileBoundingRegion.minimumHeight = ancestorMesh.minimumHeight;
- tileBoundingRegion.maximumHeight = ancestorMesh.maximumHeight;
- return ancestor;
- }
- var ancestorTerrainData = ancestorSurfaceTile.terrainData;
- if (ancestorTerrainData !== undefined && ancestorTerrainData._minimumHeight !== undefined && ancestorTerrainData._maximumHeight !== undefined) {
- tileBoundingRegion.minimumHeight = ancestorTerrainData._minimumHeight * frameState.terrainExaggeration;
- tileBoundingRegion.maximumHeight = ancestorTerrainData._maximumHeight * frameState.terrainExaggeration;
- return ancestor;
- }
- }
- ancestor = ancestor.parent;
- }
- return undefined;
- }
- /**
- * Returns true if this object was destroyed; otherwise, false.
- * <br /><br />
- * If this object was destroyed, it should not be used; calling any function other than
- * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
- *
- * @returns {Boolean} True if this object was destroyed; otherwise, false.
- *
- * @see GlobeSurfaceTileProvider#destroy
- */
- GlobeSurfaceTileProvider.prototype.isDestroyed = function() {
- return false;
- };
- /**
- * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
- * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
- * <br /><br />
- * Once an object is destroyed, it should not be used; calling any function other than
- * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
- * assign the return value (<code>undefined</code>) to the object as done in the example.
- *
- * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
- *
- *
- * @example
- * provider = provider && provider();
- *
- * @see GlobeSurfaceTileProvider#isDestroyed
- */
- GlobeSurfaceTileProvider.prototype.destroy = function() {
- this._tileProvider = this._tileProvider && this._tileProvider.destroy();
- this._clippingPlanes = this._clippingPlanes && this._clippingPlanes.destroy();
- return destroyObject(this);
- };
- function getTileReadyCallback(tileImageriesToFree, layer, terrainProvider) {
- return function(tile) {
- var tileImagery;
- var imagery;
- var startIndex = -1;
- var tileImageryCollection = tile.data.imagery;
- var length = tileImageryCollection.length;
- var i;
- for (i = 0; i < length; ++i) {
- tileImagery = tileImageryCollection[i];
- imagery = defaultValue(tileImagery.readyImagery, tileImagery.loadingImagery);
- if (imagery.imageryLayer === layer) {
- startIndex = i;
- break;
- }
- }
- if (startIndex !== -1) {
- var endIndex = startIndex + tileImageriesToFree;
- tileImagery = tileImageryCollection[endIndex];
- imagery = defined(tileImagery) ? defaultValue(tileImagery.readyImagery, tileImagery.loadingImagery) : undefined;
- if (!defined(imagery) || imagery.imageryLayer !== layer) {
- // Return false to keep the callback if we have to wait on the skeletons
- // Return true to remove the callback if something went wrong
- return !(layer._createTileImagerySkeletons(tile, terrainProvider, endIndex));
- }
- for (i = startIndex; i < endIndex; ++i) {
- tileImageryCollection[i].freeResources();
- }
- tileImageryCollection.splice(startIndex, tileImageriesToFree);
- }
- return true; // Everything is done, so remove the callback
- };
- }
- GlobeSurfaceTileProvider.prototype._onLayerAdded = function(layer, index) {
- if (layer.show) {
- var terrainProvider = this._terrainProvider;
- var that = this;
- var imageryProvider = layer.imageryProvider;
- var tileImageryUpdatedEvent = this._imageryLayersUpdatedEvent;
- imageryProvider._reload = function() {
- // Clear the layer's cache
- layer._imageryCache = {};
- that._quadtree.forEachLoadedTile(function(tile) {
- // If this layer is still waiting to for the loaded callback, just return
- if (defined(tile._loadedCallbacks[layer._layerIndex])) {
- return;
- }
- var i;
- // Figure out how many TileImageries we will need to remove and where to insert new ones
- var tileImageryCollection = tile.data.imagery;
- var length = tileImageryCollection.length;
- var startIndex = -1;
- var tileImageriesToFree = 0;
- for (i = 0; i < length; ++i) {
- var tileImagery = tileImageryCollection[i];
- var imagery = defaultValue(tileImagery.readyImagery, tileImagery.loadingImagery);
- if (imagery.imageryLayer === layer) {
- if (startIndex === -1) {
- startIndex = i;
- }
- ++tileImageriesToFree;
- } else if (startIndex !== -1) {
- // iterated past the section of TileImageries belonging to this layer, no need to continue.
- break;
- }
- }
- if (startIndex === -1) {
- return;
- }
- // Insert immediately after existing TileImageries
- var insertionPoint = startIndex + tileImageriesToFree;
- // Create new TileImageries for all loaded tiles
- if (layer._createTileImagerySkeletons(tile, terrainProvider, insertionPoint)) {
- // Add callback to remove old TileImageries when the new TileImageries are ready
- tile._loadedCallbacks[layer._layerIndex] = getTileReadyCallback(tileImageriesToFree, layer, terrainProvider);
- tile.state = QuadtreeTileLoadState.LOADING;
- }
- });
- };
- // create TileImageries for this layer for all previously loaded tiles
- this._quadtree.forEachLoadedTile(function(tile) {
- if (layer._createTileImagerySkeletons(tile, terrainProvider)) {
- tile.state = QuadtreeTileLoadState.LOADING;
- // Tiles that are not currently being rendered need to load the new layer before they're renderable.
- // We don't mark the rendered tiles non-renderable, though, because that would make the globe disappear.
- if (tile.level !== 0 && (tile._lastSelectionResultFrame !== that.quadtree._lastSelectionFrameNumber || tile._lastSelectionResult !== TileSelectionResult.RENDERED)) {
- tile.renderable = false;
- }
- }
- });
- this._layerOrderChanged = true;
- tileImageryUpdatedEvent.raiseEvent();
- }
- };
- GlobeSurfaceTileProvider.prototype._onLayerRemoved = function(layer, index) {
- // destroy TileImagerys for this layer for all previously loaded tiles
- this._quadtree.forEachLoadedTile(function(tile) {
- var tileImageryCollection = tile.data.imagery;
- var startIndex = -1;
- var numDestroyed = 0;
- for (var i = 0, len = tileImageryCollection.length; i < len; ++i) {
- var tileImagery = tileImageryCollection[i];
- var imagery = tileImagery.loadingImagery;
- if (!defined(imagery)) {
- imagery = tileImagery.readyImagery;
- }
- if (imagery.imageryLayer === layer) {
- if (startIndex === -1) {
- startIndex = i;
- }
- tileImagery.freeResources();
- ++numDestroyed;
- } else if (startIndex !== -1) {
- // iterated past the section of TileImagerys belonging to this layer, no need to continue.
- break;
- }
- }
- if (startIndex !== -1) {
- tileImageryCollection.splice(startIndex, numDestroyed);
- }
- });
- if (defined(layer.imageryProvider)) {
- layer.imageryProvider._reload = undefined;
- }
- this._imageryLayersUpdatedEvent.raiseEvent();
- };
- GlobeSurfaceTileProvider.prototype._onLayerMoved = function(layer, newIndex, oldIndex) {
- this._layerOrderChanged = true;
- this._imageryLayersUpdatedEvent.raiseEvent();
- };
- GlobeSurfaceTileProvider.prototype._onLayerShownOrHidden = function(layer, index, show) {
- if (show) {
- this._onLayerAdded(layer, index);
- } else {
- this._onLayerRemoved(layer, index);
- }
- };
- var scratchClippingPlaneMatrix = new Matrix4();
- function createTileUniformMap(frameState, globeSurfaceTileProvider) {
- var uniformMap = {
- u_initialColor : function() {
- return this.properties.initialColor;
- },
- u_fillHighlightColor : function() {
- return this.properties.fillHighlightColor;
- },
- u_zoomedOutOceanSpecularIntensity : function() {
- return this.properties.zoomedOutOceanSpecularIntensity;
- },
- u_oceanNormalMap : function() {
- return this.properties.oceanNormalMap;
- },
- u_lightingFadeDistance : function() {
- return this.properties.lightingFadeDistance;
- },
- u_nightFadeDistance : function() {
- return this.properties.nightFadeDistance;
- },
- u_center3D : function() {
- return this.properties.center3D;
- },
- u_tileRectangle : function() {
- return this.properties.tileRectangle;
- },
- u_modifiedModelView : function() {
- var viewMatrix = frameState.context.uniformState.view;
- var centerEye = Matrix4.multiplyByPoint(viewMatrix, this.properties.rtc, centerEyeScratch);
- Matrix4.setTranslation(viewMatrix, centerEye, modifiedModelViewScratch);
- return modifiedModelViewScratch;
- },
- u_modifiedModelViewProjection : function() {
- var viewMatrix = frameState.context.uniformState.view;
- var projectionMatrix = frameState.context.uniformState.projection;
- var centerEye = Matrix4.multiplyByPoint(viewMatrix, this.properties.rtc, centerEyeScratch);
- Matrix4.setTranslation(viewMatrix, centerEye, modifiedModelViewProjectionScratch);
- Matrix4.multiply(projectionMatrix, modifiedModelViewProjectionScratch, modifiedModelViewProjectionScratch);
- return modifiedModelViewProjectionScratch;
- },
- u_dayTextures : function() {
- return this.properties.dayTextures;
- },
- u_dayTextureTranslationAndScale : function() {
- return this.properties.dayTextureTranslationAndScale;
- },
- u_dayTextureTexCoordsRectangle : function() {
- return this.properties.dayTextureTexCoordsRectangle;
- },
- u_dayTextureUseWebMercatorT : function() {
- return this.properties.dayTextureUseWebMercatorT;
- },
- u_dayTextureAlpha : function() {
- return this.properties.dayTextureAlpha;
- },
- u_dayTextureBrightness : function() {
- return this.properties.dayTextureBrightness;
- },
- u_dayTextureContrast : function() {
- return this.properties.dayTextureContrast;
- },
- u_dayTextureHue : function() {
- return this.properties.dayTextureHue;
- },
- u_dayTextureSaturation : function() {
- return this.properties.dayTextureSaturation;
- },
- u_dayTextureOneOverGamma : function() {
- return this.properties.dayTextureOneOverGamma;
- },
- u_dayIntensity : function() {
- return this.properties.dayIntensity;
- },
- u_southAndNorthLatitude : function() {
- return this.properties.southAndNorthLatitude;
- },
- u_southMercatorYAndOneOverHeight : function() {
- return this.properties.southMercatorYAndOneOverHeight;
- },
- u_waterMask : function() {
- return this.properties.waterMask;
- },
- u_waterMaskTranslationAndScale : function() {
- return this.properties.waterMaskTranslationAndScale;
- },
- u_minMaxHeight : function() {
- return this.properties.minMaxHeight;
- },
- u_scaleAndBias : function() {
- return this.properties.scaleAndBias;
- },
- u_dayTextureSplit : function() {
- return this.properties.dayTextureSplit;
- },
- u_dayTextureCutoutRectangles : function() {
- return this.properties.dayTextureCutoutRectangles;
- },
- u_clippingPlanes : function() {
- var clippingPlanes = globeSurfaceTileProvider._clippingPlanes;
- if (defined(clippingPlanes) && defined(clippingPlanes.texture)) {
- // Check in case clippingPlanes hasn't been updated yet.
- return clippingPlanes.texture;
- }
- return frameState.context.defaultTexture;
- },
- u_cartographicLimitRectangle : function() {
- return this.properties.localizedCartographicLimitRectangle;
- },
- u_clippingPlanesMatrix : function() {
- var clippingPlanes = globeSurfaceTileProvider._clippingPlanes;
- return defined(clippingPlanes) ? Matrix4.multiply(frameState.context.uniformState.view, clippingPlanes.modelMatrix, scratchClippingPlaneMatrix) : Matrix4.IDENTITY;
- },
- u_clippingPlanesEdgeStyle : function() {
- var style = this.properties.clippingPlanesEdgeColor;
- style.alpha = this.properties.clippingPlanesEdgeWidth;
- return style;
- },
- u_minimumBrightness : function() {
- return frameState.fog.minimumBrightness;
- },
- u_hsbShift : function() {
- return this.properties.hsbShift;
- },
- u_colorsToAlpha : function() {
- return this.properties.colorsToAlpha;
- },
- // make a separate object so that changes to the properties are seen on
- // derived commands that combine another uniform map with this one.
- properties : {
- initialColor : new Cartesian4(0.0, 0.0, 0.5, 1.0),
- fillHighlightColor : new Color(0.0, 0.0, 0.0, 0.0),
- zoomedOutOceanSpecularIntensity : 0.5,
- oceanNormalMap : undefined,
- lightingFadeDistance : new Cartesian2(6500000.0, 9000000.0),
- nightFadeDistance : new Cartesian2(10000000.0, 40000000.0),
- hsbShift : new Cartesian3(),
- center3D : undefined,
- rtc : new Cartesian3(),
- modifiedModelView : new Matrix4(),
- tileRectangle : new Cartesian4(),
- dayTextures : [],
- dayTextureTranslationAndScale : [],
- dayTextureTexCoordsRectangle : [],
- dayTextureUseWebMercatorT : [],
- dayTextureAlpha : [],
- dayTextureBrightness : [],
- dayTextureContrast : [],
- dayTextureHue : [],
- dayTextureSaturation : [],
- dayTextureOneOverGamma : [],
- dayTextureSplit : [],
- dayTextureCutoutRectangles : [],
- dayIntensity : 0.0,
- colorsToAlpha : [],
- southAndNorthLatitude : new Cartesian2(),
- southMercatorYAndOneOverHeight : new Cartesian2(),
- waterMask : undefined,
- waterMaskTranslationAndScale : new Cartesian4(),
- minMaxHeight : new Cartesian2(),
- scaleAndBias : new Matrix4(),
- clippingPlanesEdgeColor : Color.clone(Color.WHITE),
- clippingPlanesEdgeWidth : 0.0,
- localizedCartographicLimitRectangle : new Cartesian4()
- }
- };
- return uniformMap;
- }
- function createWireframeVertexArrayIfNecessary(context, provider, tile) {
- var surfaceTile = tile.data;
- var mesh;
- var vertexArray;
- if (defined(surfaceTile.vertexArray)) {
- mesh = surfaceTile.mesh;
- vertexArray = surfaceTile.vertexArray;
- } else if (defined(surfaceTile.fill) && defined(surfaceTile.fill.vertexArray)) {
- mesh = surfaceTile.fill.mesh;
- vertexArray = surfaceTile.fill.vertexArray;
- }
- if (!defined(mesh) || !defined(vertexArray)) {
- return;
- }
- if (defined(surfaceTile.wireframeVertexArray)) {
- if (surfaceTile.wireframeVertexArray.mesh === mesh) {
- return;
- }
- surfaceTile.wireframeVertexArray.destroy();
- surfaceTile.wireframeVertexArray = undefined;
- }
- surfaceTile.wireframeVertexArray = createWireframeVertexArray(context, vertexArray, mesh);
- surfaceTile.wireframeVertexArray.mesh = mesh;
- }
- /**
- * Creates a vertex array for wireframe rendering of a terrain tile.
- *
- * @private
- *
- * @param {Context} context The context in which to create the vertex array.
- * @param {VertexArray} vertexArray The existing, non-wireframe vertex array. The new vertex array
- * will share vertex buffers with this existing one.
- * @param {TerrainMesh} terrainMesh The terrain mesh containing non-wireframe indices.
- * @returns {VertexArray} The vertex array for wireframe rendering.
- */
- function createWireframeVertexArray(context, vertexArray, terrainMesh) {
- var indices = terrainMesh.indices;
- var geometry = {
- indices : indices,
- primitiveType : PrimitiveType.TRIANGLES
- };
- GeometryPipeline.toWireframe(geometry);
- var wireframeIndices = geometry.indices;
- var wireframeIndexBuffer = Buffer.createIndexBuffer({
- context : context,
- typedArray : wireframeIndices,
- usage : BufferUsage.STATIC_DRAW,
- indexDatatype : IndexDatatype.fromSizeInBytes(wireframeIndices.BYTES_PER_ELEMENT)
- });
- return new VertexArray({
- context : context,
- attributes : vertexArray._attributes,
- indexBuffer : wireframeIndexBuffer
- });
- }
- var getDebugOrientedBoundingBox;
- var getDebugBoundingSphere;
- var debugDestroyPrimitive;
- (function() {
- var instanceOBB = new GeometryInstance({
- geometry : BoxOutlineGeometry.fromDimensions({dimensions : new Cartesian3(2.0, 2.0, 2.0)})
- });
- var instanceSphere = new GeometryInstance({
- geometry : new SphereOutlineGeometry({radius : 1.0})
- });
- var modelMatrix = new Matrix4();
- var previousVolume;
- var primitive;
- function createDebugPrimitive(instance) {
- return new Primitive({
- geometryInstances : instance,
- appearance : new PerInstanceColorAppearance({
- translucent : false,
- flat : true
- }),
- asynchronous : false
- });
- }
- getDebugOrientedBoundingBox = function(obb, color) {
- if (obb === previousVolume) {
- return primitive;
- }
- debugDestroyPrimitive();
- previousVolume = obb;
- modelMatrix = Matrix4.fromRotationTranslation(obb.halfAxes, obb.center, modelMatrix);
- instanceOBB.modelMatrix = modelMatrix;
- instanceOBB.attributes.color = ColorGeometryInstanceAttribute.fromColor(color);
- primitive = createDebugPrimitive(instanceOBB);
- return primitive;
- };
- getDebugBoundingSphere = function(sphere, color) {
- if (sphere === previousVolume) {
- return primitive;
- }
- debugDestroyPrimitive();
- previousVolume = sphere;
- modelMatrix = Matrix4.fromTranslation(sphere.center, modelMatrix);
- modelMatrix = Matrix4.multiplyByUniformScale(modelMatrix, sphere.radius, modelMatrix);
- instanceSphere.modelMatrix = modelMatrix;
- instanceSphere.attributes.color = ColorGeometryInstanceAttribute.fromColor(color);
- primitive = createDebugPrimitive(instanceSphere);
- return primitive;
- };
- debugDestroyPrimitive = function() {
- if (defined(primitive)) {
- primitive.destroy();
- primitive = undefined;
- previousVolume = undefined;
- }
- };
- })();
- var otherPassesInitialColor = new Cartesian4(0.0, 0.0, 0.0, 0.0);
- var surfaceShaderSetOptionsScratch = {
- frameState : undefined,
- surfaceTile : undefined,
- numberOfDayTextures : undefined,
- applyBrightness : undefined,
- applyContrast : undefined,
- applyHue : undefined,
- applySaturation : undefined,
- applyGamma : undefined,
- applyAlpha : undefined,
- applySplit : undefined,
- showReflectiveOcean : undefined,
- showOceanWaves : undefined,
- enableLighting : undefined,
- showGroundAtmosphere : undefined,
- perFragmentGroundAtmosphere : undefined,
- hasVertexNormals : undefined,
- useWebMercatorProjection : undefined,
- enableFog : undefined,
- enableClippingPlanes : undefined,
- clippingPlanes : undefined,
- clippedByBoundaries : undefined,
- hasImageryLayerCutout : undefined,
- colorCorrect : undefined,
- colorToAlpha : undefined
- };
- function addDrawCommandsForTile(tileProvider, tile, frameState) {
- var surfaceTile = tile.data;
- if (!defined(surfaceTile.vertexArray)) {
- if (surfaceTile.fill === undefined) {
- // No fill was created for this tile, probably because this tile is not connected to
- // any renderable tiles. So create a simple tile in the middle of the tile's possible
- // height range.
- surfaceTile.fill = new TerrainFillMesh(tile);
- }
- surfaceTile.fill.update(tileProvider, frameState);
- }
- var creditDisplay = frameState.creditDisplay;
- var terrainData = surfaceTile.terrainData;
- if (defined(terrainData) && defined(terrainData.credits)) {
- var tileCredits = terrainData.credits;
- for (var tileCreditIndex = 0,
- tileCreditLength = tileCredits.length; tileCreditIndex < tileCreditLength; ++tileCreditIndex) {
- creditDisplay.addCredit(tileCredits[tileCreditIndex]);
- }
- }
- var maxTextures = ContextLimits.maximumTextureImageUnits;
- var waterMaskTexture = surfaceTile.waterMaskTexture;
- var waterMaskTranslationAndScale = surfaceTile.waterMaskTranslationAndScale;
- if (!defined(waterMaskTexture) && defined(surfaceTile.fill)) {
- waterMaskTexture = surfaceTile.fill.waterMaskTexture;
- waterMaskTranslationAndScale = surfaceTile.fill.waterMaskTranslationAndScale;
- }
- var showReflectiveOcean = tileProvider.hasWaterMask && defined(waterMaskTexture);
- var oceanNormalMap = tileProvider.oceanNormalMap;
- var showOceanWaves = showReflectiveOcean && defined(oceanNormalMap);
- var hasVertexNormals = tileProvider.terrainProvider.ready && tileProvider.terrainProvider.hasVertexNormals;
- var enableFog = frameState.fog.enabled;
- var showGroundAtmosphere = tileProvider.showGroundAtmosphere;
- var castShadows = ShadowMode.castShadows(tileProvider.shadows);
- var receiveShadows = ShadowMode.receiveShadows(tileProvider.shadows);
- var hueShift = tileProvider.hueShift;
- var saturationShift = tileProvider.saturationShift;
- var brightnessShift = tileProvider.brightnessShift;
- var colorCorrect = !(CesiumMath.equalsEpsilon(hueShift, 0.0, CesiumMath.EPSILON7) &&
- CesiumMath.equalsEpsilon(saturationShift, 0.0, CesiumMath.EPSILON7) &&
- CesiumMath.equalsEpsilon(brightnessShift, 0.0, CesiumMath.EPSILON7));
- var perFragmentGroundAtmosphere = false;
- if (showGroundAtmosphere) {
- var mode = frameState.mode;
- var camera = frameState.camera;
- var cameraDistance;
- if (mode === SceneMode.SCENE2D || mode === SceneMode.COLUMBUS_VIEW) {
- cameraDistance = camera.positionCartographic.height;
- } else {
- cameraDistance = Cartesian3.magnitude(camera.positionWC);
- }
- var fadeOutDistance = tileProvider.nightFadeOutDistance;
- if (mode !== SceneMode.SCENE3D) {
- fadeOutDistance -= frameState.mapProjection.ellipsoid.maximumRadius;
- }
- perFragmentGroundAtmosphere = cameraDistance > fadeOutDistance;
- }
- if (showReflectiveOcean) {
- --maxTextures;
- }
- if (showOceanWaves) {
- --maxTextures;
- }
- if (defined(frameState.shadowState) && frameState.shadowState.shadowsEnabled) {
- --maxTextures;
- }
- if (defined(tileProvider.clippingPlanes) && tileProvider.clippingPlanes.enabled) {
- --maxTextures;
- }
- var mesh = surfaceTile.renderedMesh;
- var rtc = mesh.center;
- var encoding = mesh.encoding;
- // Not used in 3D.
- var tileRectangle = tileRectangleScratch;
- // Only used for Mercator projections.
- var southLatitude = 0.0;
- var northLatitude = 0.0;
- var southMercatorY = 0.0;
- var oneOverMercatorHeight = 0.0;
- var useWebMercatorProjection = false;
- if (frameState.mode !== SceneMode.SCENE3D) {
- var projection = frameState.mapProjection;
- var southwest = projection.project(Rectangle.southwest(tile.rectangle), southwestScratch);
- var northeast = projection.project(Rectangle.northeast(tile.rectangle), northeastScratch);
- tileRectangle.x = southwest.x;
- tileRectangle.y = southwest.y;
- tileRectangle.z = northeast.x;
- tileRectangle.w = northeast.y;
- // In 2D and Columbus View, use the center of the tile for RTC rendering.
- if (frameState.mode !== SceneMode.MORPHING) {
- rtc = rtcScratch;
- rtc.x = 0.0;
- rtc.y = (tileRectangle.z + tileRectangle.x) * 0.5;
- rtc.z = (tileRectangle.w + tileRectangle.y) * 0.5;
- tileRectangle.x -= rtc.y;
- tileRectangle.y -= rtc.z;
- tileRectangle.z -= rtc.y;
- tileRectangle.w -= rtc.z;
- }
- if (frameState.mode === SceneMode.SCENE2D && encoding.quantization === TerrainQuantization.BITS12) {
- // In 2D, the texture coordinates of the tile are interpolated over the rectangle to get the position in the vertex shader.
- // When the texture coordinates are quantized, error is introduced. This can be seen through the 1px wide cracking
- // between the quantized tiles in 2D. To compensate for the error, move the expand the rectangle in each direction by
- // half the error amount.
- var epsilon = (1.0 / (Math.pow(2.0, 12.0) - 1.0)) * 0.5;
- var widthEpsilon = (tileRectangle.z - tileRectangle.x) * epsilon;
- var heightEpsilon = (tileRectangle.w - tileRectangle.y) * epsilon;
- tileRectangle.x -= widthEpsilon;
- tileRectangle.y -= heightEpsilon;
- tileRectangle.z += widthEpsilon;
- tileRectangle.w += heightEpsilon;
- }
- if (projection instanceof WebMercatorProjection) {
- southLatitude = tile.rectangle.south;
- northLatitude = tile.rectangle.north;
- southMercatorY = WebMercatorProjection.geodeticLatitudeToMercatorAngle(southLatitude);
- oneOverMercatorHeight = 1.0 / (WebMercatorProjection.geodeticLatitudeToMercatorAngle(northLatitude) - southMercatorY);
- useWebMercatorProjection = true;
- }
- }
- var surfaceShaderSetOptions = surfaceShaderSetOptionsScratch;
- surfaceShaderSetOptions.frameState = frameState;
- surfaceShaderSetOptions.surfaceTile = surfaceTile;
- surfaceShaderSetOptions.showReflectiveOcean = showReflectiveOcean;
- surfaceShaderSetOptions.showOceanWaves = showOceanWaves;
- surfaceShaderSetOptions.enableLighting = tileProvider.enableLighting;
- surfaceShaderSetOptions.showGroundAtmosphere = showGroundAtmosphere;
- surfaceShaderSetOptions.perFragmentGroundAtmosphere = perFragmentGroundAtmosphere;
- surfaceShaderSetOptions.hasVertexNormals = hasVertexNormals;
- surfaceShaderSetOptions.useWebMercatorProjection = useWebMercatorProjection;
- surfaceShaderSetOptions.clippedByBoundaries = surfaceTile.clippedByBoundaries;
- var tileImageryCollection = surfaceTile.imagery;
- var imageryIndex = 0;
- var imageryLen = tileImageryCollection.length;
- var firstPassRenderState = tileProvider._renderState;
- var otherPassesRenderState = tileProvider._blendRenderState;
- var renderState = firstPassRenderState;
- var initialColor = tileProvider._firstPassInitialColor;
- var context = frameState.context;
- if (!defined(tileProvider._debug.boundingSphereTile)) {
- debugDestroyPrimitive();
- }
- do {
- var numberOfDayTextures = 0;
- var command;
- var uniformMap;
- if (tileProvider._drawCommands.length <= tileProvider._usedDrawCommands) {
- command = new DrawCommand();
- command.owner = tile;
- command.cull = false;
- command.boundingVolume = new BoundingSphere();
- command.orientedBoundingBox = undefined;
- uniformMap = createTileUniformMap(frameState, tileProvider);
- tileProvider._drawCommands.push(command);
- tileProvider._uniformMaps.push(uniformMap);
- } else {
- command = tileProvider._drawCommands[tileProvider._usedDrawCommands];
- uniformMap = tileProvider._uniformMaps[tileProvider._usedDrawCommands];
- }
- command.owner = tile;
- ++tileProvider._usedDrawCommands;
- if (tile === tileProvider._debug.boundingSphereTile) {
- var obb = surfaceTile.orientedBoundingBox;
- // If a debug primitive already exists for this tile, it will not be
- // re-created, to avoid allocation every frame. If it were possible
- // to have more than one selected tile, this would have to change.
- if (defined(obb)) {
- getDebugOrientedBoundingBox(obb, Color.RED).update(frameState);
- } else if (defined(mesh) && defined(mesh.boundingSphere3D)) {
- getDebugBoundingSphere(mesh.boundingSphere3D, Color.RED).update(frameState);
- }
- }
- var uniformMapProperties = uniformMap.properties;
- Cartesian4.clone(initialColor, uniformMapProperties.initialColor);
- uniformMapProperties.oceanNormalMap = oceanNormalMap;
- uniformMapProperties.lightingFadeDistance.x = tileProvider.lightingFadeOutDistance;
- uniformMapProperties.lightingFadeDistance.y = tileProvider.lightingFadeInDistance;
- uniformMapProperties.nightFadeDistance.x = tileProvider.nightFadeOutDistance;
- uniformMapProperties.nightFadeDistance.y = tileProvider.nightFadeInDistance;
- uniformMapProperties.zoomedOutOceanSpecularIntensity = tileProvider.zoomedOutOceanSpecularIntensity;
- var highlightFillTile = !defined(surfaceTile.vertexArray) && defined(tileProvider.fillHighlightColor) && tileProvider.fillHighlightColor.alpha > 0.0;
- if (highlightFillTile) {
- Color.clone(tileProvider.fillHighlightColor, uniformMapProperties.fillHighlightColor);
- }
- uniformMapProperties.center3D = mesh.center;
- Cartesian3.clone(rtc, uniformMapProperties.rtc);
- Cartesian4.clone(tileRectangle, uniformMapProperties.tileRectangle);
- uniformMapProperties.southAndNorthLatitude.x = southLatitude;
- uniformMapProperties.southAndNorthLatitude.y = northLatitude;
- uniformMapProperties.southMercatorYAndOneOverHeight.x = southMercatorY;
- uniformMapProperties.southMercatorYAndOneOverHeight.y = oneOverMercatorHeight;
- // Convert tile limiter rectangle from cartographic to texture space using the tileRectangle.
- var localizedCartographicLimitRectangle = localizedCartographicLimitRectangleScratch;
- var cartographicLimitRectangle = clipRectangleAntimeridian(tile.rectangle, tileProvider.cartographicLimitRectangle);
- Cartesian3.fromElements(hueShift, saturationShift, brightnessShift, uniformMapProperties.hsbShift);
- var cartographicTileRectangle = tile.rectangle;
- var inverseTileWidth = 1.0 / cartographicTileRectangle.width;
- var inverseTileHeight = 1.0 / cartographicTileRectangle.height;
- localizedCartographicLimitRectangle.x = (cartographicLimitRectangle.west - cartographicTileRectangle.west) * inverseTileWidth;
- localizedCartographicLimitRectangle.y = (cartographicLimitRectangle.south - cartographicTileRectangle.south) * inverseTileHeight;
- localizedCartographicLimitRectangle.z = (cartographicLimitRectangle.east - cartographicTileRectangle.west) * inverseTileWidth;
- localizedCartographicLimitRectangle.w = (cartographicLimitRectangle.north - cartographicTileRectangle.south) * inverseTileHeight;
- Cartesian4.clone(localizedCartographicLimitRectangle, uniformMapProperties.localizedCartographicLimitRectangle);
- // For performance, use fog in the shader only when the tile is in fog.
- var applyFog = enableFog && CesiumMath.fog(tile._distance, frameState.fog.density) > CesiumMath.EPSILON3;
- colorCorrect = colorCorrect && (applyFog || showGroundAtmosphere);
- var applyBrightness = false;
- var applyContrast = false;
- var applyHue = false;
- var applySaturation = false;
- var applyGamma = false;
- var applyAlpha = false;
- var applySplit = false;
- var applyCutout = false;
- var applyColorToAlpha = false;
- while (numberOfDayTextures < maxTextures && imageryIndex < imageryLen) {
- var tileImagery = tileImageryCollection[imageryIndex];
- var imagery = tileImagery.readyImagery;
- ++imageryIndex;
- if (!defined(imagery) || imagery.imageryLayer.alpha === 0.0) {
- continue;
- }
- var texture = tileImagery.useWebMercatorT ? imagery.textureWebMercator : imagery.texture;
- //>>includeStart('debug', pragmas.debug);
- if (!defined(texture)) {
- // Our "ready" texture isn't actually ready. This should never happen.
- //
- // Side note: It IS possible for it to not be in the READY ImageryState, though.
- // This can happen when a single imagery tile is shared by two terrain tiles (common)
- // and one of them (A) needs a geographic version of the tile because it is near the poles,
- // and the other (B) does not. B can and will transition the imagery tile to the READY state
- // without reprojecting to geographic. Then, later, A will deem that same tile not-ready-yet
- // because it only has the Web Mercator texture, and flip it back to the TRANSITIONING state.
- // The imagery tile won't be in the READY state anymore, but it's still READY enough for B's
- // purposes.
- throw new DeveloperError('readyImagery is not actually ready!');
- }
- //>>includeEnd('debug');
- var imageryLayer = imagery.imageryLayer;
- if (!defined(tileImagery.textureTranslationAndScale)) {
- tileImagery.textureTranslationAndScale = imageryLayer._calculateTextureTranslationAndScale(tile, tileImagery);
- }
- uniformMapProperties.dayTextures[numberOfDayTextures] = texture;
- uniformMapProperties.dayTextureTranslationAndScale[numberOfDayTextures] = tileImagery.textureTranslationAndScale;
- uniformMapProperties.dayTextureTexCoordsRectangle[numberOfDayTextures] = tileImagery.textureCoordinateRectangle;
- uniformMapProperties.dayTextureUseWebMercatorT[numberOfDayTextures] = tileImagery.useWebMercatorT;
- uniformMapProperties.dayTextureAlpha[numberOfDayTextures] = imageryLayer.alpha;
- applyAlpha = applyAlpha || uniformMapProperties.dayTextureAlpha[numberOfDayTextures] !== 1.0;
- uniformMapProperties.dayTextureBrightness[numberOfDayTextures] = imageryLayer.brightness;
- applyBrightness = applyBrightness || uniformMapProperties.dayTextureBrightness[numberOfDayTextures] !== ImageryLayer.DEFAULT_BRIGHTNESS;
- uniformMapProperties.dayTextureContrast[numberOfDayTextures] = imageryLayer.contrast;
- applyContrast = applyContrast || uniformMapProperties.dayTextureContrast[numberOfDayTextures] !== ImageryLayer.DEFAULT_CONTRAST;
- uniformMapProperties.dayTextureHue[numberOfDayTextures] = imageryLayer.hue;
- applyHue = applyHue || uniformMapProperties.dayTextureHue[numberOfDayTextures] !== ImageryLayer.DEFAULT_HUE;
- uniformMapProperties.dayTextureSaturation[numberOfDayTextures] = imageryLayer.saturation;
- applySaturation = applySaturation || uniformMapProperties.dayTextureSaturation[numberOfDayTextures] !== ImageryLayer.DEFAULT_SATURATION;
- uniformMapProperties.dayTextureOneOverGamma[numberOfDayTextures] = 1.0 / imageryLayer.gamma;
- applyGamma = applyGamma || uniformMapProperties.dayTextureOneOverGamma[numberOfDayTextures] !== 1.0 / ImageryLayer.DEFAULT_GAMMA;
- uniformMapProperties.dayTextureSplit[numberOfDayTextures] = imageryLayer.splitDirection;
- applySplit = applySplit || uniformMapProperties.dayTextureSplit[numberOfDayTextures] !== 0.0;
- // Update cutout rectangle
- var dayTextureCutoutRectangle = uniformMapProperties.dayTextureCutoutRectangles[numberOfDayTextures];
- if (!defined(dayTextureCutoutRectangle)) {
- dayTextureCutoutRectangle = uniformMapProperties.dayTextureCutoutRectangles[numberOfDayTextures] = new Cartesian4();
- }
- Cartesian4.clone(Cartesian4.ZERO, dayTextureCutoutRectangle);
- if (defined(imageryLayer.cutoutRectangle)) {
- var cutoutRectangle = clipRectangleAntimeridian(cartographicTileRectangle, imageryLayer.cutoutRectangle);
- var intersection = Rectangle.simpleIntersection(cutoutRectangle, cartographicTileRectangle, rectangleIntersectionScratch);
- applyCutout = defined(intersection) || applyCutout;
- dayTextureCutoutRectangle.x = (cutoutRectangle.west - cartographicTileRectangle.west) * inverseTileWidth;
- dayTextureCutoutRectangle.y = (cutoutRectangle.south - cartographicTileRectangle.south) * inverseTileHeight;
- dayTextureCutoutRectangle.z = (cutoutRectangle.east - cartographicTileRectangle.west) * inverseTileWidth;
- dayTextureCutoutRectangle.w = (cutoutRectangle.north - cartographicTileRectangle.south) * inverseTileHeight;
- }
- // Update color to alpha
- var colorToAlpha = uniformMapProperties.colorsToAlpha[numberOfDayTextures];
- if (!defined(colorToAlpha)) {
- colorToAlpha = uniformMapProperties.colorsToAlpha[numberOfDayTextures] = new Cartesian4();
- }
- var hasColorToAlpha = defined(imageryLayer.colorToAlpha) && imageryLayer.colorToAlphaThreshold > 0.0;
- applyColorToAlpha = applyColorToAlpha || hasColorToAlpha;
- if (hasColorToAlpha) {
- var color = imageryLayer.colorToAlpha;
- colorToAlpha.x = color.red;
- colorToAlpha.y = color.green;
- colorToAlpha.z = color.blue;
- colorToAlpha.w = imageryLayer.colorToAlphaThreshold;
- } else {
- colorToAlpha.w = -1.0;
- }
- if (defined(imagery.credits)) {
- var credits = imagery.credits;
- for (var creditIndex = 0, creditLength = credits.length; creditIndex < creditLength; ++creditIndex) {
- creditDisplay.addCredit(credits[creditIndex]);
- }
- }
- ++numberOfDayTextures;
- }
- // trim texture array to the used length so we don't end up using old textures
- // which might get destroyed eventually
- uniformMapProperties.dayTextures.length = numberOfDayTextures;
- uniformMapProperties.waterMask = waterMaskTexture;
- Cartesian4.clone(waterMaskTranslationAndScale, uniformMapProperties.waterMaskTranslationAndScale);
- uniformMapProperties.minMaxHeight.x = encoding.minimumHeight;
- uniformMapProperties.minMaxHeight.y = encoding.maximumHeight;
- Matrix4.clone(encoding.matrix, uniformMapProperties.scaleAndBias);
- // update clipping planes
- var clippingPlanes = tileProvider._clippingPlanes;
- var clippingPlanesEnabled = defined(clippingPlanes) && clippingPlanes.enabled && tile.isClipped;
- if (clippingPlanesEnabled) {
- uniformMapProperties.clippingPlanesEdgeColor = Color.clone(clippingPlanes.edgeColor, uniformMapProperties.clippingPlanesEdgeColor);
- uniformMapProperties.clippingPlanesEdgeWidth = clippingPlanes.edgeWidth;
- }
- if (defined(tileProvider.uniformMap)) {
- uniformMap = combine(uniformMap, tileProvider.uniformMap);
- }
- surfaceShaderSetOptions.numberOfDayTextures = numberOfDayTextures;
- surfaceShaderSetOptions.applyBrightness = applyBrightness;
- surfaceShaderSetOptions.applyContrast = applyContrast;
- surfaceShaderSetOptions.applyHue = applyHue;
- surfaceShaderSetOptions.applySaturation = applySaturation;
- surfaceShaderSetOptions.applyGamma = applyGamma;
- surfaceShaderSetOptions.applyAlpha = applyAlpha;
- surfaceShaderSetOptions.applySplit = applySplit;
- surfaceShaderSetOptions.enableFog = applyFog;
- surfaceShaderSetOptions.enableClippingPlanes = clippingPlanesEnabled;
- surfaceShaderSetOptions.clippingPlanes = clippingPlanes;
- surfaceShaderSetOptions.hasImageryLayerCutout = applyCutout;
- surfaceShaderSetOptions.colorCorrect = colorCorrect;
- surfaceShaderSetOptions.highlightFillTile = highlightFillTile;
- surfaceShaderSetOptions.colorToAlpha = applyColorToAlpha;
- command.shaderProgram = tileProvider._surfaceShaderSet.getShaderProgram(surfaceShaderSetOptions);
- command.castShadows = castShadows;
- command.receiveShadows = receiveShadows;
- command.renderState = renderState;
- command.primitiveType = PrimitiveType.TRIANGLES;
- command.vertexArray = surfaceTile.vertexArray || surfaceTile.fill.vertexArray;
- command.uniformMap = uniformMap;
- command.pass = Pass.GLOBE;
- if (tileProvider._debug.wireframe) {
- createWireframeVertexArrayIfNecessary(context, tileProvider, tile);
- if (defined(surfaceTile.wireframeVertexArray)) {
- command.vertexArray = surfaceTile.wireframeVertexArray;
- command.primitiveType = PrimitiveType.LINES;
- }
- }
- var boundingVolume = command.boundingVolume;
- var orientedBoundingBox = command.orientedBoundingBox;
- if (frameState.mode !== SceneMode.SCENE3D) {
- var tileBoundingRegion = surfaceTile.tileBoundingRegion;
- BoundingSphere.fromRectangleWithHeights2D(tile.rectangle, frameState.mapProjection, tileBoundingRegion.minimumHeight, tileBoundingRegion.maximumHeight, boundingVolume);
- Cartesian3.fromElements(boundingVolume.center.z, boundingVolume.center.x, boundingVolume.center.y, boundingVolume.center);
- if (frameState.mode === SceneMode.MORPHING) {
- boundingVolume = BoundingSphere.union(mesh.boundingSphere3D, boundingVolume, boundingVolume);
- }
- } else {
- command.boundingVolume = BoundingSphere.clone(mesh.boundingSphere3D, boundingVolume);
- command.orientedBoundingBox = OrientedBoundingBox.clone(surfaceTile.orientedBoundingBox, orientedBoundingBox);
- }
- command.dirty = true;
- frameState.commandList.push(command);
- renderState = otherPassesRenderState;
- initialColor = otherPassesInitialColor;
- } while (imageryIndex < imageryLen);
- }
- export default GlobeSurfaceTileProvider;
|