cesium
Version:
CesiumJS is a JavaScript library for creating 3D globes and 2D maps in a web browser without a plugin.
956 lines (876 loc) • 107 kB
JavaScript
import ApproximateTerrainHeights from '../Core/ApproximateTerrainHeights.js';
import Cartesian2 from '../Core/Cartesian2.js';
import Cartesian3 from '../Core/Cartesian3.js';
import Cartographic from '../Core/Cartographic.js';
import Check from '../Core/Check.js';
import Credit from '../Core/Credit.js';
import defaultValue from '../Core/defaultValue.js';
import defined from '../Core/defined.js';
import deprecationWarning from '../Core/deprecationWarning.js';
import destroyObject from '../Core/destroyObject.js';
import DeveloperError from '../Core/DeveloperError.js';
import Ellipsoid from '../Core/Ellipsoid.js';
import Event from '../Core/Event.js';
import JulianDate from '../Core/JulianDate.js';
import ManagedArray from '../Core/ManagedArray.js';
import CesiumMath from '../Core/Math.js';
import Matrix4 from '../Core/Matrix4.js';
import Resource from '../Core/Resource.js';
import RuntimeError from '../Core/RuntimeError.js';
import Transforms from '../Core/Transforms.js';
import ClearCommand from '../Renderer/ClearCommand.js';
import Pass from '../Renderer/Pass.js';
import RenderState from '../Renderer/RenderState.js';
import when from '../ThirdParty/when.js';
import Axis from './Axis.js';
import Cesium3DTile from './Cesium3DTile.js';
import Cesium3DTileColorBlendMode from './Cesium3DTileColorBlendMode.js';
import Cesium3DTileContentState from './Cesium3DTileContentState.js';
import Cesium3DTileOptimizations from './Cesium3DTileOptimizations.js';
import Cesium3DTilePass from './Cesium3DTilePass.js';
import Cesium3DTileRefine from './Cesium3DTileRefine.js';
import Cesium3DTilesetCache from './Cesium3DTilesetCache.js';
import Cesium3DTilesetHeatmap from './Cesium3DTilesetHeatmap.js';
import Cesium3DTilesetStatistics from './Cesium3DTilesetStatistics.js';
import Cesium3DTileStyleEngine from './Cesium3DTileStyleEngine.js';
import ClippingPlaneCollection from './ClippingPlaneCollection.js';
import LabelCollection from './LabelCollection.js';
import PointCloudEyeDomeLighting from './PointCloudEyeDomeLighting.js';
import PointCloudShading from './PointCloudShading.js';
import SceneMode from './SceneMode.js';
import ShadowMode from './ShadowMode.js';
import StencilConstants from './StencilConstants.js';
import TileBoundingRegion from './TileBoundingRegion.js';
import TileBoundingSphere from './TileBoundingSphere.js';
import TileOrientedBoundingBox from './TileOrientedBoundingBox.js';
/**
* A {@link https://github.com/CesiumGS/3d-tiles/tree/master/specification|3D Tiles tileset},
* used for streaming massive heterogeneous 3D geospatial datasets.
*
* @alias Cesium3DTileset
* @constructor
*
* @param {Object} options Object with the following properties:
* @param {Resource|String|Promise<Resource>|Promise<String>} options.url The url to a tileset JSON file.
* @param {Boolean} [options.show=true] Determines if the tileset will be shown.
* @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] A 4x4 transformation matrix that transforms the tileset's root tile.
* @param {ShadowMode} [options.shadows=ShadowMode.ENABLED] Determines whether the tileset casts or receives shadows from light sources.
* @param {Number} [options.maximumScreenSpaceError=16] The maximum screen space error used to drive level of detail refinement.
* @param {Number} [options.maximumMemoryUsage=512] The maximum amount of memory in MB that can be used by the tileset.
* @param {Boolean} [options.cullWithChildrenBounds=true] Optimization option. Whether to cull tiles using the union of their children bounding volumes.
* @param {Boolean} [options.cullRequestsWhileMoving=true] Optimization option. Don't request tiles that will likely be unused when they come back because of the camera's movement. This optimization only applies to stationary tilesets.
* @param {Number} [options.cullRequestsWhileMovingMultiplier=60.0] Optimization option. Multiplier used in culling requests while moving. Larger is more aggressive culling, smaller less aggressive culling.
* @param {Boolean} [options.preloadWhenHidden=false] Preload tiles when <code>tileset.show</code> is <code>false</code>. Loads tiles as if the tileset is visible but does not render them.
* @param {Boolean} [options.preloadFlightDestinations=true] Optimization option. Preload tiles at the camera's flight destination while the camera is in flight.
* @param {Boolean} [options.preferLeaves=false] Optimization option. Prefer loading of leaves first.
* @param {Boolean} [options.dynamicScreenSpaceError=false] Optimization option. Reduce the screen space error for tiles that are further away from the camera.
* @param {Number} [options.dynamicScreenSpaceErrorDensity=0.00278] Density used to adjust the dynamic screen space error, similar to fog density.
* @param {Number} [options.dynamicScreenSpaceErrorFactor=4.0] A factor used to increase the computed dynamic screen space error.
* @param {Number} [options.dynamicScreenSpaceErrorHeightFalloff=0.25] A ratio of the tileset's height at which the density starts to falloff.
* @param {Number} [options.progressiveResolutionHeightFraction=0.3] Optimization option. If between (0.0, 0.5], tiles at or above the screen space error for the reduced screen resolution of <code>progressiveResolutionHeightFraction*screenHeight</code> will be prioritized first. This can help get a quick layer of tiles down while full resolution tiles continue to load.
* @param {Boolean} [options.foveatedScreenSpaceError=true] Optimization option. Prioritize loading tiles in the center of the screen by temporarily raising the screen space error for tiles around the edge of the screen. Screen space error returns to normal once all the tiles in the center of the screen as determined by the {@link Cesium3DTileset#foveatedConeSize} are loaded.
* @param {Number} [options.foveatedConeSize=0.1] Optimization option. Used when {@link Cesium3DTileset#foveatedScreenSpaceError} is true to control the cone size that determines which tiles are deferred. Tiles that are inside this cone are loaded immediately. Tiles outside the cone are potentially deferred based on how far outside the cone they are and their screen space error. This is controlled by {@link Cesium3DTileset#foveatedInterpolationCallback} and {@link Cesium3DTileset#foveatedMinimumScreenSpaceErrorRelaxation}. Setting this to 0.0 means the cone will be the line formed by the camera position and its view direction. Setting this to 1.0 means the cone encompasses the entire field of view of the camera, disabling the effect.
* @param {Number} [options.foveatedMinimumScreenSpaceErrorRelaxation=0.0] Optimization option. Used when {@link Cesium3DTileset#foveatedScreenSpaceError} is true to control the starting screen space error relaxation for tiles outside the foveated cone. The screen space error will be raised starting with tileset value up to {@link Cesium3DTileset#maximumScreenSpaceError} based on the provided {@link Cesium3DTileset#foveatedInterpolationCallback}.
* @param {Cesium3DTileset~foveatedInterpolationCallback} [options.foveatedInterpolationCallback=Math.lerp] Optimization option. Used when {@link Cesium3DTileset#foveatedScreenSpaceError} is true to control how much to raise the screen space error for tiles outside the foveated cone, interpolating between {@link Cesium3DTileset#foveatedMinimumScreenSpaceErrorRelaxation} and {@link Cesium3DTileset#maximumScreenSpaceError}
* @param {Number} [options.foveatedTimeDelay=0.2] Optimization option. Used when {@link Cesium3DTileset#foveatedScreenSpaceError} is true to control how long in seconds to wait after the camera stops moving before deferred tiles start loading in. This time delay prevents requesting tiles around the edges of the screen when the camera is moving. Setting this to 0.0 will immediately request all tiles in any given view.
* @param {Boolean} [options.skipLevelOfDetail=false] Optimization option. Determines if level of detail skipping should be applied during the traversal.
* @param {Number} [options.baseScreenSpaceError=1024] When <code>skipLevelOfDetail</code> is <code>true</code>, the screen space error that must be reached before skipping levels of detail.
* @param {Number} [options.skipScreenSpaceErrorFactor=16] When <code>skipLevelOfDetail</code> is <code>true</code>, a multiplier defining the minimum screen space error to skip. Used in conjunction with <code>skipLevels</code> to determine which tiles to load.
* @param {Number} [options.skipLevels=1] When <code>skipLevelOfDetail</code> is <code>true</code>, a constant defining the minimum number of levels to skip when loading tiles. When it is 0, no levels are skipped. Used in conjunction with <code>skipScreenSpaceErrorFactor</code> to determine which tiles to load.
* @param {Boolean} [options.immediatelyLoadDesiredLevelOfDetail=false] When <code>skipLevelOfDetail</code> is <code>true</code>, only tiles that meet the maximum screen space error will ever be downloaded. Skipping factors are ignored and just the desired tiles are loaded.
* @param {Boolean} [options.loadSiblings=false] When <code>skipLevelOfDetail</code> is <code>true</code>, determines whether siblings of visible tiles are always downloaded during traversal.
* @param {ClippingPlaneCollection} [options.clippingPlanes] The {@link ClippingPlaneCollection} used to selectively disable rendering the tileset.
* @param {ClassificationType} [options.classificationType] Determines whether terrain, 3D Tiles or both will be classified by this tileset. See {@link Cesium3DTileset#classificationType} for details about restrictions and limitations.
* @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid determining the size and shape of the globe.
* @param {Object} [options.pointCloudShading] Options for constructing a {@link PointCloudShading} object to control point attenuation based on geometric error and lighting.
* @param {Cartesian2} [options.imageBasedLightingFactor=new Cartesian2(1.0, 1.0)] Scales the diffuse and specular image-based lighting from the earth, sky, atmosphere and star skybox.
* @param {Cartesian3} [options.lightColor] The light color when shading models. When <code>undefined</code> the scene's light color is used instead.
* @param {Number} [options.luminanceAtZenith=0.2] The sun's luminance at the zenith in kilo candela per meter squared to use for this model's procedural environment map.
* @param {Cartesian3[]} [options.sphericalHarmonicCoefficients] The third order spherical harmonic coefficients used for the diffuse color of image-based lighting.
* @param {String} [options.specularEnvironmentMaps] A URL to a KTX file that contains a cube map of the specular lighting and the convoluted specular mipmaps.
* @param {String} [options.debugHeatmapTilePropertyName] The tile variable to colorize as a heatmap. All rendered tiles will be colorized relative to each other's specified variable value.
* @param {Boolean} [options.debugFreezeFrame=false] For debugging only. Determines if only the tiles from last frame should be used for rendering.
* @param {Boolean} [options.debugColorizeTiles=false] For debugging only. When true, assigns a random color to each tile.
* @param {Boolean} [options.debugWireframe=false] For debugging only. When true, render's each tile's content as a wireframe.
* @param {Boolean} [options.debugShowBoundingVolume=false] For debugging only. When true, renders the bounding volume for each tile.
* @param {Boolean} [options.debugShowContentBoundingVolume=false] For debugging only. When true, renders the bounding volume for each tile's content.
* @param {Boolean} [options.debugShowViewerRequestVolume=false] For debugging only. When true, renders the viewer request volume for each tile.
* @param {Boolean} [options.debugShowGeometricError=false] For debugging only. When true, draws labels to indicate the geometric error of each tile.
* @param {Boolean} [options.debugShowRenderingStatistics=false] For debugging only. When true, draws labels to indicate the number of commands, points, triangles and features for each tile.
* @param {Boolean} [options.debugShowMemoryUsage=false] For debugging only. When true, draws labels to indicate the texture and geometry memory in megabytes used by each tile.
* @param {Boolean} [options.debugShowUrl=false] For debugging only. When true, draws labels to indicate the url of each tile.
*
* @exception {DeveloperError} The tileset must be 3D Tiles version 0.0 or 1.0.
*
* @example
* var tileset = scene.primitives.add(new Cesium.Cesium3DTileset({
* url : 'http://localhost:8002/tilesets/Seattle/tileset.json'
* }));
*
* @example
* // Common setting for the skipLevelOfDetail optimization
* var tileset = scene.primitives.add(new Cesium.Cesium3DTileset({
* url : 'http://localhost:8002/tilesets/Seattle/tileset.json',
* skipLevelOfDetail : true,
* baseScreenSpaceError : 1024,
* skipScreenSpaceErrorFactor : 16,
* skipLevels : 1,
* immediatelyLoadDesiredLevelOfDetail : false,
* loadSiblings : false,
* cullWithChildrenBounds : true
* }));
*
* @example
* // Common settings for the dynamicScreenSpaceError optimization
* var tileset = scene.primitives.add(new Cesium.Cesium3DTileset({
* url : 'http://localhost:8002/tilesets/Seattle/tileset.json',
* dynamicScreenSpaceError : true,
* dynamicScreenSpaceErrorDensity : 0.00278,
* dynamicScreenSpaceErrorFactor : 4.0,
* dynamicScreenSpaceErrorHeightFalloff : 0.25
* }));
*
* @see {@link https://github.com/CesiumGS/3d-tiles/tree/master/specification|3D Tiles specification}
*/
function Cesium3DTileset(options) {
options = defaultValue(options, defaultValue.EMPTY_OBJECT);
//>>includeStart('debug', pragmas.debug);
Check.defined('options.url', options.url);
//>>includeEnd('debug');
this._url = undefined;
this._basePath = undefined;
this._root = undefined;
this._asset = undefined; // Metadata for the entire tileset
this._properties = undefined; // Metadata for per-model/point/etc properties
this._geometricError = undefined; // Geometric error when the tree is not rendered at all
this._extensionsUsed = undefined;
this._gltfUpAxis = undefined;
this._cache = new Cesium3DTilesetCache();
this._processingQueue = [];
this._selectedTiles = [];
this._emptyTiles = [];
this._requestedTiles = [];
this._selectedTilesToStyle = [];
this._loadTimestamp = undefined;
this._timeSinceLoad = 0.0;
this._updatedVisibilityFrame = 0;
this._updatedModelMatrixFrame = 0;
this._modelMatrixChanged = false;
this._previousModelMatrix = undefined;
this._extras = undefined;
this._credits = undefined;
this._cullWithChildrenBounds = defaultValue(options.cullWithChildrenBounds, true);
this._allTilesAdditive = true;
this._hasMixedContent = false;
this._stencilClearCommand = undefined;
this._backfaceCommands = new ManagedArray();
this._maximumScreenSpaceError = defaultValue(options.maximumScreenSpaceError, 16);
this._maximumMemoryUsage = defaultValue(options.maximumMemoryUsage, 512);
this._styleEngine = new Cesium3DTileStyleEngine();
this._modelMatrix = defined(options.modelMatrix) ? Matrix4.clone(options.modelMatrix) : Matrix4.clone(Matrix4.IDENTITY);
this._statistics = new Cesium3DTilesetStatistics();
this._statisticsLast = new Cesium3DTilesetStatistics();
this._statisticsPerPass = new Array(Cesium3DTilePass.NUMBER_OF_PASSES);
for (var i = 0; i < Cesium3DTilePass.NUMBER_OF_PASSES; ++i) {
this._statisticsPerPass[i] = new Cesium3DTilesetStatistics();
}
this._requestedTilesInFlight = [];
this._maximumPriority = { foveatedFactor: -Number.MAX_VALUE, depth: -Number.MAX_VALUE, distance: -Number.MAX_VALUE, reverseScreenSpaceError: -Number.MAX_VALUE };
this._minimumPriority = { foveatedFactor: Number.MAX_VALUE, depth: Number.MAX_VALUE, distance: Number.MAX_VALUE, reverseScreenSpaceError: Number.MAX_VALUE };
this._heatmap = new Cesium3DTilesetHeatmap(options.debugHeatmapTilePropertyName);
/**
* Optimization option. Don't request tiles that will likely be unused when they come back because of the camera's movement. This optimization only applies to stationary tilesets.
*
* @type {Boolean}
* @default true
*/
this.cullRequestsWhileMoving = defaultValue(options.cullRequestsWhileMoving, true);
this._cullRequestsWhileMoving = false;
/**
* Optimization option. Multiplier used in culling requests while moving. Larger is more aggressive culling, smaller less aggressive culling.
*
* @type {Number}
* @default 60.0
*/
this.cullRequestsWhileMovingMultiplier = defaultValue(options.cullRequestsWhileMovingMultiplier, 60.0);
/**
* Optimization option. If between (0.0, 0.5], tiles at or above the screen space error for the reduced screen resolution of <code>progressiveResolutionHeightFraction*screenHeight</code> will be prioritized first. This can help get a quick layer of tiles down while full resolution tiles continue to load.
*
* @type {Number}
* @default 0.3
*/
this.progressiveResolutionHeightFraction = CesiumMath.clamp(defaultValue(options.progressiveResolutionHeightFraction, 0.3), 0.0, 0.5);
/**
* Optimization option. Prefer loading of leaves first.
*
* @type {Boolean}
* @default false
*/
this.preferLeaves = defaultValue(options.preferLeaves, false);
this._tilesLoaded = false;
this._initialTilesLoaded = false;
this._tileDebugLabels = undefined;
this._readyPromise = when.defer();
this._classificationType = options.classificationType;
this._ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84);
this._initialClippingPlanesOriginMatrix = Matrix4.IDENTITY; // Computed from the tileset JSON.
this._clippingPlanesOriginMatrix = undefined; // Combines the above with any run-time transforms.
this._clippingPlanesOriginMatrixDirty = true;
/**
* Preload tiles when <code>tileset.show</code> is <code>false</code>. Loads tiles as if the tileset is visible but does not render them.
*
* @type {Boolean}
* @default false
*/
this.preloadWhenHidden = defaultValue(options.preloadWhenHidden, false);
/**
* Optimization option. Fetch tiles at the camera's flight destination while the camera is in flight.
*
* @type {Boolean}
* @default true
*/
this.preloadFlightDestinations = defaultValue(options.preloadFlightDestinations, true);
this._pass = undefined; // Cesium3DTilePass
/**
* Optimization option. Whether the tileset should refine based on a dynamic screen space error. Tiles that are further
* away will be rendered with lower detail than closer tiles. This improves performance by rendering fewer
* tiles and making less requests, but may result in a slight drop in visual quality for tiles in the distance.
* The algorithm is biased towards "street views" where the camera is close to the ground plane of the tileset and looking
* at the horizon. In addition results are more accurate for tightly fitting bounding volumes like box and region.
*
* @type {Boolean}
* @default false
*/
this.dynamicScreenSpaceError = defaultValue(options.dynamicScreenSpaceError, false);
/**
* Optimization option. Prioritize loading tiles in the center of the screen by temporarily raising the
* screen space error for tiles around the edge of the screen. Screen space error returns to normal once all
* the tiles in the center of the screen as determined by the {@link Cesium3DTileset#foveatedConeSize} are loaded.
*
* @type {Boolean}
* @default true
*/
this.foveatedScreenSpaceError = defaultValue(options.foveatedScreenSpaceError, true);
this._foveatedConeSize = defaultValue(options.foveatedConeSize, 0.1);
this._foveatedMinimumScreenSpaceErrorRelaxation = defaultValue(options.foveatedMinimumScreenSpaceErrorRelaxation, 0.0);
/**
* Gets a function that will update the foveated screen space error for a tile.
*
* @type {Cesium3DTileset~foveatedInterpolationCallback} A callback to control how much to raise the screen space error for tiles outside the foveated cone, interpolating between {@link Cesium3DTileset#foveatedMinimumScreenSpaceErrorRelaxation} and {@link Cesium3DTileset#maximumScreenSpaceError}.
*/
this.foveatedInterpolationCallback = defaultValue(options.foveatedInterpolationCallback, CesiumMath.lerp);
/**
* Optimization option. Used when {@link Cesium3DTileset#foveatedScreenSpaceError} is true to control
* how long in seconds to wait after the camera stops moving before deferred tiles start loading in.
* This time delay prevents requesting tiles around the edges of the screen when the camera is moving.
* Setting this to 0.0 will immediately request all tiles in any given view.
*
* @type {Number}
* @default 0.2
*/
this.foveatedTimeDelay = defaultValue(options.foveatedTimeDelay, 0.2);
/**
* A scalar that determines the density used to adjust the dynamic screen space error, similar to {@link Fog}. Increasing this
* value has the effect of increasing the maximum screen space error for all tiles, but in a non-linear fashion.
* The error starts at 0.0 and increases exponentially until a midpoint is reached, and then approaches 1.0 asymptotically.
* This has the effect of keeping high detail in the closer tiles and lower detail in the further tiles, with all tiles
* beyond a certain distance all roughly having an error of 1.0.
* <p>
* The dynamic error is in the range [0.0, 1.0) and is multiplied by <code>dynamicScreenSpaceErrorFactor</code> to produce the
* final dynamic error. This dynamic error is then subtracted from the tile's actual screen space error.
* </p>
* <p>
* Increasing <code>dynamicScreenSpaceErrorDensity</code> has the effect of moving the error midpoint closer to the camera.
* It is analogous to moving fog closer to the camera.
* </p>
*
* @type {Number}
* @default 0.00278
*/
this.dynamicScreenSpaceErrorDensity = 0.00278;
/**
* A factor used to increase the screen space error of tiles for dynamic screen space error. As this value increases less tiles
* are requested for rendering and tiles in the distance will have lower detail. If set to zero, the feature will be disabled.
*
* @type {Number}
* @default 4.0
*/
this.dynamicScreenSpaceErrorFactor = 4.0;
/**
* A ratio of the tileset's height at which the density starts to falloff. If the camera is below this height the
* full computed density is applied, otherwise the density falls off. This has the effect of higher density at
* street level views.
* <p>
* Valid values are between 0.0 and 1.0.
* </p>
*
* @type {Number}
* @default 0.25
*/
this.dynamicScreenSpaceErrorHeightFalloff = 0.25;
this._dynamicScreenSpaceErrorComputedDensity = 0.0; // Updated based on the camera position and direction
/**
* Determines whether the tileset casts or receives shadows from light sources.
* <p>
* Enabling shadows has a performance impact. A tileset that casts shadows must be rendered twice, once from the camera and again from the light's point of view.
* </p>
* <p>
* Shadows are rendered only when {@link Viewer#shadows} is <code>true</code>.
* </p>
*
* @type {ShadowMode}
* @default ShadowMode.ENABLED
*/
this.shadows = defaultValue(options.shadows, ShadowMode.ENABLED);
/**
* Determines if the tileset will be shown.
*
* @type {Boolean}
* @default true
*/
this.show = defaultValue(options.show, true);
/**
* Defines how per-feature colors set from the Cesium API or declarative styling blend with the source colors from
* the original feature, e.g. glTF material or per-point color in the tile.
*
* @type {Cesium3DTileColorBlendMode}
* @default Cesium3DTileColorBlendMode.HIGHLIGHT
*/
this.colorBlendMode = Cesium3DTileColorBlendMode.HIGHLIGHT;
/**
* Defines the value used to linearly interpolate between the source color and feature color when the {@link Cesium3DTileset#colorBlendMode} is <code>MIX</code>.
* A value of 0.0 results in the source color while a value of 1.0 results in the feature color, with any value in-between
* resulting in a mix of the source color and feature color.
*
* @type {Number}
* @default 0.5
*/
this.colorBlendAmount = 0.5;
/**
* Options for controlling point size based on geometric error and eye dome lighting.
* @type {PointCloudShading}
*/
this.pointCloudShading = new PointCloudShading(options.pointCloudShading);
this._pointCloudEyeDomeLighting = new PointCloudEyeDomeLighting();
/**
* The event fired to indicate progress of loading new tiles. This event is fired when a new tile
* is requested, when a requested tile is finished downloading, and when a downloaded tile has been
* processed and is ready to render.
* <p>
* The number of pending tile requests, <code>numberOfPendingRequests</code>, and number of tiles
* processing, <code>numberOfTilesProcessing</code> are passed to the event listener.
* </p>
* <p>
* This event is fired at the end of the frame after the scene is rendered.
* </p>
*
* @type {Event}
* @default new Event()
*
* @example
* tileset.loadProgress.addEventListener(function(numberOfPendingRequests, numberOfTilesProcessing) {
* if ((numberOfPendingRequests === 0) && (numberOfTilesProcessing === 0)) {
* console.log('Stopped loading');
* return;
* }
*
* console.log('Loading: requests: ' + numberOfPendingRequests + ', processing: ' + numberOfTilesProcessing);
* });
*/
this.loadProgress = new Event();
/**
* The event fired to indicate that all tiles that meet the screen space error this frame are loaded. The tileset
* is completely loaded for this view.
* <p>
* This event is fired at the end of the frame after the scene is rendered.
* </p>
*
* @type {Event}
* @default new Event()
*
* @example
* tileset.allTilesLoaded.addEventListener(function() {
* console.log('All tiles are loaded');
* });
*
* @see Cesium3DTileset#tilesLoaded
*/
this.allTilesLoaded = new Event();
/**
* The event fired to indicate that all tiles that meet the screen space error this frame are loaded. This event
* is fired once when all tiles in the initial view are loaded.
* <p>
* This event is fired at the end of the frame after the scene is rendered.
* </p>
*
* @type {Event}
* @default new Event()
*
* @example
* tileset.initialTilesLoaded.addEventListener(function() {
* console.log('Initial tiles are loaded');
* });
*
* @see Cesium3DTileset#allTilesLoaded
*/
this.initialTilesLoaded = new Event();
/**
* The event fired to indicate that a tile's content was loaded.
* <p>
* The loaded {@link Cesium3DTile} is passed to the event listener.
* </p>
* <p>
* This event is fired during the tileset traversal while the frame is being rendered
* so that updates to the tile take effect in the same frame. Do not create or modify
* Cesium entities or primitives during the event listener.
* </p>
*
* @type {Event}
* @default new Event()
*
* @example
* tileset.tileLoad.addEventListener(function(tile) {
* console.log('A tile was loaded.');
* });
*/
this.tileLoad = new Event();
/**
* The event fired to indicate that a tile's content was unloaded.
* <p>
* The unloaded {@link Cesium3DTile} is passed to the event listener.
* </p>
* <p>
* This event is fired immediately before the tile's content is unloaded while the frame is being
* rendered so that the event listener has access to the tile's content. Do not create
* or modify Cesium entities or primitives during the event listener.
* </p>
*
* @type {Event}
* @default new Event()
*
* @example
* tileset.tileUnload.addEventListener(function(tile) {
* console.log('A tile was unloaded from the cache.');
* });
*
* @see Cesium3DTileset#maximumMemoryUsage
* @see Cesium3DTileset#trimLoadedTiles
*/
this.tileUnload = new Event();
/**
* The event fired to indicate that a tile's content failed to load.
* <p>
* If there are no event listeners, error messages will be logged to the console.
* </p>
* <p>
* The error object passed to the listener contains two properties:
* <ul>
* <li><code>url</code>: the url of the failed tile.</li>
* <li><code>message</code>: the error message.</li>
* </ul>
*
* @type {Event}
* @default new Event()
*
* @example
* tileset.tileFailed.addEventListener(function(error) {
* console.log('An error occurred loading tile: ' + error.url);
* console.log('Error: ' + error.message);
* });
*/
this.tileFailed = new Event();
/**
* This event fires once for each visible tile in a frame. This can be used to manually
* style a tileset.
* <p>
* The visible {@link Cesium3DTile} is passed to the event listener.
* </p>
* <p>
* This event is fired during the tileset traversal while the frame is being rendered
* so that updates to the tile take effect in the same frame. Do not create or modify
* Cesium entities or primitives during the event listener.
* </p>
*
* @type {Event}
* @default new Event()
*
* @example
* tileset.tileVisible.addEventListener(function(tile) {
* if (tile.content instanceof Cesium.Batched3DModel3DTileContent) {
* console.log('A Batched 3D Model tile is visible.');
* }
* });
*
* @example
* // Apply a red style and then manually set random colors for every other feature when the tile becomes visible.
* tileset.style = new Cesium.Cesium3DTileStyle({
* color : 'color("red")'
* });
* tileset.tileVisible.addEventListener(function(tile) {
* var content = tile.content;
* var featuresLength = content.featuresLength;
* for (var i = 0; i < featuresLength; i+=2) {
* content.getFeature(i).color = Cesium.Color.fromRandom();
* }
* });
*/
this.tileVisible = new Event();
/**
* Optimization option. Determines if level of detail skipping should be applied during the traversal.
* <p>
* The common strategy for replacement-refinement traversal is to store all levels of the tree in memory and require
* all children to be loaded before the parent can refine. With this optimization levels of the tree can be skipped
* entirely and children can be rendered alongside their parents. The tileset requires significantly less memory when
* using this optimization.
* </p>
*
* @type {Boolean}
* @default true
*/
this.skipLevelOfDetail = defaultValue(options.skipLevelOfDetail, false);
this._skipLevelOfDetail = this.skipLevelOfDetail;
this._disableSkipLevelOfDetail = false;
/**
* The screen space error that must be reached before skipping levels of detail.
* <p>
* Only used when {@link Cesium3DTileset#skipLevelOfDetail} is <code>true</code>.
* </p>
*
* @type {Number}
* @default 1024
*/
this.baseScreenSpaceError = defaultValue(options.baseScreenSpaceError, 1024);
/**
* Multiplier defining the minimum screen space error to skip.
* For example, if a tile has screen space error of 100, no tiles will be loaded unless they
* are leaves or have a screen space error <code><= 100 / skipScreenSpaceErrorFactor</code>.
* <p>
* Only used when {@link Cesium3DTileset#skipLevelOfDetail} is <code>true</code>.
* </p>
*
* @type {Number}
* @default 16
*/
this.skipScreenSpaceErrorFactor = defaultValue(options.skipScreenSpaceErrorFactor, 16);
/**
* Constant defining the minimum number of levels to skip when loading tiles. When it is 0, no levels are skipped.
* For example, if a tile is level 1, no tiles will be loaded unless they are at level greater than 2.
* <p>
* Only used when {@link Cesium3DTileset#skipLevelOfDetail} is <code>true</code>.
* </p>
*
* @type {Number}
* @default 1
*/
this.skipLevels = defaultValue(options.skipLevels, 1);
/**
* When true, only tiles that meet the maximum screen space error will ever be downloaded.
* Skipping factors are ignored and just the desired tiles are loaded.
* <p>
* Only used when {@link Cesium3DTileset#skipLevelOfDetail} is <code>true</code>.
* </p>
*
* @type {Boolean}
* @default false
*/
this.immediatelyLoadDesiredLevelOfDetail = defaultValue(options.immediatelyLoadDesiredLevelOfDetail, false);
/**
* Determines whether siblings of visible tiles are always downloaded during traversal.
* This may be useful for ensuring that tiles are already available when the viewer turns left/right.
* <p>
* Only used when {@link Cesium3DTileset#skipLevelOfDetail} is <code>true</code>.
* </p>
*
* @type {Boolean}
* @default false
*/
this.loadSiblings = defaultValue(options.loadSiblings, false);
this._clippingPlanes = undefined;
this.clippingPlanes = options.clippingPlanes;
this._imageBasedLightingFactor = new Cartesian2(1.0, 1.0);
Cartesian2.clone(options.imageBasedLightingFactor, this._imageBasedLightingFactor);
/**
* The light color when shading models. When <code>undefined</code> the scene's light color is used instead.
* <p>
* For example, disabling additional light sources by setting <code>model.imageBasedLightingFactor = new Cartesian2(0.0, 0.0)</code> will make the
* model much darker. Here, increasing the intensity of the light source will make the model brighter.
* </p>
*
* @type {Cartesian3}
* @default undefined
*/
this.lightColor = options.lightColor;
/**
* The sun's luminance at the zenith in kilo candela per meter squared to use for this model's procedural environment map.
* This is used when {@link Cesium3DTileset#specularEnvironmentMaps} and {@link Cesium3DTileset#sphericalHarmonicCoefficients} are not defined.
*
* @type Number
*
* @default 0.2
*
*/
this.luminanceAtZenith = defaultValue(options.luminanceAtZenith, 0.2);
/**
* The third order spherical harmonic coefficients used for the diffuse color of image-based lighting. When <code>undefined</code>, a diffuse irradiance
* computed from the atmosphere color is used.
* <p>
* There are nine <code>Cartesian3</code> coefficients.
* The order of the coefficients is: L<sub>00</sub>, L<sub>1-1</sub>, L<sub>10</sub>, L<sub>11</sub>, L<sub>2-2</sub>, L<sub>2-1</sub>, L<sub>20</sub>, L<sub>21</sub>, L<sub>22</sub>
* </p>
*
* These values can be obtained by preprocessing the environment map using the <code>cmgen</code> tool of
* {@link https://github.com/google/filament/releases|Google's Filament project}. This will also generate a KTX file that can be
* supplied to {@link Cesium3DTileset#specularEnvironmentMaps}.
*
* @type {Cartesian3[]}
* @demo {@link https://sandcastle.cesium.com/index.html?src=Image-Based Lighting.html|Sandcastle Image Based Lighting Demo}
* @see {@link https://graphics.stanford.edu/papers/envmap/envmap.pdf|An Efficient Representation for Irradiance Environment Maps}
*/
this.sphericalHarmonicCoefficients = options.sphericalHarmonicCoefficients;
/**
* A URL to a KTX file that contains a cube map of the specular lighting and the convoluted specular mipmaps.
*
* @demo {@link https://sandcastle.cesium.com/index.html?src=Image-Based Lighting.html|Sandcastle Image Based Lighting Demo}
* @type {String}
* @see Cesium3DTileset#sphericalHarmonicCoefficients
*/
this.specularEnvironmentMaps = options.specularEnvironmentMaps;
/**
* This property is for debugging only; it is not optimized for production use.
* <p>
* Determines if only the tiles from last frame should be used for rendering. This
* effectively "freezes" the tileset to the previous frame so it is possible to zoom
* out and see what was rendered.
* </p>
*
* @type {Boolean}
* @default false
*/
this.debugFreezeFrame = defaultValue(options.debugFreezeFrame, false);
/**
* This property is for debugging only; it is not optimized for production use.
* <p>
* When true, assigns a random color to each tile. This is useful for visualizing
* what features belong to what tiles, especially with additive refinement where features
* from parent tiles may be interleaved with features from child tiles.
* </p>
*
* @type {Boolean}
* @default false
*/
this.debugColorizeTiles = defaultValue(options.debugColorizeTiles, false);
/**
* This property is for debugging only; it is not optimized for production use.
* <p>
* When true, renders each tile's content as a wireframe.
* </p>
*
* @type {Boolean}
* @default false
*/
this.debugWireframe = defaultValue(options.debugWireframe, false);
/**
* This property is for debugging only; it is not optimized for production use.
* <p>
* When true, renders the bounding volume for each visible tile. The bounding volume is
* white if the tile has a content bounding volume or is empty; otherwise, it is red. Tiles that don't meet the
* screen space error and are still refining to their descendants are yellow.
* </p>
*
* @type {Boolean}
* @default false
*/
this.debugShowBoundingVolume = defaultValue(options.debugShowBoundingVolume, false);
/**
* This property is for debugging only; it is not optimized for production use.
* <p>
* When true, renders the bounding volume for each visible tile's content. The bounding volume is
* blue if the tile has a content bounding volume; otherwise it is red.
* </p>
*
* @type {Boolean}
* @default false
*/
this.debugShowContentBoundingVolume = defaultValue(options.debugShowContentBoundingVolume, false);
/**
* This property is for debugging only; it is not optimized for production use.
* <p>
* When true, renders the viewer request volume for each tile.
* </p>
*
* @type {Boolean}
* @default false
*/
this.debugShowViewerRequestVolume = defaultValue(options.debugShowViewerRequestVolume, false);
this._tileDebugLabels = undefined;
this.debugPickedTileLabelOnly = false;
this.debugPickedTile = undefined;
this.debugPickPosition = undefined;
/**
* This property is for debugging only; it is not optimized for production use.
* <p>
* When true, draws labels to indicate the geometric error of each tile.
* </p>
*
* @type {Boolean}
* @default false
*/
this.debugShowGeometricError = defaultValue(options.debugShowGeometricError, false);
/**
* This property is for debugging only; it is not optimized for production use.
* <p>
* When true, draws labels to indicate the number of commands, points, triangles and features of each tile.
* </p>
*
* @type {Boolean}
* @default false
*/
this.debugShowRenderingStatistics = defaultValue(options.debugShowRenderingStatistics, false);
/**
* This property is for debugging only; it is not optimized for production use.
* <p>
* When true, draws labels to indicate the geometry and texture memory usage of each tile.
* </p>
*
* @type {Boolean}
* @default false
*/
this.debugShowMemoryUsage = defaultValue(options.debugShowMemoryUsage, false);
/**
* This property is for debugging only; it is not optimized for production use.
* <p>
* When true, draws labels to indicate the url of each tile.
* </p>
*
* @type {Boolean}
* @default false
*/
this.debugShowUrl = defaultValue(options.debugShowUrl, false);
var that = this;
var resource;
when(options.url)
.then(function(url) {
var basePath;
resource = Resource.createIfNeeded(url);
// ion resources have a credits property we can use for additional attribution.
that._credits = resource.credits;
if (resource.extension === 'json') {
basePath = resource.getBaseUri(true);
} else if (resource.isDataUri) {
basePath = '';
}
that._url = resource.url;
that._basePath = basePath;
return Cesium3DTileset.loadJson(resource);
})
.then(function(tilesetJson) {
that._root = that.loadTileset(resource, tilesetJson);
var gltfUpAxis = defined(tilesetJson.asset.gltfUpAxis) ? Axis.fromName(tilesetJson.asset.gltfUpAxis) : Axis.Y;
var asset = tilesetJson.asset;
that._asset = asset;
that._properties = tilesetJson.properties;
that._geometricError = tilesetJson.geometricError;
that._extensionsUsed = tilesetJson.extensionsUsed;
that._gltfUpAxis = gltfUpAxis;
that._extras = tilesetJson.extras;
var extras = asset.extras;
if (defined(extras) && defined(extras.cesium) && defined(extras.cesium.credits)) {
var extraCredits = extras.cesium.credits;
var credits = that._credits;
if (!defined(credits)) {
credits = [];
that._credits = credits;
}
for (var i = 0; i < extraCredits.length; ++i) {
var credit = extraCredits[i];
credits.push(new Credit(credit.html, credit.showOnScreen));
}
}
// Save the original, untransformed bounding volume position so we can apply
// the tile transform and model matrix at run time
var boundingVolume = that._root.createBoundingVolume(tilesetJson.root.boundingVolume, Matrix4.IDENTITY);
var clippingPlanesOrigin = boundingVolume.boundingSphere.center;
// If this origin is above the surface of the earth
// we want to apply an ENU orientation as our best guess of orientation.
// Otherwise, we assume it gets its position/orientation completely from the
// root tile transform and the tileset's model matrix
var originCartographic = that._ellipsoid.cartesianToCartographic(clippingPlanesOrigin);
if (defined(originCartographic) && (originCartographic.height > ApproximateTerrainHeights._defaultMinTerrainHeight)) {
that._initialClippingPlanesOriginMatrix = Transforms.eastNorthUpToFixedFrame(clippingPlanesOrigin);
}
that._clippingPlanesOriginMatrix = Matrix4.clone(that._initialClippingPlanesOriginMatrix);
that._readyPromise.resolve(that);
}).otherwise(function(error) {
that._readyPromise.reject(error);
});
}
Object.defineProperties(Cesium3DTileset.prototype, {
/**
* NOTE: This getter exists so that `Picking.js` can differentiate between
* PrimitiveCollection and Cesium3DTileset objects without inflating
* the size of the module via `instanceof Cesium3DTileset`
* @private
*/
isCesium3DTileset : {
get : function() {
return true;
}
},
/**
* Gets the tileset's asset object property, which contains metadata about the tileset.
* <p>
* See the {@link https://github.com/CesiumGS/3d-tiles/tree/master/specification#reference-asset|asset schema reference}
* in the 3D Tiles spec for the full set of properties.
* </p>
*
* @memberof Cesium3DTileset.prototype
*
* @type {Object}
* @readonly
*
* @exception {DeveloperError} The tileset is not loaded. Use Cesium3DTileset.readyPromise or wait for Cesium3DTileset.ready to be true.
*/
asset : {
get : function() {
//>>includeStart('debug', pragmas.debug);
if (!this.ready) {
throw new DeveloperError('The tileset is not loaded. Use Cesium3DTileset.readyPromise or wait for Cesium3DTileset.ready to be true.');
}
//>>includeEnd('debug');
return this._asset;
}
},
/**
* The {@link ClippingPlaneCollection} used to selectively disable rendering the tileset.
*
* @memberof Cesium3DTileset.prototype
*
* @type {ClippingPlaneCollection}
*/
clippingPlanes : {
get : function() {
return this._clippingPlanes;
},
set : function(value) {
ClippingPlaneCollection.setOwner(value, this, '_clippingPlanes');
}
},
/**
* Gets the tileset's properties dictionary object, which contains metadata about per-feature properties.
* <p>
* See the {@link https://github.com/CesiumGS/3d-tiles/tree/master/specification#reference-properties|properties schema reference}
* in the 3D Tiles spec for the full set of properties.
* </p>
*
* @memberof Cesium3DTileset.prototype
*
* @type {Object}
* @readonly
*
* @exception {DeveloperError} The tileset is not loaded. Use Cesium3DTileset.readyPromise or wait for Cesium3DTileset.ready to be true.
*
* @example
* console.log('Maximum building height: ' + tileset.properties.height.maximum);
* console.log('Minimum building height: ' + tileset.properties.height.minimum);
*
* @see Cesium3DTileFeature