UNPKG

cesium

Version:

CesiumJS is a JavaScript library for creating 3D globes and 2D maps in a web browser without a plugin.

1,712 lines (1,566 loc) 142 kB
import BoundingRectangle from "../Core/BoundingRectangle.js"; import BoundingSphere from "../Core/BoundingSphere.js"; import BoxGeometry from "../Core/BoxGeometry.js"; import Cartesian3 from "../Core/Cartesian3.js"; import Cartographic from "../Core/Cartographic.js"; import clone from "../Core/clone.js"; import Color from "../Core/Color.js"; import ColorGeometryInstanceAttribute from "../Core/ColorGeometryInstanceAttribute.js"; import createGuid from "../Core/createGuid.js"; import CullingVolume from "../Core/CullingVolume.js"; import defaultValue from "../Core/defaultValue.js"; import defined from "../Core/defined.js"; import destroyObject from "../Core/destroyObject.js"; import DeveloperError from "../Core/DeveloperError.js"; import EllipsoidGeometry from "../Core/EllipsoidGeometry.js"; import Event from "../Core/Event.js"; import GeographicProjection from "../Core/GeographicProjection.js"; import GeometryInstance from "../Core/GeometryInstance.js"; import GeometryPipeline from "../Core/GeometryPipeline.js"; import Intersect from "../Core/Intersect.js"; import JulianDate from "../Core/JulianDate.js"; import CesiumMath from "../Core/Math.js"; import Matrix4 from "../Core/Matrix4.js"; import mergeSort from "../Core/mergeSort.js"; import Occluder from "../Core/Occluder.js"; import OrthographicFrustum from "../Core/OrthographicFrustum.js"; import OrthographicOffCenterFrustum from "../Core/OrthographicOffCenterFrustum.js"; import PerspectiveFrustum from "../Core/PerspectiveFrustum.js"; import PerspectiveOffCenterFrustum from "../Core/PerspectiveOffCenterFrustum.js"; import RequestScheduler from "../Core/RequestScheduler.js"; import TaskProcessor from "../Core/TaskProcessor.js"; import Transforms from "../Core/Transforms.js"; import ClearCommand from "../Renderer/ClearCommand.js"; import ComputeEngine from "../Renderer/ComputeEngine.js"; import Context from "../Renderer/Context.js"; import ContextLimits from "../Renderer/ContextLimits.js"; import Pass from "../Renderer/Pass.js"; import RenderState from "../Renderer/RenderState.js"; import BrdfLutGenerator from "./BrdfLutGenerator.js"; import Camera from "./Camera.js"; import Cesium3DTilePass from "./Cesium3DTilePass.js"; import Cesium3DTilePassState from "./Cesium3DTilePassState.js"; import CreditDisplay from "./CreditDisplay.js"; import DebugCameraPrimitive from "./DebugCameraPrimitive.js"; import DepthPlane from "./DepthPlane.js"; import DerivedCommand from "./DerivedCommand.js"; import DeviceOrientationCameraController from "./DeviceOrientationCameraController.js"; import Fog from "./Fog.js"; import FrameState from "./FrameState.js"; import GlobeDepth from "./GlobeDepth.js"; import GlobeTranslucencyState from "./GlobeTranslucencyState.js"; import InvertClassification from "./InvertClassification.js"; import JobScheduler from "./JobScheduler.js"; import MapMode2D from "./MapMode2D.js"; import OctahedralProjectedCubeMap from "./OctahedralProjectedCubeMap.js"; import PerformanceDisplay from "./PerformanceDisplay.js"; import PerInstanceColorAppearance from "./PerInstanceColorAppearance.js"; import Picking from "./Picking.js"; import PostProcessStageCollection from "./PostProcessStageCollection.js"; import Primitive from "./Primitive.js"; import PrimitiveCollection from "./PrimitiveCollection.js"; import SceneMode from "./SceneMode.js"; import SceneTransforms from "./SceneTransforms.js"; import SceneTransitioner from "./SceneTransitioner.js"; import ScreenSpaceCameraController from "./ScreenSpaceCameraController.js"; import ShadowMap from "./ShadowMap.js"; import StencilConstants from "./StencilConstants.js"; import SunLight from "./SunLight.js"; import SunPostProcess from "./SunPostProcess.js"; import TweenCollection from "./TweenCollection.js"; import View from "./View.js"; import DebugInspector from "./DebugInspector.js"; var requestRenderAfterFrame = function (scene) { return function () { scene.frameState.afterRender.push(function () { scene.requestRender(); }); }; }; /** * The container for all 3D graphical objects and state in a Cesium virtual scene. Generally, * a scene is not created directly; instead, it is implicitly created by {@link CesiumWidget}. * <p> * <em><code>contextOptions</code> parameter details:</em> * </p> * <p> * The default values are: * <code> * { * webgl : { * alpha : false, * depth : true, * stencil : false, * antialias : true, * powerPreference: 'high-performance', * premultipliedAlpha : true, * preserveDrawingBuffer : false, * failIfMajorPerformanceCaveat : false * }, * allowTextureFilterAnisotropic : true * } * </code> * </p> * <p> * The <code>webgl</code> property corresponds to the {@link http://www.khronos.org/registry/webgl/specs/latest/#5.2|WebGLContextAttributes} * object used to create the WebGL context. * </p> * <p> * <code>webgl.alpha</code> defaults to false, which can improve performance compared to the standard WebGL default * of true. If an application needs to composite Cesium above other HTML elements using alpha-blending, set * <code>webgl.alpha</code> to true. * </p> * <p> * The other <code>webgl</code> properties match the WebGL defaults for {@link http://www.khronos.org/registry/webgl/specs/latest/#5.2|WebGLContextAttributes}. * </p> * <p> * <code>allowTextureFilterAnisotropic</code> defaults to true, which enables anisotropic texture filtering when the * WebGL extension is supported. Setting this to false will improve performance, but hurt visual quality, especially for horizon views. * </p> * * @alias Scene * @constructor * * @param {Object} [options] Object with the following properties: * @param {HTMLCanvasElement} options.canvas The HTML canvas element to create the scene for. * @param {Object} [options.contextOptions] Context and WebGL creation properties. See details above. * @param {Element} [options.creditContainer] The HTML element in which the credits will be displayed. * @param {Element} [options.creditViewport] The HTML element in which to display the credit popup. If not specified, the viewport will be a added as a sibling of the canvas. * @param {MapProjection} [options.mapProjection=new GeographicProjection()] The map projection to use in 2D and Columbus View modes. * @param {Boolean} [options.orderIndependentTranslucency=true] If true and the configuration supports it, use order independent translucency. * @param {Boolean} [options.scene3DOnly=false] If true, optimizes memory use and performance for 3D mode but disables the ability to use 2D or Columbus View. * @param {Number} [options.terrainExaggeration=1.0] A scalar used to exaggerate the terrain. Note that terrain exaggeration will not modify any other primitive as they are positioned relative to the ellipsoid. * @param {Boolean} [options.shadows=false] Determines if shadows are cast by light sources. * @param {MapMode2D} [options.mapMode2D=MapMode2D.INFINITE_SCROLL] Determines if the 2D map is rotatable or can be scrolled infinitely in the horizontal direction. * @param {Boolean} [options.requestRenderMode=false] If true, rendering a frame will only occur when needed as determined by changes within the scene. Enabling improves performance of the application, but requires using {@link Scene#requestRender} to render a new frame explicitly in this mode. This will be necessary in many cases after making changes to the scene in other parts of the API. See {@link https://cesium.com/blog/2018/01/24/cesium-scene-rendering-performance/|Improving Performance with Explicit Rendering}. * @param {Number} [options.maximumRenderTimeChange=0.0] If requestRenderMode is true, this value defines the maximum change in simulation time allowed before a render is requested. See {@link https://cesium.com/blog/2018/01/24/cesium-scene-rendering-performance/|Improving Performance with Explicit Rendering}. * * @see CesiumWidget * @see {@link http://www.khronos.org/registry/webgl/specs/latest/#5.2|WebGLContextAttributes} * * @exception {DeveloperError} options and options.canvas are required. * * @example * // Create scene without anisotropic texture filtering * var scene = new Cesium.Scene({ * canvas : canvas, * contextOptions : { * allowTextureFilterAnisotropic : false * } * }); */ function Scene(options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); var canvas = options.canvas; var creditContainer = options.creditContainer; var creditViewport = options.creditViewport; var contextOptions = clone(options.contextOptions); if (!defined(contextOptions)) { contextOptions = {}; } if (!defined(contextOptions.webgl)) { contextOptions.webgl = {}; } contextOptions.webgl.powerPreference = defaultValue( contextOptions.webgl.powerPreference, "high-performance" ); //>>includeStart('debug', pragmas.debug); if (!defined(canvas)) { throw new DeveloperError("options and options.canvas are required."); } //>>includeEnd('debug'); var hasCreditContainer = defined(creditContainer); var context = new Context(canvas, contextOptions); if (!hasCreditContainer) { creditContainer = document.createElement("div"); creditContainer.style.position = "absolute"; creditContainer.style.bottom = "0"; creditContainer.style["text-shadow"] = "0 0 2px #000000"; creditContainer.style.color = "#ffffff"; creditContainer.style["font-size"] = "10px"; creditContainer.style["padding-right"] = "5px"; canvas.parentNode.appendChild(creditContainer); } if (!defined(creditViewport)) { creditViewport = canvas.parentNode; } this._id = createGuid(); this._jobScheduler = new JobScheduler(); this._frameState = new FrameState( context, new CreditDisplay(creditContainer, " • ", creditViewport), this._jobScheduler ); this._frameState.scene3DOnly = defaultValue(options.scene3DOnly, false); this._removeCreditContainer = !hasCreditContainer; this._creditContainer = creditContainer; this._canvas = canvas; this._context = context; this._computeEngine = new ComputeEngine(context); this._globe = undefined; this._globeTranslucencyState = new GlobeTranslucencyState(); this._primitives = new PrimitiveCollection(); this._groundPrimitives = new PrimitiveCollection(); this._globeHeight = undefined; this._cameraUnderground = false; this._logDepthBuffer = context.fragmentDepth; this._logDepthBufferDirty = true; this._tweens = new TweenCollection(); this._shaderFrameCount = 0; this._sunPostProcess = undefined; this._computeCommandList = []; this._overlayCommandList = []; this._useOIT = defaultValue(options.orderIndependentTranslucency, true); this._executeOITFunction = undefined; this._depthPlane = new DepthPlane(); this._clearColorCommand = new ClearCommand({ color: new Color(), stencil: 0, owner: this, }); this._depthClearCommand = new ClearCommand({ depth: 1.0, owner: this, }); this._stencilClearCommand = new ClearCommand({ stencil: 0, }); this._classificationStencilClearCommand = new ClearCommand({ stencil: 0, renderState: RenderState.fromCache({ stencilMask: StencilConstants.CLASSIFICATION_MASK, }), }); this._depthOnlyRenderStateCache = {}; this._transitioner = new SceneTransitioner(this); this._preUpdate = new Event(); this._postUpdate = new Event(); this._renderError = new Event(); this._preRender = new Event(); this._postRender = new Event(); this._minimumDisableDepthTestDistance = 0.0; this._debugInspector = new DebugInspector(); /** * Exceptions occurring in <code>render</code> are always caught in order to raise the * <code>renderError</code> event. If this property is true, the error is rethrown * after the event is raised. If this property is false, the <code>render</code> function * returns normally after raising the event. * * @type {Boolean} * @default false */ this.rethrowRenderErrors = false; /** * Determines whether or not to instantly complete the * scene transition animation on user input. * * @type {Boolean} * @default true */ this.completeMorphOnUserInput = true; /** * The event fired at the beginning of a scene transition. * @type {Event} * @default Event() */ this.morphStart = new Event(); /** * The event fired at the completion of a scene transition. * @type {Event} * @default Event() */ this.morphComplete = new Event(); /** * The {@link SkyBox} used to draw the stars. * * @type {SkyBox} * @default undefined * * @see Scene#backgroundColor */ this.skyBox = undefined; /** * The sky atmosphere drawn around the globe. * * @type {SkyAtmosphere} * @default undefined */ this.skyAtmosphere = undefined; /** * The {@link Sun}. * * @type {Sun} * @default undefined */ this.sun = undefined; /** * Uses a bloom filter on the sun when enabled. * * @type {Boolean} * @default true */ this.sunBloom = true; this._sunBloom = undefined; /** * The {@link Moon} * * @type Moon * @default undefined */ this.moon = undefined; /** * The background color, which is only visible if there is no sky box, i.e., {@link Scene#skyBox} is undefined. * * @type {Color} * @default {@link Color.BLACK} * * @see Scene#skyBox */ this.backgroundColor = Color.clone(Color.BLACK); this._mode = SceneMode.SCENE3D; this._mapProjection = defined(options.mapProjection) ? options.mapProjection : new GeographicProjection(); /** * The current morph transition time between 2D/Columbus View and 3D, * with 0.0 being 2D or Columbus View and 1.0 being 3D. * * @type {Number} * @default 1.0 */ this.morphTime = 1.0; /** * The far-to-near ratio of the multi-frustum when using a normal depth buffer. * <p> * This value is used to create the near and far values for each frustum of the multi-frustum. It is only used * when {@link Scene#logarithmicDepthBuffer} is <code>false</code>. When <code>logarithmicDepthBuffer</code> is * <code>true</code>, use {@link Scene#logarithmicDepthFarToNearRatio}. * </p> * * @type {Number} * @default 1000.0 */ this.farToNearRatio = 1000.0; /** * The far-to-near ratio of the multi-frustum when using a logarithmic depth buffer. * <p> * This value is used to create the near and far values for each frustum of the multi-frustum. It is only used * when {@link Scene#logarithmicDepthBuffer} is <code>true</code>. When <code>logarithmicDepthBuffer</code> is * <code>false</code>, use {@link Scene#farToNearRatio}. * </p> * * @type {Number} * @default 1e9 */ this.logarithmicDepthFarToNearRatio = 1e9; /** * Determines the uniform depth size in meters of each frustum of the multifrustum in 2D. If a primitive or model close * to the surface shows z-fighting, decreasing this will eliminate the artifact, but decrease performance. On the * other hand, increasing this will increase performance but may cause z-fighting among primitives close to the surface. * * @type {Number} * @default 1.75e6 */ this.nearToFarDistance2D = 1.75e6; /** * This property is for debugging only; it is not for production use. * <p> * A function that determines what commands are executed. As shown in the examples below, * the function receives the command's <code>owner</code> as an argument, and returns a boolean indicating if the * command should be executed. * </p> * <p> * The default is <code>undefined</code>, indicating that all commands are executed. * </p> * * @type Function * * @default undefined * * @example * // Do not execute any commands. * scene.debugCommandFilter = function(command) { * return false; * }; * * // Execute only the billboard's commands. That is, only draw the billboard. * var billboards = new Cesium.BillboardCollection(); * scene.debugCommandFilter = function(command) { * return command.owner === billboards; * }; */ this.debugCommandFilter = undefined; /** * This property is for debugging only; it is not for production use. * <p> * When <code>true</code>, commands are randomly shaded. This is useful * for performance analysis to see what parts of a scene or model are * command-dense and could benefit from batching. * </p> * * @type Boolean * * @default false */ this.debugShowCommands = false; /** * This property is for debugging only; it is not for production use. * <p> * When <code>true</code>, commands are shaded based on the frustums they * overlap. Commands in the closest frustum are tinted red, commands in * the next closest are green, and commands in the farthest frustum are * blue. If a command overlaps more than one frustum, the color components * are combined, e.g., a command overlapping the first two frustums is tinted * yellow. * </p> * * @type Boolean * * @default false */ this.debugShowFrustums = false; /** * This property is for debugging only; it is not for production use. * <p> * Displays frames per second and time between frames. * </p> * * @type Boolean * * @default false */ this.debugShowFramesPerSecond = false; /** * This property is for debugging only; it is not for production use. * <p> * Displays depth information for the indicated frustum. * </p> * * @type Boolean * * @default false */ this.debugShowGlobeDepth = false; /** * This property is for debugging only; it is not for production use. * <p> * Indicates which frustum will have depth information displayed. * </p> * * @type Number * * @default 1 */ this.debugShowDepthFrustum = 1; /** * This property is for debugging only; it is not for production use. * <p> * When <code>true</code>, draws outlines to show the boundaries of the camera frustums * </p> * * @type Boolean * * @default false */ this.debugShowFrustumPlanes = false; this._debugShowFrustumPlanes = false; this._debugFrustumPlanes = undefined; /** * When <code>true</code>, enables picking using the depth buffer. * * @type Boolean * @default true */ this.useDepthPicking = true; /** * When <code>true</code>, enables picking translucent geometry using the depth buffer. Note that {@link Scene#useDepthPicking} must also be true for enabling this to work. * * <p> * Render must be called between picks. * <br>There is a decrease in performance when enabled. There are extra draw calls to write depth for * translucent geometry. * </p> * * @example * // picking the position of a translucent primitive * viewer.screenSpaceEventHandler.setInputAction(function onLeftClick(movement) { * var pickedFeature = viewer.scene.pick(movement.position); * if (!Cesium.defined(pickedFeature)) { * // nothing picked * return; * } * viewer.scene.render(); * var worldPosition = viewer.scene.pickPosition(movement.position); * }, Cesium.ScreenSpaceEventType.LEFT_CLICK); * * @type {Boolean} * @default false */ this.pickTranslucentDepth = false; /** * The time in milliseconds to wait before checking if the camera has not moved and fire the cameraMoveEnd event. * @type {Number} * @default 500.0 * @private */ this.cameraEventWaitTime = 500.0; /** * Blends the atmosphere to geometry far from the camera for horizon views. Allows for additional * performance improvements by rendering less geometry and dispatching less terrain requests. * @type {Fog} */ this.fog = new Fog(); this._shadowMapCamera = new Camera(this); /** * The shadow map for the scene's light source. When enabled, models, primitives, and the globe may cast and receive shadows. * @type {ShadowMap} */ this.shadowMap = new ShadowMap({ context: context, lightCamera: this._shadowMapCamera, enabled: defaultValue(options.shadows, false), }); /** * When <code>false</code>, 3D Tiles will render normally. When <code>true</code>, classified 3D Tile geometry will render normally and * unclassified 3D Tile geometry will render with the color multiplied by {@link Scene#invertClassificationColor}. * @type {Boolean} * @default false */ this.invertClassification = false; /** * The highlight color of unclassified 3D Tile geometry when {@link Scene#invertClassification} is <code>true</code>. * <p>When the color's alpha is less than 1.0, the unclassified portions of the 3D Tiles will not blend correctly with the classified positions of the 3D Tiles.</p> * <p>Also, when the color's alpha is less than 1.0, the WEBGL_depth_texture and EXT_frag_depth WebGL extensions must be supported.</p> * @type {Color} * @default Color.WHITE */ this.invertClassificationColor = Color.clone(Color.WHITE); this._actualInvertClassificationColor = Color.clone( this._invertClassificationColor ); this._invertClassification = new InvertClassification(); /** * The focal length for use when with cardboard or WebVR. * @type {Number} */ this.focalLength = undefined; /** * The eye separation distance in meters for use with cardboard or WebVR. * @type {Number} */ this.eyeSeparation = undefined; /** * Post processing effects applied to the final render. * @type {PostProcessStageCollection} */ this.postProcessStages = new PostProcessStageCollection(); this._brdfLutGenerator = new BrdfLutGenerator(); this._terrainExaggeration = defaultValue(options.terrainExaggeration, 1.0); this._performanceDisplay = undefined; this._debugVolume = undefined; this._screenSpaceCameraController = new ScreenSpaceCameraController(this); this._cameraUnderground = false; this._mapMode2D = defaultValue(options.mapMode2D, MapMode2D.INFINITE_SCROLL); // Keeps track of the state of a frame. FrameState is the state across // the primitives of the scene. This state is for internally keeping track // of celestial and environment effects that need to be updated/rendered in // a certain order as well as updating/tracking framebuffer usage. this._environmentState = { skyBoxCommand: undefined, skyAtmosphereCommand: undefined, sunDrawCommand: undefined, sunComputeCommand: undefined, moonCommand: undefined, isSunVisible: false, isMoonVisible: false, isReadyForAtmosphere: false, isSkyAtmosphereVisible: false, clearGlobeDepth: false, useDepthPlane: false, renderTranslucentDepthForPick: false, originalFramebuffer: undefined, useGlobeDepthFramebuffer: false, separatePrimitiveFramebuffer: false, useOIT: false, useInvertClassification: false, usePostProcess: false, usePostProcessSelected: false, useWebVR: false, }; this._useWebVR = false; this._cameraVR = undefined; this._aspectRatioVR = undefined; /** * When <code>true</code>, rendering a frame will only occur when needed as determined by changes within the scene. * Enabling improves performance of the application, but requires using {@link Scene#requestRender} * to render a new frame explicitly in this mode. This will be necessary in many cases after making changes * to the scene in other parts of the API. * * @see {@link https://cesium.com/blog/2018/01/24/cesium-scene-rendering-performance/|Improving Performance with Explicit Rendering} * @see Scene#maximumRenderTimeChange * @see Scene#requestRender * * @type {Boolean} * @default false */ this.requestRenderMode = defaultValue(options.requestRenderMode, false); this._renderRequested = true; /** * If {@link Scene#requestRenderMode} is <code>true</code>, this value defines the maximum change in * simulation time allowed before a render is requested. Lower values increase the number of frames rendered * and higher values decrease the number of frames rendered. If <code>undefined</code>, changes to * the simulation time will never request a render. * This value impacts the rate of rendering for changes in the scene like lighting, entity property updates, * and animations. * * @see {@link https://cesium.com/blog/2018/01/24/cesium-scene-rendering-performance/|Improving Performance with Explicit Rendering} * @see Scene#requestRenderMode * * @type {Number} * @default 0.0 */ this.maximumRenderTimeChange = defaultValue( options.maximumRenderTimeChange, 0.0 ); this._lastRenderTime = undefined; this._frameRateMonitor = undefined; this._removeRequestListenerCallback = RequestScheduler.requestCompletedEvent.addEventListener( requestRenderAfterFrame(this) ); this._removeTaskProcessorListenerCallback = TaskProcessor.taskCompletedEvent.addEventListener( requestRenderAfterFrame(this) ); this._removeGlobeCallbacks = []; var viewport = new BoundingRectangle( 0, 0, context.drawingBufferWidth, context.drawingBufferHeight ); var camera = new Camera(this); if (this._logDepthBuffer) { camera.frustum.near = 0.1; camera.frustum.far = 10000000000.0; } /** * The camera view for the scene camera flight destination. Used for preloading flight destination tiles. * @type {Camera} * @private */ this.preloadFlightCamera = new Camera(this); /** * The culling volume for the scene camera flight destination. Used for preloading flight destination tiles. * @type {CullingVolume} * @private */ this.preloadFlightCullingVolume = undefined; this._picking = new Picking(this); this._defaultView = new View(this, camera, viewport); this._view = this._defaultView; this._hdr = undefined; this._hdrDirty = undefined; this.highDynamicRange = false; this.gamma = 2.2; /** * The spherical harmonic coefficients for image-based lighting of PBR models. * @type {Cartesian3[]} */ this.sphericalHarmonicCoefficients = undefined; /** * The url to the KTX file containing the specular environment map and convoluted mipmaps for image-based lighting of PBR models. * @type {String} */ this.specularEnvironmentMaps = undefined; this._specularEnvironmentMapAtlas = undefined; /** * The light source for shading. Defaults to a directional light from the Sun. * @type {Light} */ this.light = new SunLight(); // Give frameState, camera, and screen space camera controller initial state before rendering updateFrameNumber(this, 0.0, JulianDate.now()); this.updateFrameState(); this.initializeFrame(); } function updateGlobeListeners(scene, globe) { for (var i = 0; i < scene._removeGlobeCallbacks.length; ++i) { scene._removeGlobeCallbacks[i](); } scene._removeGlobeCallbacks.length = 0; var removeGlobeCallbacks = []; if (defined(globe)) { removeGlobeCallbacks.push( globe.imageryLayersUpdatedEvent.addEventListener( requestRenderAfterFrame(scene) ) ); removeGlobeCallbacks.push( globe.terrainProviderChanged.addEventListener( requestRenderAfterFrame(scene) ) ); } scene._removeGlobeCallbacks = removeGlobeCallbacks; } Object.defineProperties(Scene.prototype, { /** * Gets the canvas element to which this scene is bound. * @memberof Scene.prototype * * @type {HTMLCanvasElement} * @readonly */ canvas: { get: function () { return this._canvas; }, }, /** * The drawingBufferHeight of the underlying GL context. * @memberof Scene.prototype * * @type {Number} * @readonly * * @see {@link https://www.khronos.org/registry/webgl/specs/1.0/#DOM-WebGLRenderingContext-drawingBufferHeight|drawingBufferHeight} */ drawingBufferHeight: { get: function () { return this._context.drawingBufferHeight; }, }, /** * The drawingBufferHeight of the underlying GL context. * @memberof Scene.prototype * * @type {Number} * @readonly * * @see {@link https://www.khronos.org/registry/webgl/specs/1.0/#DOM-WebGLRenderingContext-drawingBufferHeight|drawingBufferHeight} */ drawingBufferWidth: { get: function () { return this._context.drawingBufferWidth; }, }, /** * The maximum aliased line width, in pixels, supported by this WebGL implementation. It will be at least one. * @memberof Scene.prototype * * @type {Number} * @readonly * * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>ALIASED_LINE_WIDTH_RANGE</code>. */ maximumAliasedLineWidth: { get: function () { return ContextLimits.maximumAliasedLineWidth; }, }, /** * The maximum length in pixels of one edge of a cube map, supported by this WebGL implementation. It will be at least 16. * @memberof Scene.prototype * * @type {Number} * @readonly * * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>GL_MAX_CUBE_MAP_TEXTURE_SIZE</code>. */ maximumCubeMapSize: { get: function () { return ContextLimits.maximumCubeMapSize; }, }, /** * Returns <code>true</code> if the {@link Scene#pickPosition} function is supported. * @memberof Scene.prototype * * @type {Boolean} * @readonly * * @see Scene#pickPosition */ pickPositionSupported: { get: function () { return this._context.depthTexture; }, }, /** * Returns <code>true</code> if the {@link Scene#sampleHeight} and {@link Scene#sampleHeightMostDetailed} functions are supported. * @memberof Scene.prototype * * @type {Boolean} * @readonly * * @see Scene#sampleHeight * @see Scene#sampleHeightMostDetailed */ sampleHeightSupported: { get: function () { return this._context.depthTexture; }, }, /** * Returns <code>true</code> if the {@link Scene#clampToHeight} and {@link Scene#clampToHeightMostDetailed} functions are supported. * @memberof Scene.prototype * * @type {Boolean} * @readonly * * @see Scene#clampToHeight * @see Scene#clampToHeightMostDetailed */ clampToHeightSupported: { get: function () { return this._context.depthTexture; }, }, /** * Returns <code>true</code> if the {@link Scene#invertClassification} is supported. * @memberof Scene.prototype * * @type {Boolean} * @readonly * * @see Scene#invertClassification */ invertClassificationSupported: { get: function () { return this._context.depthTexture; }, }, /** * Returns <code>true</code> if specular environment maps are supported. * @memberof Scene.prototype * * @type {Boolean} * @readonly * * @see Scene#specularEnvironmentMaps */ specularEnvironmentMapsSupported: { get: function () { return OctahedralProjectedCubeMap.isSupported(this._context); }, }, /** * Gets or sets the depth-test ellipsoid. * @memberof Scene.prototype * * @type {Globe} */ globe: { get: function () { return this._globe; }, set: function (globe) { this._globe = this._globe && this._globe.destroy(); this._globe = globe; updateGlobeListeners(this, globe); }, }, /** * Gets the collection of primitives. * @memberof Scene.prototype * * @type {PrimitiveCollection} * @readonly */ primitives: { get: function () { return this._primitives; }, }, /** * Gets the collection of ground primitives. * @memberof Scene.prototype * * @type {PrimitiveCollection} * @readonly */ groundPrimitives: { get: function () { return this._groundPrimitives; }, }, /** * Gets or sets the camera. * @memberof Scene.prototype * * @type {Camera} * @readonly */ camera: { get: function () { return this._view.camera; }, set: function (camera) { // For internal use only. Documentation is still @readonly. this._view.camera = camera; }, }, /** * Gets or sets the view. * @memberof Scene.prototype * * @type {View} * @readonly * * @private */ view: { get: function () { return this._view; }, set: function (view) { // For internal use only. Documentation is still @readonly. this._view = view; }, }, /** * Gets the default view. * @memberof Scene.prototype * * @type {View} * @readonly * * @private */ defaultView: { get: function () { return this._defaultView; }, }, /** * Gets picking functions and state * @memberof Scene.prototype * * @type {Picking} * @readonly * * @private */ picking: { get: function () { return this._picking; }, }, /** * Gets the controller for camera input handling. * @memberof Scene.prototype * * @type {ScreenSpaceCameraController} * @readonly */ screenSpaceCameraController: { get: function () { return this._screenSpaceCameraController; }, }, /** * Get the map projection to use in 2D and Columbus View modes. * @memberof Scene.prototype * * @type {MapProjection} * @readonly * * @default new GeographicProjection() */ mapProjection: { get: function () { return this._mapProjection; }, }, /** * Gets the job scheduler * @memberof Scene.prototype * @type {JobScheduler} * @readonly * * @private */ jobScheduler: { get: function () { return this._jobScheduler; }, }, /** * Gets state information about the current scene. If called outside of a primitive's <code>update</code> * function, the previous frame's state is returned. * @memberof Scene.prototype * * @type {FrameState} * @readonly * * @private */ frameState: { get: function () { return this._frameState; }, }, /** * Gets the environment state. * @memberof Scene.prototype * * @type {EnvironmentState} * @readonly * * @private */ environmentState: { get: function () { return this._environmentState; }, }, /** * Gets the collection of tweens taking place in the scene. * @memberof Scene.prototype * * @type {TweenCollection} * @readonly * * @private */ tweens: { get: function () { return this._tweens; }, }, /** * Gets the collection of image layers that will be rendered on the globe. * @memberof Scene.prototype * * @type {ImageryLayerCollection} * @readonly */ imageryLayers: { get: function () { if (!defined(this.globe)) { return undefined; } return this.globe.imageryLayers; }, }, /** * The terrain provider providing surface geometry for the globe. * @memberof Scene.prototype * * @type {TerrainProvider} */ terrainProvider: { get: function () { if (!defined(this.globe)) { return undefined; } return this.globe.terrainProvider; }, set: function (terrainProvider) { if (defined(this.globe)) { this.globe.terrainProvider = terrainProvider; } }, }, /** * Gets an event that's raised when the terrain provider is changed * @memberof Scene.prototype * * @type {Event} * @readonly */ terrainProviderChanged: { get: function () { if (!defined(this.globe)) { return undefined; } return this.globe.terrainProviderChanged; }, }, /** * Gets the event that will be raised before the scene is updated or rendered. Subscribers to the event * receive the Scene instance as the first parameter and the current time as the second parameter. * @memberof Scene.prototype * * @see {@link https://cesium.com/blog/2018/01/24/cesium-scene-rendering-performance/|Improving Performance with Explicit Rendering} * @see Scene#postUpdate * @see Scene#preRender * @see Scene#postRender * * @type {Event} * @readonly */ preUpdate: { get: function () { return this._preUpdate; }, }, /** * Gets the event that will be raised immediately after the scene is updated and before the scene is rendered. * Subscribers to the event receive the Scene instance as the first parameter and the current time as the second * parameter. * @memberof Scene.prototype * * @see {@link https://cesium.com/blog/2018/01/24/cesium-scene-rendering-performance/|Improving Performance with Explicit Rendering} * @see Scene#preUpdate * @see Scene#preRender * @see Scene#postRender * * @type {Event} * @readonly */ postUpdate: { get: function () { return this._postUpdate; }, }, /** * Gets the event that will be raised when an error is thrown inside the <code>render</code> function. * The Scene instance and the thrown error are the only two parameters passed to the event handler. * By default, errors are not rethrown after this event is raised, but that can be changed by setting * the <code>rethrowRenderErrors</code> property. * @memberof Scene.prototype * * @type {Event} * @readonly */ renderError: { get: function () { return this._renderError; }, }, /** * Gets the event that will be raised after the scene is updated and immediately before the scene is rendered. * Subscribers to the event receive the Scene instance as the first parameter and the current time as the second * parameter. * @memberof Scene.prototype * * @see {@link https://cesium.com/blog/2018/01/24/cesium-scene-rendering-performance/|Improving Performance with Explicit Rendering} * @see Scene#preUpdate * @see Scene#postUpdate * @see Scene#postRender * * @type {Event} * @readonly */ preRender: { get: function () { return this._preRender; }, }, /** * Gets the event that will be raised immediately after the scene is rendered. Subscribers to the event * receive the Scene instance as the first parameter and the current time as the second parameter. * @memberof Scene.prototype * * @see {@link https://cesium.com/blog/2018/01/24/cesium-scene-rendering-performance/|Improving Performance with Explicit Rendering} * @see Scene#preUpdate * @see Scene#postUpdate * @see Scene#postRender * * @type {Event} * @readonly */ postRender: { get: function () { return this._postRender; }, }, /** * Gets the simulation time when the scene was last rendered. Returns undefined if the scene has not yet been * rendered. * @memberof Scene.prototype * * @type {JulianDate} * @readonly */ lastRenderTime: { get: function () { return this._lastRenderTime; }, }, /** * @memberof Scene.prototype * @private * @readonly */ context: { get: function () { return this._context; }, }, /** * This property is for debugging only; it is not for production use. * <p> * When {@link Scene.debugShowFrustums} is <code>true</code>, this contains * properties with statistics about the number of command execute per frustum. * <code>totalCommands</code> is the total number of commands executed, ignoring * overlap. <code>commandsInFrustums</code> is an array with the number of times * commands are executed redundantly, e.g., how many commands overlap two or * three frustums. * </p> * * @memberof Scene.prototype * * @type {Object} * @readonly * * @default undefined */ debugFrustumStatistics: { get: function () { return this._view.debugFrustumStatistics; }, }, /** * Gets whether or not the scene is optimized for 3D only viewing. * @memberof Scene.prototype * @type {Boolean} * @readonly */ scene3DOnly: { get: function () { return this._frameState.scene3DOnly; }, }, /** * Gets whether or not the scene has order independent translucency enabled. * Note that this only reflects the original construction option, and there are * other factors that could prevent OIT from functioning on a given system configuration. * @memberof Scene.prototype * @type {Boolean} * @readonly */ orderIndependentTranslucency: { get: function () { return this._useOIT; }, }, /** * Gets the unique identifier for this scene. * @memberof Scene.prototype * @type {String} * @readonly */ id: { get: function () { return this._id; }, }, /** * Gets or sets the current mode of the scene. * @memberof Scene.prototype * @type {SceneMode} * @default {@link SceneMode.SCENE3D} */ mode: { get: function () { return this._mode; }, set: function (value) { //>>includeStart('debug', pragmas.debug); if (this.scene3DOnly && value !== SceneMode.SCENE3D) { throw new DeveloperError( "Only SceneMode.SCENE3D is valid when scene3DOnly is true." ); } //>>includeEnd('debug'); if (value === SceneMode.SCENE2D) { this.morphTo2D(0); } else if (value === SceneMode.SCENE3D) { this.morphTo3D(0); } else if (value === SceneMode.COLUMBUS_VIEW) { this.morphToColumbusView(0); //>>includeStart('debug', pragmas.debug); } else { throw new DeveloperError( "value must be a valid SceneMode enumeration." ); //>>includeEnd('debug'); } this._mode = value; }, }, /** * Gets the number of frustums used in the last frame. * @memberof Scene.prototype * @type {FrustumCommands[]} * * @private */ frustumCommandsList: { get: function () { return this._view.frustumCommandsList; }, }, /** * Gets the number of frustums used in the last frame. * @memberof Scene.prototype * @type {Number} * * @private */ numberOfFrustums: { get: function () { return this._view.frustumCommandsList.length; }, }, /** * Gets the scalar used to exaggerate the terrain. * @memberof Scene.prototype * @type {Number} * @readonly */ terrainExaggeration: { get: function () { return this._terrainExaggeration; }, }, /** * When <code>true</code>, splits the scene into two viewports with steroscopic views for the left and right eyes. * Used for cardboard and WebVR. * @memberof Scene.prototype * @type {Boolean} * @default false */ useWebVR: { get: function () { return this._useWebVR; }, set: function (value) { //>>includeStart('debug', pragmas.debug); if (this.camera.frustum instanceof OrthographicFrustum) { throw new DeveloperError( "VR is unsupported with an orthographic projection." ); } //>>includeEnd('debug'); this._useWebVR = value; if (this._useWebVR) { this._frameState.creditDisplay.container.style.visibility = "hidden"; this._cameraVR = new Camera(this); if (!defined(this._deviceOrientationCameraController)) { this._deviceOrientationCameraController = new DeviceOrientationCameraController( this ); } this._aspectRatioVR = this.camera.frustum.aspectRatio; } else { this._frameState.creditDisplay.container.style.visibility = "visible"; this._cameraVR = undefined; this._deviceOrientationCameraController = this._deviceOrientationCameraController && !this._deviceOrientationCameraController.isDestroyed() && this._deviceOrientationCameraController.destroy(); this.camera.frustum.aspectRatio = this._aspectRatioVR; this.camera.frustum.xOffset = 0.0; } }, }, /** * Determines if the 2D map is rotatable or can be scrolled infinitely in the horizontal direction. * @memberof Scene.prototype * @type {MapMode2D} * @readonly */ mapMode2D: { get: function () { return this._mapMode2D; }, }, /** * Gets or sets the position of the Imagery splitter within the viewport. Valid values are between 0.0 and 1.0. * @memberof Scene.prototype * * @type {Number} */ imagerySplitPosition: { get: function () { return this._frameState.imagerySplitPosition; }, set: function (value) { this._frameState.imagerySplitPosition = value; }, }, /** * The distance from the camera at which to disable the depth test of billboards, labels and points * to, for example, prevent clipping against terrain. When set to zero, the depth test should always * be applied. When less than zero, the depth test should never be applied. Setting the disableDepthTestDistance * property of a billboard, label or point will override this value. * @memberof Scene.prototype * @type {Number} * @default 0.0 */ minimumDisableDepthTestDistance: { get: function () { return this._minimumDisableDepthTestDistance; }, set: function (value) { //>>includeStart('debug', pragmas.debug); if (!defined(value) || value < 0.0) { throw new DeveloperError( "minimumDisableDepthTestDistance must be greater than or equal to 0.0." ); } //>>includeEnd('debug'); this._minimumDisableDepthTestDistance = value; }, }, /** * Whether or not to use a logarithmic depth buffer. Enabling this option will allow for less frustums in the multi-frustum, * increasing performance. This property relies on fragmentDepth being supported. * @memberof Scene.prototype * @type {Boolean} */ logarithmicDepthBuffer: { get: function () { return this._logDepthBuffer; }, set: function (value) { value = this._context.fragmentDepth && value; if (this._logDepthBuffer !== value) { this._logDepthBuffer = value; this._logDepthBufferDirty = true; } }, }, /** * The value used for gamma correction. This is only used when rendering with high dynamic range. * @memberof Scene.prototype * @type {Number} * @default 2.2 */ gamma: { get: function () { return this._context.uniformState.gamma; }, set: function (value) { this._context.uniformState.gamma = value; }, }, /** * Whether or not to use high dynamic range rendering. * @memberof Scene.prototype * @type {Boolean} * @default true */ highDynamicRange: { get: function () { return this._hdr; }, set: function (value) { var context = this._context; var hdr = value && context.depthTexture && (context.colorBufferFloat || context.colorBufferHalfFloat); this._hdrDirty = hdr !== this._hdr; this._hdr = hdr; }, }, /** * Whether or not high dynamic range rendering is supported. * @memberof Scene.prototype * @type {Boolean} * @readonly * @default true */ highDynamicRangeSupported: { get: function () { var context = this._context; return ( context.depthTexture && (context.colorBufferFloat || context.colorBufferHalfFloat) ); }, }, /** * Whether or not the camera is underneath the globe. * @memberof Scene.prototype * @type {Boolean} * @readonly * @default false */ cameraUnderground: { get: function () { return this._cameraUnderground; }, }, /** * Ratio between a pixel and a density-independent pixel. Provides a standard unit of * measure for real pixel measurements appropriate to a particular device. * * @memberof Scene.prototype * @type {Number} * @default 1.0 * @private */ pixelRatio: { get: function () { return this._frameState.pixelRatio; }, set: function (value) { this._frameState.pixelRatio = value; }, }, /** * @private */ opaqueFrustumNearOffset: { get: function () { return 0.9999; }, }, /** * @private */ globeHeight: { get: function () { return this._globeHeight; }, }, }); /** * Determines if a compressed texture format is supported. * @param {String} format The texture format. May be the name of the format or the WebGL extension name, e.g. s3tc or WEBGL_compressed_texture_s3tc. * @return {boolean} Whether or not the format is supported. */ Scene.prototype.getCompressedTextureFormatSupported = function (format) { var context = this.context; return ( ((format === "WEBGL_compressed_texture_s3tc" || format === "s3tc") && context.s3tc) || ((format === "WEBGL_compressed_texture_pvrtc" || format === "pvrtc") && context.pvrtc) || ((format === "WEBGL_compressed_texture_etc1" || format === "etc1") && context.etc1) ); }; function updateDerivedCommands(scene, command, shadowsDirty) { var frameState = scene._frameState; var context = scene._context; var oit = scene._view.oit; var lightShadowMaps = frameState.shadowState.lightShadowMaps; var lightShadowsEnabled = frameState.shadowState.lightShadowsEnabled; var derivedCommands = command.derivedCommands; if (defined(command.pickId)) { derivedCommands.picking = DerivedCommand.createPickDerivedCommand( scene, command, context, derivedCommands.picking ); } if (!command.pickOnly) { derivedCommands.depth = DerivedCommand.createDepthOnlyDerivedCommand( scene, command, context, derivedCommands.depth ); } derivedCommands.originalCommand = command; if (scene._hdr) { derivedCommands.hdr = DerivedCommand.createHdrCommand( comman