/*global define*/ define([ '../Core/Cartesian3', '../Core/defaultValue', '../Core/defined', '../Core/defineProperties', '../Core/destroyObject', '../Core/Ellipsoid', '../Core/EllipsoidGeometry', '../Core/GeometryPipeline', '../Core/VertexFormat', '../Renderer/BufferUsage', '../Renderer/DrawCommand', '../Renderer/ShaderSource', '../Shaders/SkyAtmosphereFS', '../Shaders/SkyAtmosphereVS', './BlendingState', './CullFace', './SceneMode' ], function( Cartesian3, defaultValue, defined, defineProperties, destroyObject, Ellipsoid, EllipsoidGeometry, GeometryPipeline, VertexFormat, BufferUsage, DrawCommand, ShaderSource, SkyAtmosphereFS, SkyAtmosphereVS, BlendingState, CullFace, SceneMode) { "use strict"; /** * An atmosphere drawn around the limb of the provided ellipsoid. Based on * {@link http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter16.html|Accurate Atmospheric Scattering} * in GPU Gems 2. *

* This is only supported in 3D. atmosphere is faded out when morphing to 2D or Columbus view. *

* * @alias SkyAtmosphere * @constructor * * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid that the atmosphere is drawn around. * * @example * scene.skyAtmosphere = new Cesium.SkyAtmosphere(); * * @see Scene.skyAtmosphere */ var SkyAtmosphere = function(ellipsoid) { ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84); /** * Determines if the atmosphere is shown. * * @type {Boolean} * @default true */ this.show = true; this._ellipsoid = ellipsoid; this._command = new DrawCommand({ owner : this }); this._spSkyFromSpace = undefined; this._spSkyFromAtmosphere = undefined; this._fCameraHeight = undefined; this._fCameraHeight2 = undefined; this._outerRadius = Cartesian3.maximumComponent(Cartesian3.multiplyByScalar(ellipsoid.radii, 1.025, new Cartesian3())); var innerRadius = ellipsoid.maximumRadius; var rayleighScaleDepth = 0.25; var that = this; this._command.uniformMap = { fCameraHeight : function() { return that._fCameraHeight; }, fCameraHeight2 : function() { return that._fCameraHeight2; }, fOuterRadius : function() { return that._outerRadius; }, fOuterRadius2 : function() { return that._outerRadius * that._outerRadius; }, fInnerRadius : function() { return innerRadius; }, fScale : function() { return 1.0 / (that._outerRadius - innerRadius); }, fScaleDepth : function() { return rayleighScaleDepth; }, fScaleOverScaleDepth : function() { return (1.0 / (that._outerRadius - innerRadius)) / rayleighScaleDepth; } }; }; defineProperties(SkyAtmosphere.prototype, { /** * Gets the ellipsoid the atmosphere is drawn around. * @memberof SkyAtmosphere.prototype * * @type {Ellipsoid} * @readonly */ ellipsoid : { get : function() { return this._ellipsoid; } } }); /** * @private */ SkyAtmosphere.prototype.update = function(context, frameState) { if (!this.show) { return undefined; } if ((frameState.mode !== SceneMode.SCENE3D) && (frameState.mode !== SceneMode.MORPHING)) { return undefined; } // The atmosphere is only rendered during the render pass; it is not pickable, it doesn't cast shadows, etc. if (!frameState.passes.render) { return undefined; } var command = this._command; if (!defined(command.vertexArray)) { var geometry = EllipsoidGeometry.createGeometry(new EllipsoidGeometry({ radii : Cartesian3.multiplyByScalar(this._ellipsoid.radii, 1.025, new Cartesian3()), slicePartitions : 256, stackPartitions : 256, vertexFormat : VertexFormat.POSITION_ONLY })); command.vertexArray = context.createVertexArrayFromGeometry({ geometry : geometry, attributeLocations : GeometryPipeline.createAttributeLocations(geometry), bufferUsage : BufferUsage.STATIC_DRAW }); command.renderState = context.createRenderState({ cull : { enabled : true, face : CullFace.FRONT }, blending : BlendingState.ALPHA_BLEND }); var vs = new ShaderSource({ defines : ['SKY_FROM_SPACE'], sources : [SkyAtmosphereVS] }); this._spSkyFromSpace = context.createShaderProgram(vs, SkyAtmosphereFS); vs = new ShaderSource({ defines : ['SKY_FROM_ATMOSPHERE'], sources : [SkyAtmosphereVS] }); this._spSkyFromAtmosphere = context.createShaderProgram(vs, SkyAtmosphereFS); } var cameraPosition = frameState.camera.positionWC; this._fCameraHeight2 = Cartesian3.magnitudeSquared(cameraPosition); this._fCameraHeight = Math.sqrt(this._fCameraHeight2); if (this._fCameraHeight > this._outerRadius) { // Camera in space command.shaderProgram = this._spSkyFromSpace; } else { // Camera in atmosphere command.shaderProgram = this._spSkyFromAtmosphere; } return command; }; /** * Returns true if this object was destroyed; otherwise, false. *

* If this object was destroyed, it should not be used; calling any function other than * isDestroyed will result in a {@link DeveloperError} exception. * * @returns {Boolean} true if this object was destroyed; otherwise, false. * * @see SkyAtmosphere#destroy */ SkyAtmosphere.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. *

* Once an object is destroyed, it should not be used; calling any function other than * isDestroyed will result in a {@link DeveloperError} exception. Therefore, * assign the return value (undefined) to the object as done in the example. * * @returns {undefined} * * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called. * * @see SkyAtmosphere#isDestroyed * * @example * skyAtmosphere = skyAtmosphere && skyAtmosphere.destroy(); */ SkyAtmosphere.prototype.destroy = function() { var command = this._command; command.vertexArray = command.vertexArray && command.vertexArray.destroy(); this._spSkyFromSpace = this._spSkyFromSpace && this._spSkyFromSpace.destroy(); this._spSkyFromAtmosphere = this._spSkyFromAtmosphere && this._spSkyFromAtmosphere.destroy(); return destroyObject(this); }; return SkyAtmosphere; });