SkyAtmosphere.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. import Cartesian3 from '../Core/Cartesian3.js';
  2. import Cartesian4 from '../Core/Cartesian4.js';
  3. import defaultValue from '../Core/defaultValue.js';
  4. import defined from '../Core/defined.js';
  5. import defineProperties from '../Core/defineProperties.js';
  6. import destroyObject from '../Core/destroyObject.js';
  7. import Ellipsoid from '../Core/Ellipsoid.js';
  8. import EllipsoidGeometry from '../Core/EllipsoidGeometry.js';
  9. import GeometryPipeline from '../Core/GeometryPipeline.js';
  10. import CesiumMath from '../Core/Math.js';
  11. import VertexFormat from '../Core/VertexFormat.js';
  12. import BufferUsage from '../Renderer/BufferUsage.js';
  13. import DrawCommand from '../Renderer/DrawCommand.js';
  14. import RenderState from '../Renderer/RenderState.js';
  15. import ShaderProgram from '../Renderer/ShaderProgram.js';
  16. import ShaderSource from '../Renderer/ShaderSource.js';
  17. import VertexArray from '../Renderer/VertexArray.js';
  18. import SkyAtmosphereFS from '../Shaders/SkyAtmosphereFS.js';
  19. import SkyAtmosphereVS from '../Shaders/SkyAtmosphereVS.js';
  20. import BlendingState from './BlendingState.js';
  21. import CullFace from './CullFace.js';
  22. import SceneMode from './SceneMode.js';
  23. /**
  24. * An atmosphere drawn around the limb of the provided ellipsoid. Based on
  25. * {@link https://developer.nvidia.com/gpugems/GPUGems2/gpugems2_chapter16.html|Accurate Atmospheric Scattering}
  26. * in GPU Gems 2.
  27. * <p>
  28. * This is only supported in 3D. Atmosphere is faded out when morphing to 2D or Columbus view.
  29. * </p>
  30. *
  31. * @alias SkyAtmosphere
  32. * @constructor
  33. *
  34. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid that the atmosphere is drawn around.
  35. *
  36. * @example
  37. * scene.skyAtmosphere = new Cesium.SkyAtmosphere();
  38. *
  39. * @demo {@link https://sandcastle.cesium.com/index.html?src=Sky%20Atmosphere.html|Sky atmosphere demo in Sandcastle}
  40. *
  41. * @see Scene.skyAtmosphere
  42. */
  43. function SkyAtmosphere(ellipsoid) {
  44. ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
  45. /**
  46. * Determines if the atmosphere is shown.
  47. *
  48. * @type {Boolean}
  49. * @default true
  50. */
  51. this.show = true;
  52. this._ellipsoid = ellipsoid;
  53. this._command = new DrawCommand({
  54. owner : this
  55. });
  56. this._spSkyFromSpace = undefined;
  57. this._spSkyFromAtmosphere = undefined;
  58. this._spSkyFromSpaceColorCorrect = undefined;
  59. this._spSkyFromAtmosphereColorCorrect = undefined;
  60. /**
  61. * The hue shift to apply to the atmosphere. Defaults to 0.0 (no shift).
  62. * A hue shift of 1.0 indicates a complete rotation of the hues available.
  63. * @type {Number}
  64. * @default 0.0
  65. */
  66. this.hueShift = 0.0;
  67. /**
  68. * The saturation shift to apply to the atmosphere. Defaults to 0.0 (no shift).
  69. * A saturation shift of -1.0 is monochrome.
  70. * @type {Number}
  71. * @default 0.0
  72. */
  73. this.saturationShift = 0.0;
  74. /**
  75. * The brightness shift to apply to the atmosphere. Defaults to 0.0 (no shift).
  76. * A brightness shift of -1.0 is complete darkness, which will let space show through.
  77. * @type {Number}
  78. * @default 0.0
  79. */
  80. this.brightnessShift = 0.0;
  81. this._hueSaturationBrightness = new Cartesian3();
  82. // camera height, outer radius, inner radius, dynamic atmosphere color flag
  83. var cameraAndRadiiAndDynamicAtmosphereColor = new Cartesian4();
  84. // Toggles whether the sun position is used. 0 treats the sun as always directly overhead.
  85. cameraAndRadiiAndDynamicAtmosphereColor.w = 0;
  86. cameraAndRadiiAndDynamicAtmosphereColor.y = Cartesian3.maximumComponent(Cartesian3.multiplyByScalar(ellipsoid.radii, 1.025, new Cartesian3()));
  87. cameraAndRadiiAndDynamicAtmosphereColor.z = ellipsoid.maximumRadius;
  88. this._cameraAndRadiiAndDynamicAtmosphereColor = cameraAndRadiiAndDynamicAtmosphereColor;
  89. var that = this;
  90. this._command.uniformMap = {
  91. u_cameraAndRadiiAndDynamicAtmosphereColor : function() {
  92. return that._cameraAndRadiiAndDynamicAtmosphereColor;
  93. },
  94. u_hsbShift : function() {
  95. that._hueSaturationBrightness.x = that.hueShift;
  96. that._hueSaturationBrightness.y = that.saturationShift;
  97. that._hueSaturationBrightness.z = that.brightnessShift;
  98. return that._hueSaturationBrightness;
  99. }
  100. };
  101. }
  102. defineProperties(SkyAtmosphere.prototype, {
  103. /**
  104. * Gets the ellipsoid the atmosphere is drawn around.
  105. * @memberof SkyAtmosphere.prototype
  106. *
  107. * @type {Ellipsoid}
  108. * @readonly
  109. */
  110. ellipsoid : {
  111. get : function() {
  112. return this._ellipsoid;
  113. }
  114. }
  115. });
  116. /**
  117. * @private
  118. */
  119. SkyAtmosphere.prototype.setDynamicAtmosphereColor = function(enableLighting) {
  120. this._cameraAndRadiiAndDynamicAtmosphereColor.w = enableLighting ? 1 : 0;
  121. };
  122. /**
  123. * @private
  124. */
  125. SkyAtmosphere.prototype.update = function(frameState) {
  126. if (!this.show) {
  127. return undefined;
  128. }
  129. var mode = frameState.mode;
  130. if ((mode !== SceneMode.SCENE3D) &&
  131. (mode !== SceneMode.MORPHING)) {
  132. return undefined;
  133. }
  134. // The atmosphere is only rendered during the render pass; it is not pickable, it doesn't cast shadows, etc.
  135. if (!frameState.passes.render) {
  136. return undefined;
  137. }
  138. var command = this._command;
  139. if (!defined(command.vertexArray)) {
  140. var context = frameState.context;
  141. var geometry = EllipsoidGeometry.createGeometry(new EllipsoidGeometry({
  142. radii : Cartesian3.multiplyByScalar(this._ellipsoid.radii, 1.025, new Cartesian3()),
  143. slicePartitions : 256,
  144. stackPartitions : 256,
  145. vertexFormat : VertexFormat.POSITION_ONLY
  146. }));
  147. command.vertexArray = VertexArray.fromGeometry({
  148. context : context,
  149. geometry : geometry,
  150. attributeLocations : GeometryPipeline.createAttributeLocations(geometry),
  151. bufferUsage : BufferUsage.STATIC_DRAW
  152. });
  153. command.renderState = RenderState.fromCache({
  154. cull : {
  155. enabled : true,
  156. face : CullFace.FRONT
  157. },
  158. blending : BlendingState.ALPHA_BLEND,
  159. depthMask : false
  160. });
  161. var vs = new ShaderSource({
  162. defines : ['SKY_FROM_SPACE'],
  163. sources : [SkyAtmosphereVS]
  164. });
  165. this._spSkyFromSpace = ShaderProgram.fromCache({
  166. context : context,
  167. vertexShaderSource : vs,
  168. fragmentShaderSource : SkyAtmosphereFS
  169. });
  170. vs = new ShaderSource({
  171. defines : ['SKY_FROM_ATMOSPHERE'],
  172. sources : [SkyAtmosphereVS]
  173. });
  174. this._spSkyFromAtmosphere = ShaderProgram.fromCache({
  175. context : context,
  176. vertexShaderSource : vs,
  177. fragmentShaderSource : SkyAtmosphereFS
  178. });
  179. }
  180. // Compile the color correcting versions of the shader on demand
  181. var useColorCorrect = colorCorrect(this);
  182. if (useColorCorrect && (!defined(this._spSkyFromSpaceColorCorrect) || !defined(this._spSkyFromAtmosphereColorCorrect))) {
  183. var contextColorCorrect = frameState.context;
  184. var vsColorCorrect = new ShaderSource({
  185. defines : ['SKY_FROM_SPACE'],
  186. sources : [SkyAtmosphereVS]
  187. });
  188. var fsColorCorrect = new ShaderSource({
  189. defines : ['COLOR_CORRECT'],
  190. sources : [SkyAtmosphereFS]
  191. });
  192. this._spSkyFromSpaceColorCorrect = ShaderProgram.fromCache({
  193. context : contextColorCorrect,
  194. vertexShaderSource : vsColorCorrect,
  195. fragmentShaderSource : fsColorCorrect
  196. });
  197. vsColorCorrect = new ShaderSource({
  198. defines : ['SKY_FROM_ATMOSPHERE'],
  199. sources : [SkyAtmosphereVS]
  200. });
  201. this._spSkyFromAtmosphereColorCorrect = ShaderProgram.fromCache({
  202. context : contextColorCorrect,
  203. vertexShaderSource : vsColorCorrect,
  204. fragmentShaderSource : fsColorCorrect
  205. });
  206. }
  207. var cameraPosition = frameState.camera.positionWC;
  208. var cameraHeight = Cartesian3.magnitude(cameraPosition);
  209. this._cameraAndRadiiAndDynamicAtmosphereColor.x = cameraHeight;
  210. if (cameraHeight > this._cameraAndRadiiAndDynamicAtmosphereColor.y) {
  211. // Camera in space
  212. command.shaderProgram = useColorCorrect ? this._spSkyFromSpaceColorCorrect : this._spSkyFromSpace;
  213. } else {
  214. // Camera in atmosphere
  215. command.shaderProgram = useColorCorrect ? this._spSkyFromAtmosphereColorCorrect : this._spSkyFromAtmosphere;
  216. }
  217. return command;
  218. };
  219. function colorCorrect(skyAtmosphere) {
  220. return !(CesiumMath.equalsEpsilon(skyAtmosphere.hueShift, 0.0, CesiumMath.EPSILON7) &&
  221. CesiumMath.equalsEpsilon(skyAtmosphere.saturationShift, 0.0, CesiumMath.EPSILON7) &&
  222. CesiumMath.equalsEpsilon(skyAtmosphere.brightnessShift, 0.0, CesiumMath.EPSILON7));
  223. }
  224. /**
  225. * Returns true if this object was destroyed; otherwise, false.
  226. * <br /><br />
  227. * If this object was destroyed, it should not be used; calling any function other than
  228. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  229. *
  230. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  231. *
  232. * @see SkyAtmosphere#destroy
  233. */
  234. SkyAtmosphere.prototype.isDestroyed = function() {
  235. return false;
  236. };
  237. /**
  238. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  239. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  240. * <br /><br />
  241. * Once an object is destroyed, it should not be used; calling any function other than
  242. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  243. * assign the return value (<code>undefined</code>) to the object as done in the example.
  244. *
  245. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  246. *
  247. *
  248. * @example
  249. * skyAtmosphere = skyAtmosphere && skyAtmosphere.destroy();
  250. *
  251. * @see SkyAtmosphere#isDestroyed
  252. */
  253. SkyAtmosphere.prototype.destroy = function() {
  254. var command = this._command;
  255. command.vertexArray = command.vertexArray && command.vertexArray.destroy();
  256. this._spSkyFromSpace = this._spSkyFromSpace && this._spSkyFromSpace.destroy();
  257. this._spSkyFromAtmosphere = this._spSkyFromAtmosphere && this._spSkyFromAtmosphere.destroy();
  258. this._spSkyFromSpaceColorCorrect = this._spSkyFromSpaceColorCorrect && this._spSkyFromSpaceColorCorrect.destroy();
  259. this._spSkyFromAtmosphereColorCorrect = this._spSkyFromAtmosphereColorCorrect && this._spSkyFromAtmosphereColorCorrect.destroy();
  260. return destroyObject(this);
  261. };
  262. export default SkyAtmosphere;