environmentTextureTools.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. import { Tools } from "./tools.js";
  2. import { Vector3 } from "../Maths/math.vector.js";
  3. import { Scalar } from "../Maths/math.scalar.js";
  4. import { SphericalPolynomial } from "../Maths/sphericalPolynomial.js";
  5. import { InternalTexture, InternalTextureSource } from "../Materials/Textures/internalTexture.js";
  6. import { BaseTexture } from "../Materials/Textures/baseTexture.js";
  7. import { Scene } from "../scene.js";
  8. import { PostProcess } from "../PostProcesses/postProcess.js";
  9. import { Logger } from "../Misc/logger.js";
  10. import { RGBDTextureTools } from "./rgbdTextureTools.js";
  11. import "../Engines/Extensions/engine.renderTargetCube.js";
  12. import "../Engines/Extensions/engine.readTexture.js";
  13. import "../Materials/Textures/baseTexture.polynomial.js";
  14. import "../Shaders/rgbdEncode.fragment.js";
  15. import "../Shaders/rgbdDecode.fragment.js";
  16. import { DumpTools } from "../Misc/dumpTools.js";
  17. const DefaultEnvironmentTextureImageType = "image/png";
  18. const CurrentVersion = 2;
  19. /**
  20. * Magic number identifying the env file.
  21. */
  22. const MagicBytes = [0x86, 0x16, 0x87, 0x96, 0xf6, 0xd6, 0x96, 0x36];
  23. /**
  24. * Gets the environment info from an env file.
  25. * @param data The array buffer containing the .env bytes.
  26. * @returns the environment file info (the json header) if successfully parsed, normalized to the latest supported version.
  27. */
  28. export function GetEnvInfo(data) {
  29. const dataView = new DataView(data.buffer, data.byteOffset, data.byteLength);
  30. let pos = 0;
  31. for (let i = 0; i < MagicBytes.length; i++) {
  32. if (dataView.getUint8(pos++) !== MagicBytes[i]) {
  33. Logger.Error("Not a babylon environment map");
  34. return null;
  35. }
  36. }
  37. // Read json manifest - collect characters up to null terminator
  38. let manifestString = "";
  39. let charCode = 0x00;
  40. while ((charCode = dataView.getUint8(pos++))) {
  41. manifestString += String.fromCharCode(charCode);
  42. }
  43. let manifest = JSON.parse(manifestString);
  44. manifest = normalizeEnvInfo(manifest);
  45. if (manifest.specular) {
  46. // Extend the header with the position of the payload.
  47. manifest.specular.specularDataPosition = pos;
  48. // Fallback to 0.8 exactly if lodGenerationScale is not defined for backward compatibility.
  49. manifest.specular.lodGenerationScale = manifest.specular.lodGenerationScale || 0.8;
  50. }
  51. return manifest;
  52. }
  53. /**
  54. * Normalizes any supported version of the environment file info to the latest version
  55. * @param info environment file info on any supported version
  56. * @returns environment file info in the latest supported version
  57. * @private
  58. */
  59. export function normalizeEnvInfo(info) {
  60. if (info.version > CurrentVersion) {
  61. throw new Error(`Unsupported babylon environment map version "${info.version}". Latest supported version is "${CurrentVersion}".`);
  62. }
  63. if (info.version === 2) {
  64. return info;
  65. }
  66. // Migrate a v1 info to v2
  67. info = { ...info, version: 2, imageType: DefaultEnvironmentTextureImageType };
  68. return info;
  69. }
  70. /**
  71. * Creates an environment texture from a loaded cube texture.
  72. * @param texture defines the cube texture to convert in env file
  73. * @param options options for the conversion process
  74. * @param options.imageType the mime type for the encoded images, with support for "image/png" (default) and "image/webp"
  75. * @param options.imageQuality the image quality of encoded WebP images.
  76. * @returns a promise containing the environment data if successful.
  77. */
  78. export async function CreateEnvTextureAsync(texture, options = {}) {
  79. const internalTexture = texture.getInternalTexture();
  80. if (!internalTexture) {
  81. return Promise.reject("The cube texture is invalid.");
  82. }
  83. const imageType = options.imageType ?? DefaultEnvironmentTextureImageType;
  84. const engine = internalTexture.getEngine();
  85. if (texture.textureType !== 2 &&
  86. texture.textureType !== 1 &&
  87. texture.textureType !== 0 &&
  88. texture.textureType !== 0 &&
  89. texture.textureType !== 7 &&
  90. texture.textureType !== -1) {
  91. return Promise.reject("The cube texture should allow HDR (Full Float or Half Float).");
  92. }
  93. let textureType = 1;
  94. if (!engine.getCaps().textureFloatRender) {
  95. textureType = 2;
  96. if (!engine.getCaps().textureHalfFloatRender) {
  97. return Promise.reject("Env texture can only be created when the browser supports half float or full float rendering.");
  98. }
  99. }
  100. // sphericalPolynomial is lazy loaded so simply accessing it should trigger the computation.
  101. texture.sphericalPolynomial;
  102. // Lets keep track of the polynomial promise so we can wait for it to be ready before generating the pixels.
  103. const sphericalPolynomialPromise = texture.getInternalTexture()?._sphericalPolynomialPromise;
  104. const cubeWidth = internalTexture.width;
  105. const hostingScene = new Scene(engine);
  106. const specularTextures = {};
  107. // As we are going to readPixels the faces of the cube, make sure the drawing/update commands for the cube texture are fully sent to the GPU in case it is drawn for the first time in this very frame!
  108. engine.flushFramebuffer();
  109. // Read and collect all mipmaps data from the cube.
  110. const mipmapsCount = Scalar.ILog2(internalTexture.width);
  111. for (let i = 0; i <= mipmapsCount; i++) {
  112. const faceWidth = Math.pow(2, mipmapsCount - i);
  113. // All faces of the cube.
  114. for (let face = 0; face < 6; face++) {
  115. let faceData = await texture.readPixels(face, i, undefined, false);
  116. if (faceData && faceData.byteLength === faceData.length) {
  117. const faceDataFloat = new Float32Array(faceData.byteLength * 4);
  118. for (let i = 0; i < faceData.byteLength; i++) {
  119. faceDataFloat[i] = faceData[i] / 255;
  120. // Gamma to linear
  121. faceDataFloat[i] = Math.pow(faceDataFloat[i], 2.2);
  122. }
  123. faceData = faceDataFloat;
  124. }
  125. else if (faceData && texture.gammaSpace) {
  126. const floatData = faceData;
  127. for (let i = 0; i < floatData.length; i++) {
  128. // Gamma to linear
  129. floatData[i] = Math.pow(floatData[i], 2.2);
  130. }
  131. }
  132. const tempTexture = engine.createRawTexture(faceData, faceWidth, faceWidth, 5, false, true, 1, null, textureType);
  133. await RGBDTextureTools.EncodeTextureToRGBD(tempTexture, hostingScene, textureType);
  134. const rgbdEncodedData = await engine._readTexturePixels(tempTexture, faceWidth, faceWidth);
  135. const imageEncodedData = await DumpTools.DumpDataAsync(faceWidth, faceWidth, rgbdEncodedData, imageType, undefined, false, true, options.imageQuality);
  136. specularTextures[i * 6 + face] = imageEncodedData;
  137. tempTexture.dispose();
  138. }
  139. }
  140. // We can delete the hosting scene keeping track of all the creation objects
  141. hostingScene.dispose();
  142. // Ensure completion of the polynomial creation promise.
  143. if (sphericalPolynomialPromise) {
  144. await sphericalPolynomialPromise;
  145. }
  146. // Creates the json header for the env texture
  147. const info = {
  148. version: CurrentVersion,
  149. width: cubeWidth,
  150. imageType,
  151. irradiance: _CreateEnvTextureIrradiance(texture),
  152. specular: {
  153. mipmaps: [],
  154. lodGenerationScale: texture.lodGenerationScale,
  155. },
  156. };
  157. // Sets the specular image data information
  158. let position = 0;
  159. for (let i = 0; i <= mipmapsCount; i++) {
  160. for (let face = 0; face < 6; face++) {
  161. const byteLength = specularTextures[i * 6 + face].byteLength;
  162. info.specular.mipmaps.push({
  163. length: byteLength,
  164. position: position,
  165. });
  166. position += byteLength;
  167. }
  168. }
  169. // Encode the JSON as an array buffer
  170. const infoString = JSON.stringify(info);
  171. const infoBuffer = new ArrayBuffer(infoString.length + 1);
  172. const infoView = new Uint8Array(infoBuffer); // Limited to ascii subset matching unicode.
  173. for (let i = 0, strLen = infoString.length; i < strLen; i++) {
  174. infoView[i] = infoString.charCodeAt(i);
  175. }
  176. // Ends up with a null terminator for easier parsing
  177. infoView[infoString.length] = 0x00;
  178. // Computes the final required size and creates the storage
  179. const totalSize = MagicBytes.length + position + infoBuffer.byteLength;
  180. const finalBuffer = new ArrayBuffer(totalSize);
  181. const finalBufferView = new Uint8Array(finalBuffer);
  182. const dataView = new DataView(finalBuffer);
  183. // Copy the magic bytes identifying the file in
  184. let pos = 0;
  185. for (let i = 0; i < MagicBytes.length; i++) {
  186. dataView.setUint8(pos++, MagicBytes[i]);
  187. }
  188. // Add the json info
  189. finalBufferView.set(new Uint8Array(infoBuffer), pos);
  190. pos += infoBuffer.byteLength;
  191. // Finally inserts the texture data
  192. for (let i = 0; i <= mipmapsCount; i++) {
  193. for (let face = 0; face < 6; face++) {
  194. const dataBuffer = specularTextures[i * 6 + face];
  195. finalBufferView.set(new Uint8Array(dataBuffer), pos);
  196. pos += dataBuffer.byteLength;
  197. }
  198. }
  199. // Voila
  200. return finalBuffer;
  201. }
  202. /**
  203. * Creates a JSON representation of the spherical data.
  204. * @param texture defines the texture containing the polynomials
  205. * @returns the JSON representation of the spherical info
  206. */
  207. function _CreateEnvTextureIrradiance(texture) {
  208. const polynmials = texture.sphericalPolynomial;
  209. if (polynmials == null) {
  210. return null;
  211. }
  212. return {
  213. x: [polynmials.x.x, polynmials.x.y, polynmials.x.z],
  214. y: [polynmials.y.x, polynmials.y.y, polynmials.y.z],
  215. z: [polynmials.z.x, polynmials.z.y, polynmials.z.z],
  216. xx: [polynmials.xx.x, polynmials.xx.y, polynmials.xx.z],
  217. yy: [polynmials.yy.x, polynmials.yy.y, polynmials.yy.z],
  218. zz: [polynmials.zz.x, polynmials.zz.y, polynmials.zz.z],
  219. yz: [polynmials.yz.x, polynmials.yz.y, polynmials.yz.z],
  220. zx: [polynmials.zx.x, polynmials.zx.y, polynmials.zx.z],
  221. xy: [polynmials.xy.x, polynmials.xy.y, polynmials.xy.z],
  222. };
  223. }
  224. /**
  225. * Creates the ArrayBufferViews used for initializing environment texture image data.
  226. * @param data the image data
  227. * @param info parameters that determine what views will be created for accessing the underlying buffer
  228. * @returns the views described by info providing access to the underlying buffer
  229. */
  230. export function CreateImageDataArrayBufferViews(data, info) {
  231. info = normalizeEnvInfo(info);
  232. const specularInfo = info.specular;
  233. // Double checks the enclosed info
  234. let mipmapsCount = Scalar.Log2(info.width);
  235. mipmapsCount = Math.round(mipmapsCount) + 1;
  236. if (specularInfo.mipmaps.length !== 6 * mipmapsCount) {
  237. throw new Error(`Unsupported specular mipmaps number "${specularInfo.mipmaps.length}"`);
  238. }
  239. const imageData = new Array(mipmapsCount);
  240. for (let i = 0; i < mipmapsCount; i++) {
  241. imageData[i] = new Array(6);
  242. for (let face = 0; face < 6; face++) {
  243. const imageInfo = specularInfo.mipmaps[i * 6 + face];
  244. imageData[i][face] = new Uint8Array(data.buffer, data.byteOffset + specularInfo.specularDataPosition + imageInfo.position, imageInfo.length);
  245. }
  246. }
  247. return imageData;
  248. }
  249. /**
  250. * Uploads the texture info contained in the env file to the GPU.
  251. * @param texture defines the internal texture to upload to
  252. * @param data defines the data to load
  253. * @param info defines the texture info retrieved through the GetEnvInfo method
  254. * @returns a promise
  255. */
  256. export function UploadEnvLevelsAsync(texture, data, info) {
  257. info = normalizeEnvInfo(info);
  258. const specularInfo = info.specular;
  259. if (!specularInfo) {
  260. // Nothing else parsed so far
  261. return Promise.resolve();
  262. }
  263. texture._lodGenerationScale = specularInfo.lodGenerationScale;
  264. const imageData = CreateImageDataArrayBufferViews(data, info);
  265. return UploadLevelsAsync(texture, imageData, info.imageType);
  266. }
  267. function _OnImageReadyAsync(image, engine, expandTexture, rgbdPostProcess, url, face, i, generateNonLODTextures, lodTextures, cubeRtt, texture) {
  268. return new Promise((resolve, reject) => {
  269. if (expandTexture) {
  270. const tempTexture = engine.createTexture(null, true, true, null, 1, null, (message) => {
  271. reject(message);
  272. }, image);
  273. rgbdPostProcess.getEffect().executeWhenCompiled(() => {
  274. // Uncompress the data to a RTT
  275. rgbdPostProcess.externalTextureSamplerBinding = true;
  276. rgbdPostProcess.onApply = (effect) => {
  277. effect._bindTexture("textureSampler", tempTexture);
  278. effect.setFloat2("scale", 1, engine._features.needsInvertingBitmap && image instanceof ImageBitmap ? -1 : 1);
  279. };
  280. if (!engine.scenes.length) {
  281. return;
  282. }
  283. engine.scenes[0].postProcessManager.directRender([rgbdPostProcess], cubeRtt, true, face, i);
  284. // Cleanup
  285. engine.restoreDefaultFramebuffer();
  286. tempTexture.dispose();
  287. URL.revokeObjectURL(url);
  288. resolve();
  289. });
  290. }
  291. else {
  292. engine._uploadImageToTexture(texture, image, face, i);
  293. // Upload the face to the non lod texture support
  294. if (generateNonLODTextures) {
  295. const lodTexture = lodTextures[i];
  296. if (lodTexture) {
  297. engine._uploadImageToTexture(lodTexture._texture, image, face, 0);
  298. }
  299. }
  300. resolve();
  301. }
  302. });
  303. }
  304. /**
  305. * Uploads the levels of image data to the GPU.
  306. * @param texture defines the internal texture to upload to
  307. * @param imageData defines the array buffer views of image data [mipmap][face]
  308. * @param imageType the mime type of the image data
  309. * @returns a promise
  310. */
  311. export function UploadLevelsAsync(texture, imageData, imageType = DefaultEnvironmentTextureImageType) {
  312. if (!Tools.IsExponentOfTwo(texture.width)) {
  313. throw new Error("Texture size must be a power of two");
  314. }
  315. const mipmapsCount = Scalar.ILog2(texture.width) + 1;
  316. // Gets everything ready.
  317. const engine = texture.getEngine();
  318. let expandTexture = false;
  319. let generateNonLODTextures = false;
  320. let rgbdPostProcess = null;
  321. let cubeRtt = null;
  322. let lodTextures = null;
  323. const caps = engine.getCaps();
  324. texture.format = 5;
  325. texture.type = 0;
  326. texture.generateMipMaps = true;
  327. texture._cachedAnisotropicFilteringLevel = null;
  328. engine.updateTextureSamplingMode(3, texture);
  329. // Add extra process if texture lod is not supported
  330. if (!caps.textureLOD) {
  331. expandTexture = false;
  332. generateNonLODTextures = true;
  333. lodTextures = {};
  334. }
  335. // in webgl 1 there are no ways to either render or copy lod level information for float textures.
  336. else if (!engine._features.supportRenderAndCopyToLodForFloatTextures) {
  337. expandTexture = false;
  338. }
  339. // If half float available we can uncompress the texture
  340. else if (caps.textureHalfFloatRender && caps.textureHalfFloatLinearFiltering) {
  341. expandTexture = true;
  342. texture.type = 2;
  343. }
  344. // If full float available we can uncompress the texture
  345. else if (caps.textureFloatRender && caps.textureFloatLinearFiltering) {
  346. expandTexture = true;
  347. texture.type = 1;
  348. }
  349. // Expand the texture if possible
  350. if (expandTexture) {
  351. // Simply run through the decode PP
  352. rgbdPostProcess = new PostProcess("rgbdDecode", "rgbdDecode", null, null, 1, null, 3, engine, false, undefined, texture.type, undefined, null, false);
  353. texture._isRGBD = false;
  354. texture.invertY = false;
  355. cubeRtt = engine.createRenderTargetCubeTexture(texture.width, {
  356. generateDepthBuffer: false,
  357. generateMipMaps: true,
  358. generateStencilBuffer: false,
  359. samplingMode: 3,
  360. type: texture.type,
  361. format: 5,
  362. });
  363. }
  364. else {
  365. texture._isRGBD = true;
  366. texture.invertY = true;
  367. // In case of missing support, applies the same patch than DDS files.
  368. if (generateNonLODTextures) {
  369. const mipSlices = 3;
  370. const scale = texture._lodGenerationScale;
  371. const offset = texture._lodGenerationOffset;
  372. for (let i = 0; i < mipSlices; i++) {
  373. //compute LOD from even spacing in smoothness (matching shader calculation)
  374. const smoothness = i / (mipSlices - 1);
  375. const roughness = 1 - smoothness;
  376. const minLODIndex = offset; // roughness = 0
  377. const maxLODIndex = (mipmapsCount - 1) * scale + offset; // roughness = 1 (mipmaps start from 0)
  378. const lodIndex = minLODIndex + (maxLODIndex - minLODIndex) * roughness;
  379. const mipmapIndex = Math.round(Math.min(Math.max(lodIndex, 0), maxLODIndex));
  380. const glTextureFromLod = new InternalTexture(engine, InternalTextureSource.Temp);
  381. glTextureFromLod.isCube = true;
  382. glTextureFromLod.invertY = true;
  383. glTextureFromLod.generateMipMaps = false;
  384. engine.updateTextureSamplingMode(2, glTextureFromLod);
  385. // Wrap in a base texture for easy binding.
  386. const lodTexture = new BaseTexture(null);
  387. lodTexture._isCube = true;
  388. lodTexture._texture = glTextureFromLod;
  389. lodTextures[mipmapIndex] = lodTexture;
  390. switch (i) {
  391. case 0:
  392. texture._lodTextureLow = lodTexture;
  393. break;
  394. case 1:
  395. texture._lodTextureMid = lodTexture;
  396. break;
  397. case 2:
  398. texture._lodTextureHigh = lodTexture;
  399. break;
  400. }
  401. }
  402. }
  403. }
  404. const promises = [];
  405. // All mipmaps up to provided number of images
  406. for (let i = 0; i < imageData.length; i++) {
  407. // All faces
  408. for (let face = 0; face < 6; face++) {
  409. // Constructs an image element from image data
  410. const bytes = imageData[i][face];
  411. const blob = new Blob([bytes], { type: imageType });
  412. const url = URL.createObjectURL(blob);
  413. let promise;
  414. if (engine._features.forceBitmapOverHTMLImageElement) {
  415. promise = engine.createImageBitmap(blob, { premultiplyAlpha: "none" }).then((img) => {
  416. return _OnImageReadyAsync(img, engine, expandTexture, rgbdPostProcess, url, face, i, generateNonLODTextures, lodTextures, cubeRtt, texture);
  417. });
  418. }
  419. else {
  420. const image = new Image();
  421. image.src = url;
  422. // Enqueue promise to upload to the texture.
  423. promise = new Promise((resolve, reject) => {
  424. image.onload = () => {
  425. _OnImageReadyAsync(image, engine, expandTexture, rgbdPostProcess, url, face, i, generateNonLODTextures, lodTextures, cubeRtt, texture)
  426. .then(() => resolve())
  427. .catch((reason) => {
  428. reject(reason);
  429. });
  430. };
  431. image.onerror = (error) => {
  432. reject(error);
  433. };
  434. });
  435. }
  436. promises.push(promise);
  437. }
  438. }
  439. // Fill remaining mipmaps with black textures.
  440. if (imageData.length < mipmapsCount) {
  441. let data;
  442. const size = Math.pow(2, mipmapsCount - 1 - imageData.length);
  443. const dataLength = size * size * 4;
  444. switch (texture.type) {
  445. case 0: {
  446. data = new Uint8Array(dataLength);
  447. break;
  448. }
  449. case 2: {
  450. data = new Uint16Array(dataLength);
  451. break;
  452. }
  453. case 1: {
  454. data = new Float32Array(dataLength);
  455. break;
  456. }
  457. }
  458. for (let i = imageData.length; i < mipmapsCount; i++) {
  459. for (let face = 0; face < 6; face++) {
  460. engine._uploadArrayBufferViewToTexture(texture, data, face, i);
  461. }
  462. }
  463. }
  464. // Once all done, finishes the cleanup and return
  465. return Promise.all(promises).then(() => {
  466. // Release temp RTT.
  467. if (cubeRtt) {
  468. engine._releaseTexture(texture);
  469. cubeRtt._swapAndDie(texture);
  470. }
  471. // Release temp Post Process.
  472. if (rgbdPostProcess) {
  473. rgbdPostProcess.dispose();
  474. }
  475. // Flag internal texture as ready in case they are in use.
  476. if (generateNonLODTextures) {
  477. if (texture._lodTextureHigh && texture._lodTextureHigh._texture) {
  478. texture._lodTextureHigh._texture.isReady = true;
  479. }
  480. if (texture._lodTextureMid && texture._lodTextureMid._texture) {
  481. texture._lodTextureMid._texture.isReady = true;
  482. }
  483. if (texture._lodTextureLow && texture._lodTextureLow._texture) {
  484. texture._lodTextureLow._texture.isReady = true;
  485. }
  486. }
  487. });
  488. }
  489. /**
  490. * Uploads spherical polynomials information to the texture.
  491. * @param texture defines the texture we are trying to upload the information to
  492. * @param info defines the environment texture info retrieved through the GetEnvInfo method
  493. */
  494. export function UploadEnvSpherical(texture, info) {
  495. info = normalizeEnvInfo(info);
  496. const irradianceInfo = info.irradiance;
  497. if (!irradianceInfo) {
  498. return;
  499. }
  500. const sp = new SphericalPolynomial();
  501. Vector3.FromArrayToRef(irradianceInfo.x, 0, sp.x);
  502. Vector3.FromArrayToRef(irradianceInfo.y, 0, sp.y);
  503. Vector3.FromArrayToRef(irradianceInfo.z, 0, sp.z);
  504. Vector3.FromArrayToRef(irradianceInfo.xx, 0, sp.xx);
  505. Vector3.FromArrayToRef(irradianceInfo.yy, 0, sp.yy);
  506. Vector3.FromArrayToRef(irradianceInfo.zz, 0, sp.zz);
  507. Vector3.FromArrayToRef(irradianceInfo.yz, 0, sp.yz);
  508. Vector3.FromArrayToRef(irradianceInfo.zx, 0, sp.zx);
  509. Vector3.FromArrayToRef(irradianceInfo.xy, 0, sp.xy);
  510. texture._sphericalPolynomial = sp;
  511. }
  512. /**
  513. * @internal
  514. */
  515. export function _UpdateRGBDAsync(internalTexture, data, sphericalPolynomial, lodScale, lodOffset) {
  516. const proxy = internalTexture
  517. .getEngine()
  518. .createRawCubeTexture(null, internalTexture.width, internalTexture.format, internalTexture.type, internalTexture.generateMipMaps, internalTexture.invertY, internalTexture.samplingMode, internalTexture._compression);
  519. const proxyPromise = UploadLevelsAsync(proxy, data).then(() => internalTexture);
  520. internalTexture.onRebuildCallback = (_internalTexture) => {
  521. return {
  522. proxy: proxyPromise,
  523. isReady: true,
  524. isAsync: true,
  525. };
  526. };
  527. internalTexture._source = InternalTextureSource.CubeRawRGBD;
  528. internalTexture._bufferViewArrayArray = data;
  529. internalTexture._lodGenerationScale = lodScale;
  530. internalTexture._lodGenerationOffset = lodOffset;
  531. internalTexture._sphericalPolynomial = sphericalPolynomial;
  532. return UploadLevelsAsync(internalTexture, data).then(() => {
  533. internalTexture.isReady = true;
  534. return internalTexture;
  535. });
  536. }
  537. /**
  538. * Sets of helpers addressing the serialization and deserialization of environment texture
  539. * stored in a BabylonJS env file.
  540. * Those files are usually stored as .env files.
  541. */
  542. export const EnvironmentTextureTools = {
  543. /**
  544. * Gets the environment info from an env file.
  545. * @param data The array buffer containing the .env bytes.
  546. * @returns the environment file info (the json header) if successfully parsed, normalized to the latest supported version.
  547. */
  548. GetEnvInfo,
  549. /**
  550. * Creates an environment texture from a loaded cube texture.
  551. * @param texture defines the cube texture to convert in env file
  552. * @param options options for the conversion process
  553. * @param options.imageType the mime type for the encoded images, with support for "image/png" (default) and "image/webp"
  554. * @param options.imageQuality the image quality of encoded WebP images.
  555. * @returns a promise containing the environment data if successful.
  556. */
  557. CreateEnvTextureAsync,
  558. /**
  559. * Creates the ArrayBufferViews used for initializing environment texture image data.
  560. * @param data the image data
  561. * @param info parameters that determine what views will be created for accessing the underlying buffer
  562. * @returns the views described by info providing access to the underlying buffer
  563. */
  564. CreateImageDataArrayBufferViews,
  565. /**
  566. * Uploads the texture info contained in the env file to the GPU.
  567. * @param texture defines the internal texture to upload to
  568. * @param data defines the data to load
  569. * @param info defines the texture info retrieved through the GetEnvInfo method
  570. * @returns a promise
  571. */
  572. UploadEnvLevelsAsync,
  573. /**
  574. * Uploads the levels of image data to the GPU.
  575. * @param texture defines the internal texture to upload to
  576. * @param imageData defines the array buffer views of image data [mipmap][face]
  577. * @param imageType the mime type of the image data
  578. * @returns a promise
  579. */
  580. UploadLevelsAsync,
  581. /**
  582. * Uploads spherical polynomials information to the texture.
  583. * @param texture defines the texture we are trying to upload the information to
  584. * @param info defines the environment texture info retrieved through the GetEnvInfo method
  585. */
  586. UploadEnvSpherical,
  587. };
  588. //# sourceMappingURL=environmentTextureTools.js.map