智慧水务管理系统 - 精河县供水工程综合管理平台

SpecularEnvironmentCubeMap.js 7.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. import defined from "../Core/defined.js";
  2. import destroyObject from "../Core/destroyObject.js";
  3. import Event from "../Core/Event.js";
  4. import loadKTX2 from "../Core/loadKTX2.js";
  5. import PixelFormat from "../Core/PixelFormat.js";
  6. import CubeMap from "../Renderer/CubeMap.js";
  7. import PixelDatatype from "../Renderer/PixelDatatype.js";
  8. import Sampler from "../Renderer/Sampler.js";
  9. import TextureMinificationFilter from "../Renderer/TextureMinificationFilter.js";
  10. /**
  11. * Manages a cube map for use as a specular environment map.
  12. *
  13. * @alias SpecularEnvironmentCubeMap
  14. * @constructor
  15. *
  16. * @param {string} url The url to the KTX2 file containing the specular environment map and convoluted mipmaps.
  17. * @private
  18. */
  19. function SpecularEnvironmentCubeMap(url) {
  20. this._url = url;
  21. this._cubeMapBuffers = undefined;
  22. this._texture = undefined;
  23. this._maximumMipmapLevel = undefined;
  24. this._loading = false;
  25. this._ready = false;
  26. this._errorEvent = new Event();
  27. }
  28. Object.defineProperties(SpecularEnvironmentCubeMap.prototype, {
  29. /**
  30. * The url to the KTX2 file containing the specular environment map and convoluted mipmaps.
  31. * @memberof SpecularEnvironmentCubeMap.prototype
  32. * @type {string}
  33. * @readonly
  34. */
  35. url: {
  36. get: function () {
  37. return this._url;
  38. },
  39. },
  40. /**
  41. * Gets an event that is raised when encountering an asynchronous error. By subscribing
  42. * to the event, you will be notified of the error and can potentially recover from it.
  43. * @memberof SpecularEnvironmentCubeMap.prototype
  44. * @type {Event}
  45. * @readonly
  46. */
  47. errorEvent: {
  48. get: function () {
  49. return this._errorEvent;
  50. },
  51. },
  52. /**
  53. * A texture containing all the packed convolutions.
  54. * @memberof SpecularEnvironmentCubeMap.prototype
  55. * @type {Texture}
  56. * @readonly
  57. */
  58. texture: {
  59. get: function () {
  60. return this._texture;
  61. },
  62. },
  63. /**
  64. * The maximum number of mip levels with valid environment map data.
  65. * This may differ from the number of mips in the WebGL cubemap.
  66. * The data loaded at <code>maximumMipmapLevel</code> is suitable for
  67. * PBR rendering of a material with maximum roughness (1.0).
  68. * @memberOf SpecularEnvironmentCubeMap.prototype
  69. * @type {number}
  70. * @readonly
  71. */
  72. maximumMipmapLevel: {
  73. get: function () {
  74. return this._maximumMipmapLevel;
  75. },
  76. },
  77. /**
  78. * Determines if the cube map is complete and ready to use.
  79. * @memberof SpecularEnvironmentCubeMap.prototype
  80. * @type {boolean}
  81. * @readonly
  82. */
  83. ready: {
  84. get: function () {
  85. return this._ready;
  86. },
  87. },
  88. });
  89. SpecularEnvironmentCubeMap.isSupported = function (context) {
  90. const supportsFloatBuffersAndTextures =
  91. (context.colorBufferHalfFloat && context.halfFloatingPointTexture) ||
  92. (context.floatingPointTexture && context.colorBufferFloat);
  93. return supportsFloatBuffersAndTextures && context.supportsTextureLod;
  94. };
  95. function cleanupResources(map) {
  96. map._cubeMapBuffers = undefined;
  97. }
  98. /**
  99. * Loads the environment map image and constructs the cube map for specular radiance calculations.
  100. * <p>
  101. * Once the image is loaded, the next call cleans up unused resources. Every call after that is a no-op.
  102. * </p>
  103. * @param {FrameState} frameState The frame state.
  104. *
  105. * @private
  106. */
  107. SpecularEnvironmentCubeMap.prototype.update = function (frameState) {
  108. const { context } = frameState;
  109. if (!SpecularEnvironmentCubeMap.isSupported(context)) {
  110. return;
  111. }
  112. if (defined(this._texture)) {
  113. cleanupResources(this);
  114. return;
  115. }
  116. if (!defined(this._texture) && !this._loading) {
  117. const cachedTexture = context.textureCache.getTexture(this._url);
  118. if (defined(cachedTexture)) {
  119. cleanupResources(this);
  120. this._texture = cachedTexture;
  121. this._maximumMipmapLevel = this._texture.maximumMipmapLevel;
  122. this._ready = true;
  123. }
  124. }
  125. const cubeMapBuffers = this._cubeMapBuffers;
  126. if (!defined(cubeMapBuffers) && !this._loading) {
  127. const that = this;
  128. loadKTX2(this._url)
  129. .then(function (buffers) {
  130. that._cubeMapBuffers = buffers;
  131. that._loading = false;
  132. })
  133. .catch(function (error) {
  134. if (that.isDestroyed()) {
  135. return;
  136. }
  137. that._errorEvent.raiseEvent(error);
  138. });
  139. this._loading = true;
  140. }
  141. if (!defined(this._cubeMapBuffers)) {
  142. return;
  143. }
  144. // Datatype is defined if it is a normalized type (i.e. ..._UNORM, ..._SFLOAT)
  145. let { pixelDatatype } = cubeMapBuffers[0].positiveX;
  146. if (!defined(pixelDatatype)) {
  147. pixelDatatype = context.halfFloatingPointTexture
  148. ? PixelDatatype.HALF_FLOAT
  149. : PixelDatatype.FLOAT;
  150. }
  151. const pixelFormat = PixelFormat.RGBA;
  152. const mipLevels = cubeMapBuffers.length;
  153. this._maximumMipmapLevel = mipLevels - 1;
  154. const faceSize = cubeMapBuffers[0].positiveX.width;
  155. const expectedMipLevels = Math.log2(faceSize) + 1;
  156. if (mipLevels !== expectedMipLevels) {
  157. // We assume the last supplied mip level was computed as the specular radiance
  158. // for roughness 1.0.
  159. // Fill the remaining levels with null values, to avoid WebGL errors.
  160. const dummyMipLevel = {};
  161. Object.values(CubeMap.FaceName).forEach((faceName) => {
  162. dummyMipLevel[faceName] = undefined;
  163. });
  164. for (let mipLevel = mipLevels; mipLevel < expectedMipLevels; mipLevel++) {
  165. cubeMapBuffers.push(dummyMipLevel);
  166. }
  167. }
  168. const sampler = new Sampler({
  169. minificationFilter: TextureMinificationFilter.LINEAR_MIPMAP_LINEAR,
  170. });
  171. const cubeMap = new CubeMap({
  172. context: context,
  173. source: cubeMapBuffers[0],
  174. flipY: false,
  175. pixelDatatype: pixelDatatype,
  176. pixelFormat: pixelFormat,
  177. sampler: sampler,
  178. });
  179. cubeMap.loadMipmaps(cubeMapBuffers.slice(1));
  180. this._texture = cubeMap;
  181. this._texture.maximumMipmapLevel = this._maximumMipmapLevel;
  182. context.textureCache.addTexture(this._url, this._texture);
  183. this._ready = true;
  184. };
  185. /**
  186. * Returns true if this object was destroyed; otherwise, false.
  187. * <p>
  188. * If this object was destroyed, it should not be used; calling any function other than
  189. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  190. * </p>
  191. *
  192. * @returns {boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  193. *
  194. * @see SpecularEnvironmentCubeMap#destroy
  195. */
  196. SpecularEnvironmentCubeMap.prototype.isDestroyed = function () {
  197. return false;
  198. };
  199. /**
  200. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  201. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  202. * <p>
  203. * Once an object is destroyed, it should not be used; calling any function other than
  204. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  205. * assign the return value (<code>undefined</code>) to the object as done in the example.
  206. * </p>
  207. *
  208. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  209. *
  210. * @see SpecularEnvironmentCubeMap#isDestroyed
  211. */
  212. SpecularEnvironmentCubeMap.prototype.destroy = function () {
  213. cleanupResources(this);
  214. this._texture = this._texture && this._texture.destroy();
  215. return destroyObject(this);
  216. };
  217. export default SpecularEnvironmentCubeMap;