SkyBox.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. import BoxGeometry from "../Core/BoxGeometry.js";
  2. import Cartesian3 from "../Core/Cartesian3.js";
  3. import defaultValue from "../Core/defaultValue.js";
  4. import defined from "../Core/defined.js";
  5. import destroyObject from "../Core/destroyObject.js";
  6. import DeveloperError from "../Core/DeveloperError.js";
  7. import GeometryPipeline from "../Core/GeometryPipeline.js";
  8. import Matrix4 from "../Core/Matrix4.js";
  9. import VertexFormat from "../Core/VertexFormat.js";
  10. import BufferUsage from "../Renderer/BufferUsage.js";
  11. import CubeMap from "../Renderer/CubeMap.js";
  12. import DrawCommand from "../Renderer/DrawCommand.js";
  13. import loadCubeMap from "../Renderer/loadCubeMap.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 SkyBoxFS from "../Shaders/SkyBoxFS.js";
  19. import SkyBoxVS from "../Shaders/SkyBoxVS.js";
  20. import BlendingState from "./BlendingState.js";
  21. import SceneMode from "./SceneMode.js";
  22. /**
  23. * A sky box around the scene to draw stars. The sky box is defined using the True Equator Mean Equinox (TEME) axes.
  24. * <p>
  25. * This is only supported in 3D. The sky box is faded out when morphing to 2D or Columbus view. The size of
  26. * the sky box must not exceed {@link Scene#maximumCubeMapSize}.
  27. * </p>
  28. *
  29. * @alias SkyBox
  30. * @constructor
  31. *
  32. * @param {Object} options Object with the following properties:
  33. * @param {Object} [options.sources] The source URL or <code>Image</code> object for each of the six cube map faces. See the example below.
  34. * @param {Boolean} [options.show=true] Determines if this primitive will be shown.
  35. *
  36. *
  37. * @example
  38. * scene.skyBox = new Cesium.SkyBox({
  39. * sources : {
  40. * positiveX : 'skybox_px.png',
  41. * negativeX : 'skybox_nx.png',
  42. * positiveY : 'skybox_py.png',
  43. * negativeY : 'skybox_ny.png',
  44. * positiveZ : 'skybox_pz.png',
  45. * negativeZ : 'skybox_nz.png'
  46. * }
  47. * });
  48. *
  49. * @see Scene#skyBox
  50. * @see Transforms.computeTemeToPseudoFixedMatrix
  51. */
  52. function SkyBox(options) {
  53. /**
  54. * The sources used to create the cube map faces: an object
  55. * with <code>positiveX</code>, <code>negativeX</code>, <code>positiveY</code>,
  56. * <code>negativeY</code>, <code>positiveZ</code>, and <code>negativeZ</code> properties.
  57. * These can be either URLs or <code>Image</code> objects.
  58. *
  59. * @type Object
  60. * @default undefined
  61. */
  62. this.sources = options.sources;
  63. this._sources = undefined;
  64. /**
  65. * Determines if the sky box will be shown.
  66. *
  67. * @type {Boolean}
  68. * @default true
  69. */
  70. this.show = defaultValue(options.show, true);
  71. this._command = new DrawCommand({
  72. modelMatrix: Matrix4.clone(Matrix4.IDENTITY),
  73. owner: this,
  74. });
  75. this._cubeMap = undefined;
  76. this._attributeLocations = undefined;
  77. this._useHdr = undefined;
  78. }
  79. /**
  80. * Called when {@link Viewer} or {@link CesiumWidget} render the scene to
  81. * get the draw commands needed to render this primitive.
  82. * <p>
  83. * Do not call this function directly. This is documented just to
  84. * list the exceptions that may be propagated when the scene is rendered:
  85. * </p>
  86. *
  87. * @exception {DeveloperError} this.sources is required and must have positiveX, negativeX, positiveY, negativeY, positiveZ, and negativeZ properties.
  88. * @exception {DeveloperError} this.sources properties must all be the same type.
  89. */
  90. SkyBox.prototype.update = function (frameState, useHdr) {
  91. const that = this;
  92. if (!this.show) {
  93. return undefined;
  94. }
  95. if (
  96. frameState.mode !== SceneMode.SCENE3D &&
  97. frameState.mode !== SceneMode.MORPHING
  98. ) {
  99. return undefined;
  100. }
  101. // The sky box is only rendered during the render pass; it is not pickable, it doesn't cast shadows, etc.
  102. if (!frameState.passes.render) {
  103. return undefined;
  104. }
  105. const context = frameState.context;
  106. if (this._sources !== this.sources) {
  107. this._sources = this.sources;
  108. const sources = this.sources;
  109. //>>includeStart('debug', pragmas.debug);
  110. if (
  111. !defined(sources.positiveX) ||
  112. !defined(sources.negativeX) ||
  113. !defined(sources.positiveY) ||
  114. !defined(sources.negativeY) ||
  115. !defined(sources.positiveZ) ||
  116. !defined(sources.negativeZ)
  117. ) {
  118. throw new DeveloperError(
  119. "this.sources is required and must have positiveX, negativeX, positiveY, negativeY, positiveZ, and negativeZ properties."
  120. );
  121. }
  122. if (
  123. typeof sources.positiveX !== typeof sources.negativeX ||
  124. typeof sources.positiveX !== typeof sources.positiveY ||
  125. typeof sources.positiveX !== typeof sources.negativeY ||
  126. typeof sources.positiveX !== typeof sources.positiveZ ||
  127. typeof sources.positiveX !== typeof sources.negativeZ
  128. ) {
  129. throw new DeveloperError(
  130. "this.sources properties must all be the same type."
  131. );
  132. }
  133. //>>includeEnd('debug');
  134. if (typeof sources.positiveX === "string") {
  135. // Given urls for cube-map images. Load them.
  136. loadCubeMap(context, this._sources).then(function (cubeMap) {
  137. that._cubeMap = that._cubeMap && that._cubeMap.destroy();
  138. that._cubeMap = cubeMap;
  139. });
  140. } else {
  141. this._cubeMap = this._cubeMap && this._cubeMap.destroy();
  142. this._cubeMap = new CubeMap({
  143. context: context,
  144. source: sources,
  145. });
  146. }
  147. }
  148. const command = this._command;
  149. if (!defined(command.vertexArray)) {
  150. command.uniformMap = {
  151. u_cubeMap: function () {
  152. return that._cubeMap;
  153. },
  154. };
  155. const geometry = BoxGeometry.createGeometry(
  156. BoxGeometry.fromDimensions({
  157. dimensions: new Cartesian3(2.0, 2.0, 2.0),
  158. vertexFormat: VertexFormat.POSITION_ONLY,
  159. })
  160. );
  161. const attributeLocations = (this._attributeLocations = GeometryPipeline.createAttributeLocations(
  162. geometry
  163. ));
  164. command.vertexArray = VertexArray.fromGeometry({
  165. context: context,
  166. geometry: geometry,
  167. attributeLocations: attributeLocations,
  168. bufferUsage: BufferUsage.STATIC_DRAW,
  169. });
  170. command.renderState = RenderState.fromCache({
  171. blending: BlendingState.ALPHA_BLEND,
  172. });
  173. }
  174. if (!defined(command.shaderProgram) || this._useHdr !== useHdr) {
  175. const fs = new ShaderSource({
  176. defines: [useHdr ? "HDR" : ""],
  177. sources: [SkyBoxFS],
  178. });
  179. command.shaderProgram = ShaderProgram.fromCache({
  180. context: context,
  181. vertexShaderSource: SkyBoxVS,
  182. fragmentShaderSource: fs,
  183. attributeLocations: this._attributeLocations,
  184. });
  185. this._useHdr = useHdr;
  186. }
  187. if (!defined(this._cubeMap)) {
  188. return undefined;
  189. }
  190. return command;
  191. };
  192. /**
  193. * Returns true if this object was destroyed; otherwise, false.
  194. * <br /><br />
  195. * If this object was destroyed, it should not be used; calling any function other than
  196. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  197. *
  198. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  199. *
  200. * @see SkyBox#destroy
  201. */
  202. SkyBox.prototype.isDestroyed = function () {
  203. return false;
  204. };
  205. /**
  206. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  207. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  208. * <br /><br />
  209. * Once an object is destroyed, it should not be used; calling any function other than
  210. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  211. * assign the return value (<code>undefined</code>) to the object as done in the example.
  212. *
  213. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  214. *
  215. *
  216. * @example
  217. * skyBox = skyBox && skyBox.destroy();
  218. *
  219. * @see SkyBox#isDestroyed
  220. */
  221. SkyBox.prototype.destroy = function () {
  222. const command = this._command;
  223. command.vertexArray = command.vertexArray && command.vertexArray.destroy();
  224. command.shaderProgram =
  225. command.shaderProgram && command.shaderProgram.destroy();
  226. this._cubeMap = this._cubeMap && this._cubeMap.destroy();
  227. return destroyObject(this);
  228. };
  229. export default SkyBox;