@spiffcommerce/preview 3.6.2-rc.8 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.esm.js +1576 -38
- package/dist/index.umd.js +1 -0
- package/package.json +4 -6
- package/dist/_tslib.esm.js +0 -33
- package/dist/animation.esm.js +0 -1364
- package/dist/assetCache.esm.js +0 -6
- package/dist/assetCache.esm2.js +0 -825
- package/dist/blurPostProcess.esm.js +0 -327
- package/dist/bumpVertex.esm.js +0 -497
- package/dist/compatibilityOptions.esm.js +0 -68
- package/dist/configuration.esm.js +0 -121
- package/dist/core.esm.js +0 -8135
- package/dist/dynamicTexture.esm.js +0 -105
- package/dist/dynamicTexture.esm2.js +0 -238
- package/dist/easing.esm.js +0 -130
- package/dist/effectFallbacks.esm.js +0 -378
- package/dist/engine.esm.js +0 -25504
- package/dist/glbLoaderExtensions.esm.js +0 -690
- package/dist/glowLayer.esm.js +0 -1621
- package/dist/glowLayerManager.esm.js +0 -50
- package/dist/guid.esm.js +0 -21
- package/dist/hdrFilteringFunctions.esm.js +0 -816
- package/dist/helperFunctions.esm.js +0 -5145
- package/dist/material.esm.js +0 -115
- package/dist/material.esm2.js +0 -5245
- package/dist/math.axis.esm.js +0 -35
- package/dist/math.color.esm.js +0 -1661
- package/dist/math.path.esm.js +0 -15
- package/dist/math.size.esm.js +0 -137
- package/dist/mesh.esm.js +0 -11170
- package/dist/modelContainer.esm.js +0 -1895
- package/dist/node.esm.js +0 -795
- package/dist/pbrBRDFFunctions.esm.js +0 -124
- package/dist/pbrMaterial.esm.js +8 -8739
- package/dist/productAnimations.esm.js +0 -182
- package/dist/productCamera.esm.js +0 -14
- package/dist/productCamera.esm2.js +0 -3870
- package/dist/renderConstants.esm.js +0 -116
- package/dist/renderingPipeline.esm.js +0 -18
- package/dist/renderingPipeline.esm2.js +1 -3594
- package/dist/sceneLoaderFlags.esm.js +0 -51
- package/dist/types.esm.js +0 -30
- package/dist/variants.esm.js +0 -16
- package/dist/variants.esm2.js +0 -3097
- package/dist/webRequest.esm.js +0 -7777
package/dist/variants.esm2.js
DELETED
|
@@ -1,3097 +0,0 @@
|
|
|
1
|
-
import { _ as __awaiter } from './_tslib.esm.js';
|
|
2
|
-
import { S as SceneLoader, g as getAssetContainer } from './assetCache.esm2.js';
|
|
3
|
-
import { T as ThinEngine, I as InternalTexture, a as InternalTextureSource, L as Logger, q as RandomGUID, r as LoadImage, c as Tools, e as ShaderStore } from './engine.esm.js';
|
|
4
|
-
import { _ as __decorate, M as Matrix, O as Observable, V as Vector3, T as TmpVectors, S as SerializationHelper, s as serialize, d as serializeAsVector3, k as serializeAsMatrix, E as EngineStore } from './webRequest.esm.js';
|
|
5
|
-
import { T as Texture, B as BaseTexture, E as EffectWrapper, a as EffectRenderer } from './helperFunctions.esm.js';
|
|
6
|
-
import { G as GetClass, R as RegisterClass, S as Scalar, b as ToGammaSpace } from './math.color.esm.js';
|
|
7
|
-
import { C as CubeMapToSphericalPolynomialTools, T as ToHalfFloat } from './hdrFilteringFunctions.esm.js';
|
|
8
|
-
import './math.axis.esm.js';
|
|
9
|
-
import './math.path.esm.js';
|
|
10
|
-
import './pbrBRDFFunctions.esm.js';
|
|
11
|
-
import { calculateMaterialProperties, applyDownloadedTexture } from './material.esm.js';
|
|
12
|
-
|
|
13
|
-
ThinEngine.prototype._createDepthStencilCubeTexture = function (size, options, rtWrapper) {
|
|
14
|
-
const internalTexture = new InternalTexture(this, InternalTextureSource.DepthStencil);
|
|
15
|
-
internalTexture.isCube = true;
|
|
16
|
-
if (this.webGLVersion === 1) {
|
|
17
|
-
Logger.Error("Depth cube texture is not supported by WebGL 1.");
|
|
18
|
-
return internalTexture;
|
|
19
|
-
}
|
|
20
|
-
const internalOptions = Object.assign({ bilinearFiltering: false, comparisonFunction: 0, generateStencil: false }, options);
|
|
21
|
-
const gl = this._gl;
|
|
22
|
-
this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, internalTexture, true);
|
|
23
|
-
this._setupDepthStencilTexture(internalTexture, size, internalOptions.generateStencil, internalOptions.bilinearFiltering, internalOptions.comparisonFunction);
|
|
24
|
-
rtWrapper._depthStencilTexture = internalTexture;
|
|
25
|
-
rtWrapper._depthStencilTextureWithStencil = internalOptions.generateStencil;
|
|
26
|
-
// Create the depth/stencil buffer
|
|
27
|
-
for (let face = 0; face < 6; face++) {
|
|
28
|
-
if (internalOptions.generateStencil) {
|
|
29
|
-
gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, gl.DEPTH24_STENCIL8, size, size, 0, gl.DEPTH_STENCIL, gl.UNSIGNED_INT_24_8, null);
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
32
|
-
gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, gl.DEPTH_COMPONENT24, size, size, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_INT, null);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, null);
|
|
36
|
-
this._internalTexturesCache.push(internalTexture);
|
|
37
|
-
return internalTexture;
|
|
38
|
-
};
|
|
39
|
-
ThinEngine.prototype._partialLoadFile = function (url, index, loadedFiles, onfinish, onErrorCallBack = null) {
|
|
40
|
-
const onload = (data) => {
|
|
41
|
-
loadedFiles[index] = data;
|
|
42
|
-
loadedFiles._internalCount++;
|
|
43
|
-
if (loadedFiles._internalCount === 6) {
|
|
44
|
-
onfinish(loadedFiles);
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
const onerror = (request, exception) => {
|
|
48
|
-
if (onErrorCallBack && request) {
|
|
49
|
-
onErrorCallBack(request.status + " " + request.statusText, exception);
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
this._loadFile(url, onload, undefined, undefined, true, onerror);
|
|
53
|
-
};
|
|
54
|
-
ThinEngine.prototype._cascadeLoadFiles = function (scene, onfinish, files, onError = null) {
|
|
55
|
-
const loadedFiles = [];
|
|
56
|
-
loadedFiles._internalCount = 0;
|
|
57
|
-
for (let index = 0; index < 6; index++) {
|
|
58
|
-
this._partialLoadFile(files[index], index, loadedFiles, onfinish, onError);
|
|
59
|
-
}
|
|
60
|
-
};
|
|
61
|
-
ThinEngine.prototype._cascadeLoadImgs = function (scene, texture, onfinish, files, onError = null, mimeType) {
|
|
62
|
-
const loadedImages = [];
|
|
63
|
-
loadedImages._internalCount = 0;
|
|
64
|
-
for (let index = 0; index < 6; index++) {
|
|
65
|
-
this._partialLoadImg(files[index], index, loadedImages, scene, texture, onfinish, onError, mimeType);
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
ThinEngine.prototype._partialLoadImg = function (url, index, loadedImages, scene, texture, onfinish, onErrorCallBack = null, mimeType) {
|
|
69
|
-
const tokenPendingData = RandomGUID();
|
|
70
|
-
const onload = (img) => {
|
|
71
|
-
loadedImages[index] = img;
|
|
72
|
-
loadedImages._internalCount++;
|
|
73
|
-
if (scene) {
|
|
74
|
-
scene.removePendingData(tokenPendingData);
|
|
75
|
-
}
|
|
76
|
-
if (loadedImages._internalCount === 6 && onfinish) {
|
|
77
|
-
onfinish(texture, loadedImages);
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
const onerror = (message, exception) => {
|
|
81
|
-
if (scene) {
|
|
82
|
-
scene.removePendingData(tokenPendingData);
|
|
83
|
-
}
|
|
84
|
-
if (onErrorCallBack) {
|
|
85
|
-
onErrorCallBack(message, exception);
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
LoadImage(url, onload, onerror, scene ? scene.offlineProvider : null, mimeType);
|
|
89
|
-
if (scene) {
|
|
90
|
-
scene.addPendingData(tokenPendingData);
|
|
91
|
-
}
|
|
92
|
-
};
|
|
93
|
-
ThinEngine.prototype._setCubeMapTextureParams = function (texture, loadMipmap, maxLevel) {
|
|
94
|
-
const gl = this._gl;
|
|
95
|
-
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
96
|
-
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, loadMipmap ? gl.LINEAR_MIPMAP_LINEAR : gl.LINEAR);
|
|
97
|
-
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
98
|
-
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
99
|
-
texture.samplingMode = loadMipmap ? 3 : 2;
|
|
100
|
-
if (loadMipmap && this.getCaps().textureMaxLevel && maxLevel !== undefined && maxLevel > 0) {
|
|
101
|
-
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAX_LEVEL, maxLevel);
|
|
102
|
-
texture._maxLodLevel = maxLevel;
|
|
103
|
-
}
|
|
104
|
-
this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, null);
|
|
105
|
-
};
|
|
106
|
-
ThinEngine.prototype.createCubeTextureBase = function (rootUrl, scene, files, noMipmap, onLoad = null, onError = null, format, forcedExtension = null, createPolynomials = false, lodScale = 0, lodOffset = 0, fallback = null, beforeLoadCubeDataCallback = null, imageHandler = null, useSRGBBuffer = false) {
|
|
107
|
-
const texture = fallback ? fallback : new InternalTexture(this, InternalTextureSource.Cube);
|
|
108
|
-
texture.isCube = true;
|
|
109
|
-
texture.url = rootUrl;
|
|
110
|
-
texture.generateMipMaps = !noMipmap;
|
|
111
|
-
texture._lodGenerationScale = lodScale;
|
|
112
|
-
texture._lodGenerationOffset = lodOffset;
|
|
113
|
-
texture._useSRGBBuffer = !!useSRGBBuffer && this._caps.supportSRGBBuffers && (this.webGLVersion > 1 || this.isWebGPU || !!noMipmap);
|
|
114
|
-
if (texture !== fallback) {
|
|
115
|
-
texture.label = rootUrl.substring(0, 60); // default label, can be overriden by the caller
|
|
116
|
-
}
|
|
117
|
-
if (!this._doNotHandleContextLost) {
|
|
118
|
-
texture._extension = forcedExtension;
|
|
119
|
-
texture._files = files;
|
|
120
|
-
}
|
|
121
|
-
const originalRootUrl = rootUrl;
|
|
122
|
-
if (this._transformTextureUrl && !fallback) {
|
|
123
|
-
rootUrl = this._transformTextureUrl(rootUrl);
|
|
124
|
-
}
|
|
125
|
-
const rootUrlWithoutUriParams = rootUrl.split("?")[0];
|
|
126
|
-
const lastDot = rootUrlWithoutUriParams.lastIndexOf(".");
|
|
127
|
-
const extension = forcedExtension ? forcedExtension : lastDot > -1 ? rootUrlWithoutUriParams.substring(lastDot).toLowerCase() : "";
|
|
128
|
-
let loader = null;
|
|
129
|
-
for (const availableLoader of ThinEngine._TextureLoaders) {
|
|
130
|
-
if (availableLoader.canLoad(extension)) {
|
|
131
|
-
loader = availableLoader;
|
|
132
|
-
break;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
const onInternalError = (request, exception) => {
|
|
136
|
-
if (rootUrl === originalRootUrl) {
|
|
137
|
-
if (onError && request) {
|
|
138
|
-
onError(request.status + " " + request.statusText, exception);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
else {
|
|
142
|
-
// fall back to the original url if the transformed url fails to load
|
|
143
|
-
Logger.Warn(`Failed to load ${rootUrl}, falling back to the ${originalRootUrl}`);
|
|
144
|
-
this.createCubeTextureBase(originalRootUrl, scene, files, !!noMipmap, onLoad, onError, format, forcedExtension, createPolynomials, lodScale, lodOffset, texture, beforeLoadCubeDataCallback, imageHandler, useSRGBBuffer);
|
|
145
|
-
}
|
|
146
|
-
};
|
|
147
|
-
if (loader) {
|
|
148
|
-
const onloaddata = (data) => {
|
|
149
|
-
if (beforeLoadCubeDataCallback) {
|
|
150
|
-
beforeLoadCubeDataCallback(texture, data);
|
|
151
|
-
}
|
|
152
|
-
loader.loadCubeData(data, texture, createPolynomials, onLoad, onError);
|
|
153
|
-
};
|
|
154
|
-
if (files && files.length === 6) {
|
|
155
|
-
if (loader.supportCascades) {
|
|
156
|
-
this._cascadeLoadFiles(scene, (images) => onloaddata(images.map((image) => new Uint8Array(image))), files, onError);
|
|
157
|
-
}
|
|
158
|
-
else {
|
|
159
|
-
if (onError) {
|
|
160
|
-
onError("Textures type does not support cascades.");
|
|
161
|
-
}
|
|
162
|
-
else {
|
|
163
|
-
Logger.Warn("Texture loader does not support cascades.");
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
else {
|
|
168
|
-
this._loadFile(rootUrl, (data) => onloaddata(new Uint8Array(data)), undefined, undefined, true, onInternalError);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
else {
|
|
172
|
-
if (!files) {
|
|
173
|
-
throw new Error("Cannot load cubemap because files were not defined");
|
|
174
|
-
}
|
|
175
|
-
this._cascadeLoadImgs(scene, texture, (texture, imgs) => {
|
|
176
|
-
if (imageHandler) {
|
|
177
|
-
imageHandler(texture, imgs);
|
|
178
|
-
}
|
|
179
|
-
}, files, onError);
|
|
180
|
-
}
|
|
181
|
-
this._internalTexturesCache.push(texture);
|
|
182
|
-
return texture;
|
|
183
|
-
};
|
|
184
|
-
ThinEngine.prototype.createCubeTexture = function (rootUrl, scene, files, noMipmap, onLoad = null, onError = null, format, forcedExtension = null, createPolynomials = false, lodScale = 0, lodOffset = 0, fallback = null, loaderOptions, useSRGBBuffer = false) {
|
|
185
|
-
const gl = this._gl;
|
|
186
|
-
return this.createCubeTextureBase(rootUrl, scene, files, !!noMipmap, onLoad, onError, format, forcedExtension, createPolynomials, lodScale, lodOffset, fallback, (texture) => this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, texture, true), (texture, imgs) => {
|
|
187
|
-
const width = this.needPOTTextures ? ThinEngine.GetExponentOfTwo(imgs[0].width, this._caps.maxCubemapTextureSize) : imgs[0].width;
|
|
188
|
-
const height = width;
|
|
189
|
-
const faces = [
|
|
190
|
-
gl.TEXTURE_CUBE_MAP_POSITIVE_X,
|
|
191
|
-
gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
|
|
192
|
-
gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
|
|
193
|
-
gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
|
|
194
|
-
gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
|
|
195
|
-
gl.TEXTURE_CUBE_MAP_NEGATIVE_Z,
|
|
196
|
-
];
|
|
197
|
-
this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, texture, true);
|
|
198
|
-
this._unpackFlipY(false);
|
|
199
|
-
const internalFormat = format ? this._getInternalFormat(format, texture._useSRGBBuffer) : texture._useSRGBBuffer ? this._glSRGBExtensionValues.SRGB8_ALPHA8 : gl.RGBA;
|
|
200
|
-
let texelFormat = format ? this._getInternalFormat(format) : gl.RGBA;
|
|
201
|
-
if (texture._useSRGBBuffer && this.webGLVersion === 1) {
|
|
202
|
-
texelFormat = internalFormat;
|
|
203
|
-
}
|
|
204
|
-
for (let index = 0; index < faces.length; index++) {
|
|
205
|
-
if (imgs[index].width !== width || imgs[index].height !== height) {
|
|
206
|
-
this._prepareWorkingCanvas();
|
|
207
|
-
if (!this._workingCanvas || !this._workingContext) {
|
|
208
|
-
Logger.Warn("Cannot create canvas to resize texture.");
|
|
209
|
-
return;
|
|
210
|
-
}
|
|
211
|
-
this._workingCanvas.width = width;
|
|
212
|
-
this._workingCanvas.height = height;
|
|
213
|
-
this._workingContext.drawImage(imgs[index], 0, 0, imgs[index].width, imgs[index].height, 0, 0, width, height);
|
|
214
|
-
gl.texImage2D(faces[index], 0, internalFormat, texelFormat, gl.UNSIGNED_BYTE, this._workingCanvas);
|
|
215
|
-
}
|
|
216
|
-
else {
|
|
217
|
-
gl.texImage2D(faces[index], 0, internalFormat, texelFormat, gl.UNSIGNED_BYTE, imgs[index]);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
if (!noMipmap) {
|
|
221
|
-
gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
|
|
222
|
-
}
|
|
223
|
-
this._setCubeMapTextureParams(texture, !noMipmap);
|
|
224
|
-
texture.width = width;
|
|
225
|
-
texture.height = height;
|
|
226
|
-
texture.isReady = true;
|
|
227
|
-
if (format) {
|
|
228
|
-
texture.format = format;
|
|
229
|
-
}
|
|
230
|
-
texture.onLoadedObservable.notifyObservers(texture);
|
|
231
|
-
texture.onLoadedObservable.clear();
|
|
232
|
-
if (onLoad) {
|
|
233
|
-
onLoad();
|
|
234
|
-
}
|
|
235
|
-
}, !!useSRGBBuffer);
|
|
236
|
-
};
|
|
237
|
-
|
|
238
|
-
/**
|
|
239
|
-
* Class for creating a cube texture
|
|
240
|
-
*/
|
|
241
|
-
class CubeTexture extends BaseTexture {
|
|
242
|
-
/**
|
|
243
|
-
* Gets or sets the size of the bounding box associated with the cube texture
|
|
244
|
-
* When defined, the cubemap will switch to local mode
|
|
245
|
-
* @see https://community.arm.com/graphics/b/blog/posts/reflections-based-on-local-cubemaps-in-unity
|
|
246
|
-
* @example https://www.babylonjs-playground.com/#RNASML
|
|
247
|
-
*/
|
|
248
|
-
set boundingBoxSize(value) {
|
|
249
|
-
if (this._boundingBoxSize && this._boundingBoxSize.equals(value)) {
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
|
-
this._boundingBoxSize = value;
|
|
253
|
-
const scene = this.getScene();
|
|
254
|
-
if (scene) {
|
|
255
|
-
scene.markAllMaterialsAsDirty(1);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
/**
|
|
259
|
-
* Returns the bounding box size
|
|
260
|
-
* @see https://doc.babylonjs.com/features/featuresDeepDive/materials/using/reflectionTexture#using-local-cubemap-mode
|
|
261
|
-
*/
|
|
262
|
-
get boundingBoxSize() {
|
|
263
|
-
return this._boundingBoxSize;
|
|
264
|
-
}
|
|
265
|
-
/**
|
|
266
|
-
* Sets texture matrix rotation angle around Y axis in radians.
|
|
267
|
-
*/
|
|
268
|
-
set rotationY(value) {
|
|
269
|
-
this._rotationY = value;
|
|
270
|
-
this.setReflectionTextureMatrix(Matrix.RotationY(this._rotationY));
|
|
271
|
-
}
|
|
272
|
-
/**
|
|
273
|
-
* Gets texture matrix rotation angle around Y axis radians.
|
|
274
|
-
*/
|
|
275
|
-
get rotationY() {
|
|
276
|
-
return this._rotationY;
|
|
277
|
-
}
|
|
278
|
-
/**
|
|
279
|
-
* Are mip maps generated for this texture or not.
|
|
280
|
-
*/
|
|
281
|
-
get noMipmap() {
|
|
282
|
-
return this._noMipmap;
|
|
283
|
-
}
|
|
284
|
-
/**
|
|
285
|
-
* Gets the forced extension (if any)
|
|
286
|
-
*/
|
|
287
|
-
get forcedExtension() {
|
|
288
|
-
return this._forcedExtension;
|
|
289
|
-
}
|
|
290
|
-
/**
|
|
291
|
-
* Creates a cube texture from an array of image urls
|
|
292
|
-
* @param files defines an array of image urls
|
|
293
|
-
* @param scene defines the hosting scene
|
|
294
|
-
* @param noMipmap specifies if mip maps are not used
|
|
295
|
-
* @returns a cube texture
|
|
296
|
-
*/
|
|
297
|
-
static CreateFromImages(files, scene, noMipmap) {
|
|
298
|
-
let rootUrlKey = "";
|
|
299
|
-
files.forEach((url) => (rootUrlKey += url));
|
|
300
|
-
return new CubeTexture(rootUrlKey, scene, null, noMipmap, files);
|
|
301
|
-
}
|
|
302
|
-
/**
|
|
303
|
-
* Creates and return a texture created from prefilterd data by tools like IBL Baker or Lys.
|
|
304
|
-
* @param url defines the url of the prefiltered texture
|
|
305
|
-
* @param scene defines the scene the texture is attached to
|
|
306
|
-
* @param forcedExtension defines the extension of the file if different from the url
|
|
307
|
-
* @param createPolynomials defines whether or not to create polynomial harmonics from the texture data if necessary
|
|
308
|
-
* @returns the prefiltered texture
|
|
309
|
-
*/
|
|
310
|
-
static CreateFromPrefilteredData(url, scene, forcedExtension = null, createPolynomials = true) {
|
|
311
|
-
const oldValue = scene.useDelayedTextureLoading;
|
|
312
|
-
scene.useDelayedTextureLoading = false;
|
|
313
|
-
const result = new CubeTexture(url, scene, null, false, null, null, null, undefined, true, forcedExtension, createPolynomials);
|
|
314
|
-
scene.useDelayedTextureLoading = oldValue;
|
|
315
|
-
return result;
|
|
316
|
-
}
|
|
317
|
-
/**
|
|
318
|
-
* Creates a cube texture to use with reflection for instance. It can be based upon dds or six images as well
|
|
319
|
-
* as prefiltered data.
|
|
320
|
-
* @param rootUrl defines the url of the texture or the root name of the six images
|
|
321
|
-
* @param sceneOrEngine defines the scene or engine the texture is attached to
|
|
322
|
-
* @param extensions defines the suffixes add to the picture name in case six images are in use like _px.jpg...
|
|
323
|
-
* @param noMipmap defines if mipmaps should be created or not
|
|
324
|
-
* @param files defines the six files to load for the different faces in that order: px, py, pz, nx, ny, nz
|
|
325
|
-
* @param onLoad defines a callback triggered at the end of the file load if no errors occurred
|
|
326
|
-
* @param onError defines a callback triggered in case of error during load
|
|
327
|
-
* @param format defines the internal format to use for the texture once loaded
|
|
328
|
-
* @param prefiltered defines whether or not the texture is created from prefiltered data
|
|
329
|
-
* @param forcedExtension defines the extensions to use (force a special type of file to load) in case it is different from the file name
|
|
330
|
-
* @param createPolynomials defines whether or not to create polynomial harmonics from the texture data if necessary
|
|
331
|
-
* @param lodScale defines the scale applied to environment texture. This manages the range of LOD level used for IBL according to the roughness
|
|
332
|
-
* @param lodOffset defines the offset applied to environment texture. This manages first LOD level used for IBL according to the roughness
|
|
333
|
-
* @param loaderOptions options to be passed to the loader
|
|
334
|
-
* @param useSRGBBuffer Defines if the texture must be loaded in a sRGB GPU buffer (if supported by the GPU) (default: false)
|
|
335
|
-
* @returns the cube texture
|
|
336
|
-
*/
|
|
337
|
-
constructor(rootUrl, sceneOrEngine, extensions = null, noMipmap = false, files = null, onLoad = null, onError = null, format = 5, prefiltered = false, forcedExtension = null, createPolynomials = false, lodScale = 0.8, lodOffset = 0, loaderOptions, useSRGBBuffer) {
|
|
338
|
-
var _a;
|
|
339
|
-
super(sceneOrEngine);
|
|
340
|
-
this._lodScale = 0.8;
|
|
341
|
-
this._lodOffset = 0;
|
|
342
|
-
/**
|
|
343
|
-
* Observable triggered once the texture has been loaded.
|
|
344
|
-
*/
|
|
345
|
-
this.onLoadObservable = new Observable();
|
|
346
|
-
/**
|
|
347
|
-
* Gets or sets the center of the bounding box associated with the cube texture.
|
|
348
|
-
* It must define where the camera used to render the texture was set
|
|
349
|
-
* @see https://doc.babylonjs.com/features/featuresDeepDive/materials/using/reflectionTexture#using-local-cubemap-mode
|
|
350
|
-
*/
|
|
351
|
-
this.boundingBoxPosition = Vector3.Zero();
|
|
352
|
-
this._rotationY = 0;
|
|
353
|
-
/** @internal */
|
|
354
|
-
this._files = null;
|
|
355
|
-
this._forcedExtension = null;
|
|
356
|
-
this._extensions = null;
|
|
357
|
-
this._textureMatrixRefraction = new Matrix();
|
|
358
|
-
this.name = rootUrl;
|
|
359
|
-
this.url = rootUrl;
|
|
360
|
-
this._noMipmap = noMipmap;
|
|
361
|
-
this.hasAlpha = false;
|
|
362
|
-
this._format = format;
|
|
363
|
-
this.isCube = true;
|
|
364
|
-
this._textureMatrix = Matrix.Identity();
|
|
365
|
-
this._createPolynomials = createPolynomials;
|
|
366
|
-
this.coordinatesMode = Texture.CUBIC_MODE;
|
|
367
|
-
this._extensions = extensions;
|
|
368
|
-
this._files = files;
|
|
369
|
-
this._forcedExtension = forcedExtension;
|
|
370
|
-
this._loaderOptions = loaderOptions;
|
|
371
|
-
this._useSRGBBuffer = useSRGBBuffer;
|
|
372
|
-
this._lodScale = lodScale;
|
|
373
|
-
this._lodOffset = lodOffset;
|
|
374
|
-
if (!rootUrl && !files) {
|
|
375
|
-
return;
|
|
376
|
-
}
|
|
377
|
-
this.updateURL(rootUrl, forcedExtension, onLoad, prefiltered, onError, extensions, (_a = this.getScene()) === null || _a === void 0 ? void 0 : _a.useDelayedTextureLoading, files);
|
|
378
|
-
}
|
|
379
|
-
/**
|
|
380
|
-
* Get the current class name of the texture useful for serialization or dynamic coding.
|
|
381
|
-
* @returns "CubeTexture"
|
|
382
|
-
*/
|
|
383
|
-
getClassName() {
|
|
384
|
-
return "CubeTexture";
|
|
385
|
-
}
|
|
386
|
-
/**
|
|
387
|
-
* Update the url (and optional buffer) of this texture if url was null during construction.
|
|
388
|
-
* @param url the url of the texture
|
|
389
|
-
* @param forcedExtension defines the extension to use
|
|
390
|
-
* @param onLoad callback called when the texture is loaded (defaults to null)
|
|
391
|
-
* @param prefiltered Defines whether the updated texture is prefiltered or not
|
|
392
|
-
* @param onError callback called if there was an error during the loading process (defaults to null)
|
|
393
|
-
* @param extensions defines the suffixes add to the picture name in case six images are in use like _px.jpg...
|
|
394
|
-
* @param delayLoad defines if the texture should be loaded now (false by default)
|
|
395
|
-
* @param files defines the six files to load for the different faces in that order: px, py, pz, nx, ny, nz
|
|
396
|
-
*/
|
|
397
|
-
updateURL(url, forcedExtension, onLoad = null, prefiltered = false, onError = null, extensions = null, delayLoad = false, files = null) {
|
|
398
|
-
if (!this.name || this.name.startsWith("data:")) {
|
|
399
|
-
this.name = url;
|
|
400
|
-
}
|
|
401
|
-
this.url = url;
|
|
402
|
-
if (forcedExtension) {
|
|
403
|
-
this._forcedExtension = forcedExtension;
|
|
404
|
-
}
|
|
405
|
-
const lastDot = url.lastIndexOf(".");
|
|
406
|
-
const extension = forcedExtension ? forcedExtension : lastDot > -1 ? url.substring(lastDot).toLowerCase() : "";
|
|
407
|
-
const isDDS = extension.indexOf(".dds") === 0;
|
|
408
|
-
const isEnv = extension.indexOf(".env") === 0;
|
|
409
|
-
const isBasis = extension.indexOf(".basis") === 0;
|
|
410
|
-
if (isEnv) {
|
|
411
|
-
this.gammaSpace = false;
|
|
412
|
-
this._prefiltered = false;
|
|
413
|
-
this.anisotropicFilteringLevel = 1;
|
|
414
|
-
}
|
|
415
|
-
else {
|
|
416
|
-
this._prefiltered = prefiltered;
|
|
417
|
-
if (prefiltered) {
|
|
418
|
-
this.gammaSpace = false;
|
|
419
|
-
this.anisotropicFilteringLevel = 1;
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
if (files) {
|
|
423
|
-
this._files = files;
|
|
424
|
-
}
|
|
425
|
-
else {
|
|
426
|
-
if (!isBasis && !isEnv && !isDDS && !extensions) {
|
|
427
|
-
extensions = ["_px.jpg", "_py.jpg", "_pz.jpg", "_nx.jpg", "_ny.jpg", "_nz.jpg"];
|
|
428
|
-
}
|
|
429
|
-
this._files = this._files || [];
|
|
430
|
-
this._files.length = 0;
|
|
431
|
-
if (extensions) {
|
|
432
|
-
for (let index = 0; index < extensions.length; index++) {
|
|
433
|
-
this._files.push(url + extensions[index]);
|
|
434
|
-
}
|
|
435
|
-
this._extensions = extensions;
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
if (delayLoad) {
|
|
439
|
-
this.delayLoadState = 4;
|
|
440
|
-
this._delayedOnLoad = onLoad;
|
|
441
|
-
this._delayedOnError = onError;
|
|
442
|
-
}
|
|
443
|
-
else {
|
|
444
|
-
this._loadTexture(onLoad, onError);
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
/**
|
|
448
|
-
* Delays loading of the cube texture
|
|
449
|
-
* @param forcedExtension defines the extension to use
|
|
450
|
-
*/
|
|
451
|
-
delayLoad(forcedExtension) {
|
|
452
|
-
if (this.delayLoadState !== 4) {
|
|
453
|
-
return;
|
|
454
|
-
}
|
|
455
|
-
if (forcedExtension) {
|
|
456
|
-
this._forcedExtension = forcedExtension;
|
|
457
|
-
}
|
|
458
|
-
this.delayLoadState = 1;
|
|
459
|
-
this._loadTexture(this._delayedOnLoad, this._delayedOnError);
|
|
460
|
-
}
|
|
461
|
-
/**
|
|
462
|
-
* Returns the reflection texture matrix
|
|
463
|
-
* @returns the reflection texture matrix
|
|
464
|
-
*/
|
|
465
|
-
getReflectionTextureMatrix() {
|
|
466
|
-
return this._textureMatrix;
|
|
467
|
-
}
|
|
468
|
-
/**
|
|
469
|
-
* Sets the reflection texture matrix
|
|
470
|
-
* @param value Reflection texture matrix
|
|
471
|
-
*/
|
|
472
|
-
setReflectionTextureMatrix(value) {
|
|
473
|
-
var _a, _b;
|
|
474
|
-
if (value.updateFlag === this._textureMatrix.updateFlag) {
|
|
475
|
-
return;
|
|
476
|
-
}
|
|
477
|
-
if (value.isIdentity() !== this._textureMatrix.isIdentity()) {
|
|
478
|
-
(_a = this.getScene()) === null || _a === void 0 ? void 0 : _a.markAllMaterialsAsDirty(1, (mat) => mat.getActiveTextures().indexOf(this) !== -1);
|
|
479
|
-
}
|
|
480
|
-
this._textureMatrix = value;
|
|
481
|
-
if (!((_b = this.getScene()) === null || _b === void 0 ? void 0 : _b.useRightHandedSystem)) {
|
|
482
|
-
return;
|
|
483
|
-
}
|
|
484
|
-
const scale = TmpVectors.Vector3[0];
|
|
485
|
-
const quat = TmpVectors.Quaternion[0];
|
|
486
|
-
const trans = TmpVectors.Vector3[1];
|
|
487
|
-
this._textureMatrix.decompose(scale, quat, trans);
|
|
488
|
-
quat.z *= -1; // these two operations correspond to negating the x and y euler angles
|
|
489
|
-
quat.w *= -1;
|
|
490
|
-
Matrix.ComposeToRef(scale, quat, trans, this._textureMatrixRefraction);
|
|
491
|
-
}
|
|
492
|
-
/**
|
|
493
|
-
* Gets a suitable rotate/transform matrix when the texture is used for refraction.
|
|
494
|
-
* There's a separate function from getReflectionTextureMatrix because refraction requires a special configuration of the matrix in right-handed mode.
|
|
495
|
-
* @returns The refraction matrix
|
|
496
|
-
*/
|
|
497
|
-
getRefractionTextureMatrix() {
|
|
498
|
-
var _a;
|
|
499
|
-
return ((_a = this.getScene()) === null || _a === void 0 ? void 0 : _a.useRightHandedSystem) ? this._textureMatrixRefraction : this._textureMatrix;
|
|
500
|
-
}
|
|
501
|
-
_loadTexture(onLoad = null, onError = null) {
|
|
502
|
-
var _a;
|
|
503
|
-
const scene = this.getScene();
|
|
504
|
-
const oldTexture = this._texture;
|
|
505
|
-
this._texture = this._getFromCache(this.url, this._noMipmap, undefined, undefined, this._useSRGBBuffer, this.isCube);
|
|
506
|
-
const onLoadProcessing = () => {
|
|
507
|
-
var _a;
|
|
508
|
-
this.onLoadObservable.notifyObservers(this);
|
|
509
|
-
if (oldTexture) {
|
|
510
|
-
oldTexture.dispose();
|
|
511
|
-
(_a = this.getScene()) === null || _a === void 0 ? void 0 : _a.markAllMaterialsAsDirty(1);
|
|
512
|
-
}
|
|
513
|
-
if (onLoad) {
|
|
514
|
-
onLoad();
|
|
515
|
-
}
|
|
516
|
-
};
|
|
517
|
-
const errorHandler = (message, exception) => {
|
|
518
|
-
this._loadingError = true;
|
|
519
|
-
this._errorObject = { message, exception };
|
|
520
|
-
if (onError) {
|
|
521
|
-
onError(message, exception);
|
|
522
|
-
}
|
|
523
|
-
Texture.OnTextureLoadErrorObservable.notifyObservers(this);
|
|
524
|
-
};
|
|
525
|
-
if (!this._texture) {
|
|
526
|
-
if (this._prefiltered) {
|
|
527
|
-
this._texture = this._getEngine().createPrefilteredCubeTexture(this.url, scene, this._lodScale, this._lodOffset, onLoad, errorHandler, this._format, this._forcedExtension, this._createPolynomials);
|
|
528
|
-
}
|
|
529
|
-
else {
|
|
530
|
-
this._texture = this._getEngine().createCubeTexture(this.url, scene, this._files, this._noMipmap, onLoad, errorHandler, this._format, this._forcedExtension, false, this._lodScale, this._lodOffset, null, this._loaderOptions, !!this._useSRGBBuffer);
|
|
531
|
-
}
|
|
532
|
-
(_a = this._texture) === null || _a === void 0 ? void 0 : _a.onLoadedObservable.add(() => this.onLoadObservable.notifyObservers(this));
|
|
533
|
-
}
|
|
534
|
-
else {
|
|
535
|
-
if (this._texture.isReady) {
|
|
536
|
-
Tools.SetImmediate(() => onLoadProcessing());
|
|
537
|
-
}
|
|
538
|
-
else {
|
|
539
|
-
this._texture.onLoadedObservable.add(() => onLoadProcessing());
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
/**
|
|
544
|
-
* Parses text to create a cube texture
|
|
545
|
-
* @param parsedTexture define the serialized text to read from
|
|
546
|
-
* @param scene defines the hosting scene
|
|
547
|
-
* @param rootUrl defines the root url of the cube texture
|
|
548
|
-
* @returns a cube texture
|
|
549
|
-
*/
|
|
550
|
-
static Parse(parsedTexture, scene, rootUrl) {
|
|
551
|
-
const texture = SerializationHelper.Parse(() => {
|
|
552
|
-
var _a;
|
|
553
|
-
let prefiltered = false;
|
|
554
|
-
if (parsedTexture.prefiltered) {
|
|
555
|
-
prefiltered = parsedTexture.prefiltered;
|
|
556
|
-
}
|
|
557
|
-
return new CubeTexture(rootUrl + ((_a = parsedTexture.url) !== null && _a !== void 0 ? _a : parsedTexture.name), scene, parsedTexture.extensions, false, parsedTexture.files || null, null, null, undefined, prefiltered, parsedTexture.forcedExtension);
|
|
558
|
-
}, parsedTexture, scene);
|
|
559
|
-
// Local Cubemaps
|
|
560
|
-
if (parsedTexture.boundingBoxPosition) {
|
|
561
|
-
texture.boundingBoxPosition = Vector3.FromArray(parsedTexture.boundingBoxPosition);
|
|
562
|
-
}
|
|
563
|
-
if (parsedTexture.boundingBoxSize) {
|
|
564
|
-
texture.boundingBoxSize = Vector3.FromArray(parsedTexture.boundingBoxSize);
|
|
565
|
-
}
|
|
566
|
-
// Animations
|
|
567
|
-
if (parsedTexture.animations) {
|
|
568
|
-
for (let animationIndex = 0; animationIndex < parsedTexture.animations.length; animationIndex++) {
|
|
569
|
-
const parsedAnimation = parsedTexture.animations[animationIndex];
|
|
570
|
-
const internalClass = GetClass("BABYLON.Animation");
|
|
571
|
-
if (internalClass) {
|
|
572
|
-
texture.animations.push(internalClass.Parse(parsedAnimation));
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
return texture;
|
|
577
|
-
}
|
|
578
|
-
/**
|
|
579
|
-
* Makes a clone, or deep copy, of the cube texture
|
|
580
|
-
* @returns a new cube texture
|
|
581
|
-
*/
|
|
582
|
-
clone() {
|
|
583
|
-
let uniqueId = 0;
|
|
584
|
-
const newCubeTexture = SerializationHelper.Clone(() => {
|
|
585
|
-
const cubeTexture = new CubeTexture(this.url, this.getScene() || this._getEngine(), this._extensions, this._noMipmap, this._files);
|
|
586
|
-
uniqueId = cubeTexture.uniqueId;
|
|
587
|
-
return cubeTexture;
|
|
588
|
-
}, this);
|
|
589
|
-
newCubeTexture.uniqueId = uniqueId;
|
|
590
|
-
return newCubeTexture;
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
__decorate([
|
|
594
|
-
serialize()
|
|
595
|
-
], CubeTexture.prototype, "url", void 0);
|
|
596
|
-
__decorate([
|
|
597
|
-
serializeAsVector3()
|
|
598
|
-
], CubeTexture.prototype, "boundingBoxPosition", void 0);
|
|
599
|
-
__decorate([
|
|
600
|
-
serializeAsVector3()
|
|
601
|
-
], CubeTexture.prototype, "boundingBoxSize", null);
|
|
602
|
-
__decorate([
|
|
603
|
-
serialize("rotationY")
|
|
604
|
-
], CubeTexture.prototype, "rotationY", null);
|
|
605
|
-
__decorate([
|
|
606
|
-
serialize("files")
|
|
607
|
-
], CubeTexture.prototype, "_files", void 0);
|
|
608
|
-
__decorate([
|
|
609
|
-
serialize("forcedExtension")
|
|
610
|
-
], CubeTexture.prototype, "_forcedExtension", void 0);
|
|
611
|
-
__decorate([
|
|
612
|
-
serialize("extensions")
|
|
613
|
-
], CubeTexture.prototype, "_extensions", void 0);
|
|
614
|
-
__decorate([
|
|
615
|
-
serializeAsMatrix("textureMatrix")
|
|
616
|
-
], CubeTexture.prototype, "_textureMatrix", void 0);
|
|
617
|
-
__decorate([
|
|
618
|
-
serializeAsMatrix("textureMatrixRefraction")
|
|
619
|
-
], CubeTexture.prototype, "_textureMatrixRefraction", void 0);
|
|
620
|
-
Texture._CubeTextureParser = CubeTexture.Parse;
|
|
621
|
-
// Some exporters relies on Tools.Instantiate
|
|
622
|
-
RegisterClass("BABYLON.CubeTexture", CubeTexture);
|
|
623
|
-
|
|
624
|
-
ThinEngine.prototype.updateRawTexture = function (texture, data, format, invertY, compression = null, type = 0, useSRGBBuffer = false) {
|
|
625
|
-
if (!texture) {
|
|
626
|
-
return;
|
|
627
|
-
}
|
|
628
|
-
// Babylon's internalSizedFomat but gl's texImage2D internalFormat
|
|
629
|
-
const internalSizedFomat = this._getRGBABufferInternalSizedFormat(type, format, useSRGBBuffer);
|
|
630
|
-
// Babylon's internalFormat but gl's texImage2D format
|
|
631
|
-
const internalFormat = this._getInternalFormat(format);
|
|
632
|
-
const textureType = this._getWebGLTextureType(type);
|
|
633
|
-
this._bindTextureDirectly(this._gl.TEXTURE_2D, texture, true);
|
|
634
|
-
this._unpackFlipY(invertY === undefined ? true : invertY ? true : false);
|
|
635
|
-
if (!this._doNotHandleContextLost) {
|
|
636
|
-
texture._bufferView = data;
|
|
637
|
-
texture.format = format;
|
|
638
|
-
texture.type = type;
|
|
639
|
-
texture.invertY = invertY;
|
|
640
|
-
texture._compression = compression;
|
|
641
|
-
}
|
|
642
|
-
if (texture.width % 4 !== 0) {
|
|
643
|
-
this._gl.pixelStorei(this._gl.UNPACK_ALIGNMENT, 1);
|
|
644
|
-
}
|
|
645
|
-
if (compression && data) {
|
|
646
|
-
this._gl.compressedTexImage2D(this._gl.TEXTURE_2D, 0, this.getCaps().s3tc[compression], texture.width, texture.height, 0, data);
|
|
647
|
-
}
|
|
648
|
-
else {
|
|
649
|
-
this._gl.texImage2D(this._gl.TEXTURE_2D, 0, internalSizedFomat, texture.width, texture.height, 0, internalFormat, textureType, data);
|
|
650
|
-
}
|
|
651
|
-
if (texture.generateMipMaps) {
|
|
652
|
-
this._gl.generateMipmap(this._gl.TEXTURE_2D);
|
|
653
|
-
}
|
|
654
|
-
this._bindTextureDirectly(this._gl.TEXTURE_2D, null);
|
|
655
|
-
// this.resetTextureCache();
|
|
656
|
-
texture.isReady = true;
|
|
657
|
-
};
|
|
658
|
-
ThinEngine.prototype.createRawTexture = function (data, width, height, format, generateMipMaps, invertY, samplingMode, compression = null, type = 0,
|
|
659
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
660
|
-
creationFlags = 0, useSRGBBuffer = false) {
|
|
661
|
-
const texture = new InternalTexture(this, InternalTextureSource.Raw);
|
|
662
|
-
texture.baseWidth = width;
|
|
663
|
-
texture.baseHeight = height;
|
|
664
|
-
texture.width = width;
|
|
665
|
-
texture.height = height;
|
|
666
|
-
texture.format = format;
|
|
667
|
-
texture.generateMipMaps = generateMipMaps;
|
|
668
|
-
texture.samplingMode = samplingMode;
|
|
669
|
-
texture.invertY = invertY;
|
|
670
|
-
texture._compression = compression;
|
|
671
|
-
texture.type = type;
|
|
672
|
-
texture._useSRGBBuffer = this._getUseSRGBBuffer(useSRGBBuffer, !generateMipMaps);
|
|
673
|
-
if (!this._doNotHandleContextLost) {
|
|
674
|
-
texture._bufferView = data;
|
|
675
|
-
}
|
|
676
|
-
this.updateRawTexture(texture, data, format, invertY, compression, type, texture._useSRGBBuffer);
|
|
677
|
-
this._bindTextureDirectly(this._gl.TEXTURE_2D, texture, true);
|
|
678
|
-
// Filters
|
|
679
|
-
const filters = this._getSamplingParameters(samplingMode, generateMipMaps);
|
|
680
|
-
this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MAG_FILTER, filters.mag);
|
|
681
|
-
this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MIN_FILTER, filters.min);
|
|
682
|
-
if (generateMipMaps) {
|
|
683
|
-
this._gl.generateMipmap(this._gl.TEXTURE_2D);
|
|
684
|
-
}
|
|
685
|
-
this._bindTextureDirectly(this._gl.TEXTURE_2D, null);
|
|
686
|
-
this._internalTexturesCache.push(texture);
|
|
687
|
-
return texture;
|
|
688
|
-
};
|
|
689
|
-
ThinEngine.prototype.createRawCubeTexture = function (data, size, format, type, generateMipMaps, invertY, samplingMode, compression = null) {
|
|
690
|
-
const gl = this._gl;
|
|
691
|
-
const texture = new InternalTexture(this, InternalTextureSource.CubeRaw);
|
|
692
|
-
texture.isCube = true;
|
|
693
|
-
texture.format = format;
|
|
694
|
-
texture.type = type;
|
|
695
|
-
if (!this._doNotHandleContextLost) {
|
|
696
|
-
texture._bufferViewArray = data;
|
|
697
|
-
}
|
|
698
|
-
const textureType = this._getWebGLTextureType(type);
|
|
699
|
-
let internalFormat = this._getInternalFormat(format);
|
|
700
|
-
if (internalFormat === gl.RGB) {
|
|
701
|
-
internalFormat = gl.RGBA;
|
|
702
|
-
}
|
|
703
|
-
// Mipmap generation needs a sized internal format that is both color-renderable and texture-filterable
|
|
704
|
-
if (textureType === gl.FLOAT && !this._caps.textureFloatLinearFiltering) {
|
|
705
|
-
generateMipMaps = false;
|
|
706
|
-
samplingMode = 1;
|
|
707
|
-
Logger.Warn("Float texture filtering is not supported. Mipmap generation and sampling mode are forced to false and TEXTURE_NEAREST_SAMPLINGMODE, respectively.");
|
|
708
|
-
}
|
|
709
|
-
else if (textureType === this._gl.HALF_FLOAT_OES && !this._caps.textureHalfFloatLinearFiltering) {
|
|
710
|
-
generateMipMaps = false;
|
|
711
|
-
samplingMode = 1;
|
|
712
|
-
Logger.Warn("Half float texture filtering is not supported. Mipmap generation and sampling mode are forced to false and TEXTURE_NEAREST_SAMPLINGMODE, respectively.");
|
|
713
|
-
}
|
|
714
|
-
else if (textureType === gl.FLOAT && !this._caps.textureFloatRender) {
|
|
715
|
-
generateMipMaps = false;
|
|
716
|
-
Logger.Warn("Render to float textures is not supported. Mipmap generation forced to false.");
|
|
717
|
-
}
|
|
718
|
-
else if (textureType === gl.HALF_FLOAT && !this._caps.colorBufferFloat) {
|
|
719
|
-
generateMipMaps = false;
|
|
720
|
-
Logger.Warn("Render to half float textures is not supported. Mipmap generation forced to false.");
|
|
721
|
-
}
|
|
722
|
-
const width = size;
|
|
723
|
-
const height = width;
|
|
724
|
-
texture.width = width;
|
|
725
|
-
texture.height = height;
|
|
726
|
-
texture.invertY = invertY;
|
|
727
|
-
texture._compression = compression;
|
|
728
|
-
// Double check on POT to generate Mips.
|
|
729
|
-
const isPot = !this.needPOTTextures || (Tools.IsExponentOfTwo(texture.width) && Tools.IsExponentOfTwo(texture.height));
|
|
730
|
-
if (!isPot) {
|
|
731
|
-
generateMipMaps = false;
|
|
732
|
-
}
|
|
733
|
-
// Upload data if needed. The texture won't be ready until then.
|
|
734
|
-
if (data) {
|
|
735
|
-
this.updateRawCubeTexture(texture, data, format, type, invertY, compression);
|
|
736
|
-
}
|
|
737
|
-
else {
|
|
738
|
-
const internalSizedFomat = this._getRGBABufferInternalSizedFormat(type);
|
|
739
|
-
const level = 0;
|
|
740
|
-
this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, texture, true);
|
|
741
|
-
for (let faceIndex = 0; faceIndex < 6; faceIndex++) {
|
|
742
|
-
if (compression) {
|
|
743
|
-
gl.compressedTexImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, level, this.getCaps().s3tc[compression], texture.width, texture.height, 0, undefined);
|
|
744
|
-
}
|
|
745
|
-
else {
|
|
746
|
-
gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, level, internalSizedFomat, texture.width, texture.height, 0, internalFormat, textureType, null);
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, null);
|
|
750
|
-
}
|
|
751
|
-
this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, texture, true);
|
|
752
|
-
// Filters
|
|
753
|
-
if (data && generateMipMaps) {
|
|
754
|
-
this._gl.generateMipmap(this._gl.TEXTURE_CUBE_MAP);
|
|
755
|
-
}
|
|
756
|
-
const filters = this._getSamplingParameters(samplingMode, generateMipMaps);
|
|
757
|
-
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, filters.mag);
|
|
758
|
-
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, filters.min);
|
|
759
|
-
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
760
|
-
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
761
|
-
this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, null);
|
|
762
|
-
texture.generateMipMaps = generateMipMaps;
|
|
763
|
-
texture.samplingMode = samplingMode;
|
|
764
|
-
texture.isReady = true;
|
|
765
|
-
return texture;
|
|
766
|
-
};
|
|
767
|
-
ThinEngine.prototype.updateRawCubeTexture = function (texture, data, format, type, invertY, compression = null, level = 0) {
|
|
768
|
-
texture._bufferViewArray = data;
|
|
769
|
-
texture.format = format;
|
|
770
|
-
texture.type = type;
|
|
771
|
-
texture.invertY = invertY;
|
|
772
|
-
texture._compression = compression;
|
|
773
|
-
const gl = this._gl;
|
|
774
|
-
const textureType = this._getWebGLTextureType(type);
|
|
775
|
-
let internalFormat = this._getInternalFormat(format);
|
|
776
|
-
const internalSizedFomat = this._getRGBABufferInternalSizedFormat(type);
|
|
777
|
-
let needConversion = false;
|
|
778
|
-
if (internalFormat === gl.RGB) {
|
|
779
|
-
internalFormat = gl.RGBA;
|
|
780
|
-
needConversion = true;
|
|
781
|
-
}
|
|
782
|
-
this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, texture, true);
|
|
783
|
-
this._unpackFlipY(invertY === undefined ? true : invertY ? true : false);
|
|
784
|
-
if (texture.width % 4 !== 0) {
|
|
785
|
-
gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
|
|
786
|
-
}
|
|
787
|
-
// Data are known to be in +X +Y +Z -X -Y -Z
|
|
788
|
-
for (let faceIndex = 0; faceIndex < 6; faceIndex++) {
|
|
789
|
-
let faceData = data[faceIndex];
|
|
790
|
-
if (compression) {
|
|
791
|
-
gl.compressedTexImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, level, this.getCaps().s3tc[compression], texture.width, texture.height, 0, faceData);
|
|
792
|
-
}
|
|
793
|
-
else {
|
|
794
|
-
if (needConversion) {
|
|
795
|
-
faceData = _convertRGBtoRGBATextureData(faceData, texture.width, texture.height, type);
|
|
796
|
-
}
|
|
797
|
-
gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, level, internalSizedFomat, texture.width, texture.height, 0, internalFormat, textureType, faceData);
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
const isPot = !this.needPOTTextures || (Tools.IsExponentOfTwo(texture.width) && Tools.IsExponentOfTwo(texture.height));
|
|
801
|
-
if (isPot && texture.generateMipMaps && level === 0) {
|
|
802
|
-
this._gl.generateMipmap(this._gl.TEXTURE_CUBE_MAP);
|
|
803
|
-
}
|
|
804
|
-
this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, null);
|
|
805
|
-
// this.resetTextureCache();
|
|
806
|
-
texture.isReady = true;
|
|
807
|
-
};
|
|
808
|
-
ThinEngine.prototype.createRawCubeTextureFromUrl = function (url, scene, size, format, type, noMipmap, callback, mipmapGenerator, onLoad = null, onError = null, samplingMode = 3, invertY = false) {
|
|
809
|
-
const gl = this._gl;
|
|
810
|
-
const texture = this.createRawCubeTexture(null, size, format, type, !noMipmap, invertY, samplingMode, null);
|
|
811
|
-
scene === null || scene === void 0 ? void 0 : scene.addPendingData(texture);
|
|
812
|
-
texture.url = url;
|
|
813
|
-
texture.isReady = false;
|
|
814
|
-
this._internalTexturesCache.push(texture);
|
|
815
|
-
const onerror = (request, exception) => {
|
|
816
|
-
scene === null || scene === void 0 ? void 0 : scene.removePendingData(texture);
|
|
817
|
-
if (onError && request) {
|
|
818
|
-
onError(request.status + " " + request.statusText, exception);
|
|
819
|
-
}
|
|
820
|
-
};
|
|
821
|
-
const internalCallback = (data) => {
|
|
822
|
-
const width = texture.width;
|
|
823
|
-
const faceDataArrays = callback(data);
|
|
824
|
-
if (!faceDataArrays) {
|
|
825
|
-
return;
|
|
826
|
-
}
|
|
827
|
-
if (mipmapGenerator) {
|
|
828
|
-
const textureType = this._getWebGLTextureType(type);
|
|
829
|
-
let internalFormat = this._getInternalFormat(format);
|
|
830
|
-
const internalSizedFomat = this._getRGBABufferInternalSizedFormat(type);
|
|
831
|
-
let needConversion = false;
|
|
832
|
-
if (internalFormat === gl.RGB) {
|
|
833
|
-
internalFormat = gl.RGBA;
|
|
834
|
-
needConversion = true;
|
|
835
|
-
}
|
|
836
|
-
this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, texture, true);
|
|
837
|
-
this._unpackFlipY(false);
|
|
838
|
-
const mipData = mipmapGenerator(faceDataArrays);
|
|
839
|
-
for (let level = 0; level < mipData.length; level++) {
|
|
840
|
-
const mipSize = width >> level;
|
|
841
|
-
for (let faceIndex = 0; faceIndex < 6; faceIndex++) {
|
|
842
|
-
let mipFaceData = mipData[level][faceIndex];
|
|
843
|
-
if (needConversion) {
|
|
844
|
-
mipFaceData = _convertRGBtoRGBATextureData(mipFaceData, mipSize, mipSize, type);
|
|
845
|
-
}
|
|
846
|
-
gl.texImage2D(faceIndex, level, internalSizedFomat, mipSize, mipSize, 0, internalFormat, textureType, mipFaceData);
|
|
847
|
-
}
|
|
848
|
-
}
|
|
849
|
-
this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, null);
|
|
850
|
-
}
|
|
851
|
-
else {
|
|
852
|
-
this.updateRawCubeTexture(texture, faceDataArrays, format, type, invertY);
|
|
853
|
-
}
|
|
854
|
-
texture.isReady = true;
|
|
855
|
-
// this.resetTextureCache();
|
|
856
|
-
scene === null || scene === void 0 ? void 0 : scene.removePendingData(texture);
|
|
857
|
-
texture.onLoadedObservable.notifyObservers(texture);
|
|
858
|
-
texture.onLoadedObservable.clear();
|
|
859
|
-
if (onLoad) {
|
|
860
|
-
onLoad();
|
|
861
|
-
}
|
|
862
|
-
};
|
|
863
|
-
this._loadFile(url, (data) => {
|
|
864
|
-
internalCallback(data);
|
|
865
|
-
}, undefined, scene === null || scene === void 0 ? void 0 : scene.offlineProvider, true, onerror);
|
|
866
|
-
return texture;
|
|
867
|
-
};
|
|
868
|
-
/**
|
|
869
|
-
* @internal
|
|
870
|
-
*/
|
|
871
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
872
|
-
function _convertRGBtoRGBATextureData(rgbData, width, height, textureType) {
|
|
873
|
-
// Create new RGBA data container.
|
|
874
|
-
let rgbaData;
|
|
875
|
-
let val1 = 1;
|
|
876
|
-
if (textureType === 1) {
|
|
877
|
-
rgbaData = new Float32Array(width * height * 4);
|
|
878
|
-
}
|
|
879
|
-
else if (textureType === 2) {
|
|
880
|
-
rgbaData = new Uint16Array(width * height * 4);
|
|
881
|
-
val1 = 15360; // 15360 is the encoding of 1 in half float
|
|
882
|
-
}
|
|
883
|
-
else if (textureType === 7) {
|
|
884
|
-
rgbaData = new Uint32Array(width * height * 4);
|
|
885
|
-
}
|
|
886
|
-
else {
|
|
887
|
-
rgbaData = new Uint8Array(width * height * 4);
|
|
888
|
-
}
|
|
889
|
-
// Convert each pixel.
|
|
890
|
-
for (let x = 0; x < width; x++) {
|
|
891
|
-
for (let y = 0; y < height; y++) {
|
|
892
|
-
const index = (y * width + x) * 3;
|
|
893
|
-
const newIndex = (y * width + x) * 4;
|
|
894
|
-
// Map Old Value to new value.
|
|
895
|
-
rgbaData[newIndex + 0] = rgbData[index + 0];
|
|
896
|
-
rgbaData[newIndex + 1] = rgbData[index + 1];
|
|
897
|
-
rgbaData[newIndex + 2] = rgbData[index + 2];
|
|
898
|
-
// Add fully opaque alpha channel.
|
|
899
|
-
rgbaData[newIndex + 3] = val1;
|
|
900
|
-
}
|
|
901
|
-
}
|
|
902
|
-
return rgbaData;
|
|
903
|
-
}
|
|
904
|
-
/**
|
|
905
|
-
* Create a function for createRawTexture3D/createRawTexture2DArray
|
|
906
|
-
* @param is3D true for TEXTURE_3D and false for TEXTURE_2D_ARRAY
|
|
907
|
-
* @internal
|
|
908
|
-
*/
|
|
909
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
910
|
-
function _makeCreateRawTextureFunction(is3D) {
|
|
911
|
-
return function (data, width, height, depth, format, generateMipMaps, invertY, samplingMode, compression = null, textureType = 0) {
|
|
912
|
-
const target = is3D ? this._gl.TEXTURE_3D : this._gl.TEXTURE_2D_ARRAY;
|
|
913
|
-
const source = is3D ? InternalTextureSource.Raw3D : InternalTextureSource.Raw2DArray;
|
|
914
|
-
const texture = new InternalTexture(this, source);
|
|
915
|
-
texture.baseWidth = width;
|
|
916
|
-
texture.baseHeight = height;
|
|
917
|
-
texture.baseDepth = depth;
|
|
918
|
-
texture.width = width;
|
|
919
|
-
texture.height = height;
|
|
920
|
-
texture.depth = depth;
|
|
921
|
-
texture.format = format;
|
|
922
|
-
texture.type = textureType;
|
|
923
|
-
texture.generateMipMaps = generateMipMaps;
|
|
924
|
-
texture.samplingMode = samplingMode;
|
|
925
|
-
if (is3D) {
|
|
926
|
-
texture.is3D = true;
|
|
927
|
-
}
|
|
928
|
-
else {
|
|
929
|
-
texture.is2DArray = true;
|
|
930
|
-
}
|
|
931
|
-
if (!this._doNotHandleContextLost) {
|
|
932
|
-
texture._bufferView = data;
|
|
933
|
-
}
|
|
934
|
-
if (is3D) {
|
|
935
|
-
this.updateRawTexture3D(texture, data, format, invertY, compression, textureType);
|
|
936
|
-
}
|
|
937
|
-
else {
|
|
938
|
-
this.updateRawTexture2DArray(texture, data, format, invertY, compression, textureType);
|
|
939
|
-
}
|
|
940
|
-
this._bindTextureDirectly(target, texture, true);
|
|
941
|
-
// Filters
|
|
942
|
-
const filters = this._getSamplingParameters(samplingMode, generateMipMaps);
|
|
943
|
-
this._gl.texParameteri(target, this._gl.TEXTURE_MAG_FILTER, filters.mag);
|
|
944
|
-
this._gl.texParameteri(target, this._gl.TEXTURE_MIN_FILTER, filters.min);
|
|
945
|
-
if (generateMipMaps) {
|
|
946
|
-
this._gl.generateMipmap(target);
|
|
947
|
-
}
|
|
948
|
-
this._bindTextureDirectly(target, null);
|
|
949
|
-
this._internalTexturesCache.push(texture);
|
|
950
|
-
return texture;
|
|
951
|
-
};
|
|
952
|
-
}
|
|
953
|
-
ThinEngine.prototype.createRawTexture2DArray = _makeCreateRawTextureFunction(false);
|
|
954
|
-
ThinEngine.prototype.createRawTexture3D = _makeCreateRawTextureFunction(true);
|
|
955
|
-
/**
|
|
956
|
-
* Create a function for updateRawTexture3D/updateRawTexture2DArray
|
|
957
|
-
* @param is3D true for TEXTURE_3D and false for TEXTURE_2D_ARRAY
|
|
958
|
-
* @internal
|
|
959
|
-
*/
|
|
960
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
961
|
-
function _makeUpdateRawTextureFunction(is3D) {
|
|
962
|
-
return function (texture, data, format, invertY, compression = null, textureType = 0) {
|
|
963
|
-
const target = is3D ? this._gl.TEXTURE_3D : this._gl.TEXTURE_2D_ARRAY;
|
|
964
|
-
const internalType = this._getWebGLTextureType(textureType);
|
|
965
|
-
const internalFormat = this._getInternalFormat(format);
|
|
966
|
-
const internalSizedFomat = this._getRGBABufferInternalSizedFormat(textureType, format);
|
|
967
|
-
this._bindTextureDirectly(target, texture, true);
|
|
968
|
-
this._unpackFlipY(invertY === undefined ? true : invertY ? true : false);
|
|
969
|
-
if (!this._doNotHandleContextLost) {
|
|
970
|
-
texture._bufferView = data;
|
|
971
|
-
texture.format = format;
|
|
972
|
-
texture.invertY = invertY;
|
|
973
|
-
texture._compression = compression;
|
|
974
|
-
}
|
|
975
|
-
if (texture.width % 4 !== 0) {
|
|
976
|
-
this._gl.pixelStorei(this._gl.UNPACK_ALIGNMENT, 1);
|
|
977
|
-
}
|
|
978
|
-
if (compression && data) {
|
|
979
|
-
this._gl.compressedTexImage3D(target, 0, this.getCaps().s3tc[compression], texture.width, texture.height, texture.depth, 0, data);
|
|
980
|
-
}
|
|
981
|
-
else {
|
|
982
|
-
this._gl.texImage3D(target, 0, internalSizedFomat, texture.width, texture.height, texture.depth, 0, internalFormat, internalType, data);
|
|
983
|
-
}
|
|
984
|
-
if (texture.generateMipMaps) {
|
|
985
|
-
this._gl.generateMipmap(target);
|
|
986
|
-
}
|
|
987
|
-
this._bindTextureDirectly(target, null);
|
|
988
|
-
// this.resetTextureCache();
|
|
989
|
-
texture.isReady = true;
|
|
990
|
-
};
|
|
991
|
-
}
|
|
992
|
-
ThinEngine.prototype.updateRawTexture2DArray = _makeUpdateRawTextureFunction(false);
|
|
993
|
-
ThinEngine.prototype.updateRawTexture3D = _makeUpdateRawTextureFunction(true);
|
|
994
|
-
|
|
995
|
-
/**
|
|
996
|
-
* Helper class useful to convert panorama picture to their cubemap representation in 6 faces.
|
|
997
|
-
*/
|
|
998
|
-
class PanoramaToCubeMapTools {
|
|
999
|
-
/**
|
|
1000
|
-
* Converts a panorama stored in RGB right to left up to down format into a cubemap (6 faces).
|
|
1001
|
-
*
|
|
1002
|
-
* @param float32Array The source data.
|
|
1003
|
-
* @param inputWidth The width of the input panorama.
|
|
1004
|
-
* @param inputHeight The height of the input panorama.
|
|
1005
|
-
* @param size The willing size of the generated cubemap (each faces will be size * size pixels)
|
|
1006
|
-
* @returns The cubemap data
|
|
1007
|
-
*/
|
|
1008
|
-
static ConvertPanoramaToCubemap(float32Array, inputWidth, inputHeight, size, supersample = false) {
|
|
1009
|
-
if (!float32Array) {
|
|
1010
|
-
throw "ConvertPanoramaToCubemap: input cannot be null";
|
|
1011
|
-
}
|
|
1012
|
-
if (float32Array.length != inputWidth * inputHeight * 3) {
|
|
1013
|
-
throw "ConvertPanoramaToCubemap: input size is wrong";
|
|
1014
|
-
}
|
|
1015
|
-
const textureFront = this.CreateCubemapTexture(size, this.FACE_FRONT, float32Array, inputWidth, inputHeight, supersample);
|
|
1016
|
-
const textureBack = this.CreateCubemapTexture(size, this.FACE_BACK, float32Array, inputWidth, inputHeight, supersample);
|
|
1017
|
-
const textureLeft = this.CreateCubemapTexture(size, this.FACE_LEFT, float32Array, inputWidth, inputHeight, supersample);
|
|
1018
|
-
const textureRight = this.CreateCubemapTexture(size, this.FACE_RIGHT, float32Array, inputWidth, inputHeight, supersample);
|
|
1019
|
-
const textureUp = this.CreateCubemapTexture(size, this.FACE_UP, float32Array, inputWidth, inputHeight, supersample);
|
|
1020
|
-
const textureDown = this.CreateCubemapTexture(size, this.FACE_DOWN, float32Array, inputWidth, inputHeight, supersample);
|
|
1021
|
-
return {
|
|
1022
|
-
front: textureFront,
|
|
1023
|
-
back: textureBack,
|
|
1024
|
-
left: textureLeft,
|
|
1025
|
-
right: textureRight,
|
|
1026
|
-
up: textureUp,
|
|
1027
|
-
down: textureDown,
|
|
1028
|
-
size: size,
|
|
1029
|
-
type: 1,
|
|
1030
|
-
format: 4,
|
|
1031
|
-
gammaSpace: false,
|
|
1032
|
-
};
|
|
1033
|
-
}
|
|
1034
|
-
static CreateCubemapTexture(texSize, faceData, float32Array, inputWidth, inputHeight, supersample = false) {
|
|
1035
|
-
const buffer = new ArrayBuffer(texSize * texSize * 4 * 3);
|
|
1036
|
-
const textureArray = new Float32Array(buffer);
|
|
1037
|
-
// If supersampling, determine number of samples needed when source texture width is divided for 4 cube faces
|
|
1038
|
-
const samples = supersample ? Math.max(1, Math.round(inputWidth / 4 / texSize)) : 1;
|
|
1039
|
-
const sampleFactor = 1 / samples;
|
|
1040
|
-
const sampleFactorSqr = sampleFactor * sampleFactor;
|
|
1041
|
-
const rotDX1 = faceData[1].subtract(faceData[0]).scale(sampleFactor / texSize);
|
|
1042
|
-
const rotDX2 = faceData[3].subtract(faceData[2]).scale(sampleFactor / texSize);
|
|
1043
|
-
const dy = 1 / texSize;
|
|
1044
|
-
let fy = 0;
|
|
1045
|
-
for (let y = 0; y < texSize; y++) {
|
|
1046
|
-
for (let sy = 0; sy < samples; sy++) {
|
|
1047
|
-
let xv1 = faceData[0];
|
|
1048
|
-
let xv2 = faceData[2];
|
|
1049
|
-
for (let x = 0; x < texSize; x++) {
|
|
1050
|
-
for (let sx = 0; sx < samples; sx++) {
|
|
1051
|
-
const v = xv2.subtract(xv1).scale(fy).add(xv1);
|
|
1052
|
-
v.normalize();
|
|
1053
|
-
const color = this.CalcProjectionSpherical(v, float32Array, inputWidth, inputHeight);
|
|
1054
|
-
// 3 channels per pixels
|
|
1055
|
-
textureArray[y * texSize * 3 + x * 3 + 0] += color.r * sampleFactorSqr;
|
|
1056
|
-
textureArray[y * texSize * 3 + x * 3 + 1] += color.g * sampleFactorSqr;
|
|
1057
|
-
textureArray[y * texSize * 3 + x * 3 + 2] += color.b * sampleFactorSqr;
|
|
1058
|
-
xv1 = xv1.add(rotDX1);
|
|
1059
|
-
xv2 = xv2.add(rotDX2);
|
|
1060
|
-
}
|
|
1061
|
-
}
|
|
1062
|
-
fy += dy * sampleFactor;
|
|
1063
|
-
}
|
|
1064
|
-
}
|
|
1065
|
-
return textureArray;
|
|
1066
|
-
}
|
|
1067
|
-
static CalcProjectionSpherical(vDir, float32Array, inputWidth, inputHeight) {
|
|
1068
|
-
let theta = Math.atan2(vDir.z, vDir.x);
|
|
1069
|
-
const phi = Math.acos(vDir.y);
|
|
1070
|
-
while (theta < -Math.PI) {
|
|
1071
|
-
theta += 2 * Math.PI;
|
|
1072
|
-
}
|
|
1073
|
-
while (theta > Math.PI) {
|
|
1074
|
-
theta -= 2 * Math.PI;
|
|
1075
|
-
}
|
|
1076
|
-
let dx = theta / Math.PI;
|
|
1077
|
-
const dy = phi / Math.PI;
|
|
1078
|
-
// recenter.
|
|
1079
|
-
dx = dx * 0.5 + 0.5;
|
|
1080
|
-
let px = Math.round(dx * inputWidth);
|
|
1081
|
-
if (px < 0) {
|
|
1082
|
-
px = 0;
|
|
1083
|
-
}
|
|
1084
|
-
else if (px >= inputWidth) {
|
|
1085
|
-
px = inputWidth - 1;
|
|
1086
|
-
}
|
|
1087
|
-
let py = Math.round(dy * inputHeight);
|
|
1088
|
-
if (py < 0) {
|
|
1089
|
-
py = 0;
|
|
1090
|
-
}
|
|
1091
|
-
else if (py >= inputHeight) {
|
|
1092
|
-
py = inputHeight - 1;
|
|
1093
|
-
}
|
|
1094
|
-
const inputY = inputHeight - py - 1;
|
|
1095
|
-
const r = float32Array[inputY * inputWidth * 3 + px * 3 + 0];
|
|
1096
|
-
const g = float32Array[inputY * inputWidth * 3 + px * 3 + 1];
|
|
1097
|
-
const b = float32Array[inputY * inputWidth * 3 + px * 3 + 2];
|
|
1098
|
-
return {
|
|
1099
|
-
r: r,
|
|
1100
|
-
g: g,
|
|
1101
|
-
b: b,
|
|
1102
|
-
};
|
|
1103
|
-
}
|
|
1104
|
-
}
|
|
1105
|
-
PanoramaToCubeMapTools.FACE_LEFT = [new Vector3(-1.0, -1.0, -1.0), new Vector3(1.0, -1.0, -1.0), new Vector3(-1.0, 1.0, -1.0), new Vector3(1.0, 1.0, -1.0)];
|
|
1106
|
-
PanoramaToCubeMapTools.FACE_RIGHT = [new Vector3(1.0, -1.0, 1.0), new Vector3(-1.0, -1.0, 1.0), new Vector3(1.0, 1.0, 1.0), new Vector3(-1.0, 1.0, 1.0)];
|
|
1107
|
-
PanoramaToCubeMapTools.FACE_FRONT = [new Vector3(1.0, -1.0, -1.0), new Vector3(1.0, -1.0, 1.0), new Vector3(1.0, 1.0, -1.0), new Vector3(1.0, 1.0, 1.0)];
|
|
1108
|
-
PanoramaToCubeMapTools.FACE_BACK = [new Vector3(-1.0, -1.0, 1.0), new Vector3(-1.0, -1.0, -1.0), new Vector3(-1.0, 1.0, 1.0), new Vector3(-1.0, 1.0, -1.0)];
|
|
1109
|
-
PanoramaToCubeMapTools.FACE_DOWN = [new Vector3(1.0, 1.0, -1.0), new Vector3(1.0, 1.0, 1.0), new Vector3(-1.0, 1.0, -1.0), new Vector3(-1.0, 1.0, 1.0)];
|
|
1110
|
-
PanoramaToCubeMapTools.FACE_UP = [new Vector3(-1.0, -1.0, -1.0), new Vector3(-1.0, -1.0, 1.0), new Vector3(1.0, -1.0, -1.0), new Vector3(1.0, -1.0, 1.0)];
|
|
1111
|
-
|
|
1112
|
-
/**
|
|
1113
|
-
* This groups tools to convert HDR texture to native colors array.
|
|
1114
|
-
*/
|
|
1115
|
-
class HDRTools {
|
|
1116
|
-
static _Ldexp(mantissa, exponent) {
|
|
1117
|
-
if (exponent > 1023) {
|
|
1118
|
-
return mantissa * Math.pow(2, 1023) * Math.pow(2, exponent - 1023);
|
|
1119
|
-
}
|
|
1120
|
-
if (exponent < -1074) {
|
|
1121
|
-
return mantissa * Math.pow(2, -1074) * Math.pow(2, exponent + 1074);
|
|
1122
|
-
}
|
|
1123
|
-
return mantissa * Math.pow(2, exponent);
|
|
1124
|
-
}
|
|
1125
|
-
static _Rgbe2float(float32array, red, green, blue, exponent, index) {
|
|
1126
|
-
if (exponent > 0) {
|
|
1127
|
-
/*nonzero pixel*/
|
|
1128
|
-
exponent = this._Ldexp(1.0, exponent - (128 + 8));
|
|
1129
|
-
float32array[index + 0] = red * exponent;
|
|
1130
|
-
float32array[index + 1] = green * exponent;
|
|
1131
|
-
float32array[index + 2] = blue * exponent;
|
|
1132
|
-
}
|
|
1133
|
-
else {
|
|
1134
|
-
float32array[index + 0] = 0;
|
|
1135
|
-
float32array[index + 1] = 0;
|
|
1136
|
-
float32array[index + 2] = 0;
|
|
1137
|
-
}
|
|
1138
|
-
}
|
|
1139
|
-
static _ReadStringLine(uint8array, startIndex) {
|
|
1140
|
-
let line = "";
|
|
1141
|
-
let character = "";
|
|
1142
|
-
for (let i = startIndex; i < uint8array.length - startIndex; i++) {
|
|
1143
|
-
character = String.fromCharCode(uint8array[i]);
|
|
1144
|
-
if (character == "\n") {
|
|
1145
|
-
break;
|
|
1146
|
-
}
|
|
1147
|
-
line += character;
|
|
1148
|
-
}
|
|
1149
|
-
return line;
|
|
1150
|
-
}
|
|
1151
|
-
/**
|
|
1152
|
-
* Reads header information from an RGBE texture stored in a native array.
|
|
1153
|
-
* More information on this format are available here:
|
|
1154
|
-
* https://en.wikipedia.org/wiki/RGBE_image_format
|
|
1155
|
-
*
|
|
1156
|
-
* @param uint8array The binary file stored in native array.
|
|
1157
|
-
* @returns The header information.
|
|
1158
|
-
*/
|
|
1159
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
1160
|
-
static RGBE_ReadHeader(uint8array) {
|
|
1161
|
-
let height = 0;
|
|
1162
|
-
let width = 0;
|
|
1163
|
-
let line = this._ReadStringLine(uint8array, 0);
|
|
1164
|
-
if (line[0] != "#" || line[1] != "?") {
|
|
1165
|
-
throw "Bad HDR Format.";
|
|
1166
|
-
}
|
|
1167
|
-
let endOfHeader = false;
|
|
1168
|
-
let findFormat = false;
|
|
1169
|
-
let lineIndex = 0;
|
|
1170
|
-
do {
|
|
1171
|
-
lineIndex += line.length + 1;
|
|
1172
|
-
line = this._ReadStringLine(uint8array, lineIndex);
|
|
1173
|
-
if (line == "FORMAT=32-bit_rle_rgbe") {
|
|
1174
|
-
findFormat = true;
|
|
1175
|
-
}
|
|
1176
|
-
else if (line.length == 0) {
|
|
1177
|
-
endOfHeader = true;
|
|
1178
|
-
}
|
|
1179
|
-
} while (!endOfHeader);
|
|
1180
|
-
if (!findFormat) {
|
|
1181
|
-
throw "HDR Bad header format, unsupported FORMAT";
|
|
1182
|
-
}
|
|
1183
|
-
lineIndex += line.length + 1;
|
|
1184
|
-
line = this._ReadStringLine(uint8array, lineIndex);
|
|
1185
|
-
const sizeRegexp = /^-Y (.*) \+X (.*)$/g;
|
|
1186
|
-
const match = sizeRegexp.exec(line);
|
|
1187
|
-
// TODO. Support +Y and -X if needed.
|
|
1188
|
-
if (!match || match.length < 3) {
|
|
1189
|
-
throw "HDR Bad header format, no size";
|
|
1190
|
-
}
|
|
1191
|
-
width = parseInt(match[2]);
|
|
1192
|
-
height = parseInt(match[1]);
|
|
1193
|
-
if (width < 8 || width > 0x7fff) {
|
|
1194
|
-
throw "HDR Bad header format, unsupported size";
|
|
1195
|
-
}
|
|
1196
|
-
lineIndex += line.length + 1;
|
|
1197
|
-
return {
|
|
1198
|
-
height: height,
|
|
1199
|
-
width: width,
|
|
1200
|
-
dataPosition: lineIndex,
|
|
1201
|
-
};
|
|
1202
|
-
}
|
|
1203
|
-
/**
|
|
1204
|
-
* Returns the cubemap information (each faces texture data) extracted from an RGBE texture.
|
|
1205
|
-
* This RGBE texture needs to store the information as a panorama.
|
|
1206
|
-
*
|
|
1207
|
-
* More information on this format are available here:
|
|
1208
|
-
* https://en.wikipedia.org/wiki/RGBE_image_format
|
|
1209
|
-
*
|
|
1210
|
-
* @param buffer The binary file stored in an array buffer.
|
|
1211
|
-
* @param size The expected size of the extracted cubemap.
|
|
1212
|
-
* @returns The Cube Map information.
|
|
1213
|
-
*/
|
|
1214
|
-
static GetCubeMapTextureData(buffer, size, supersample = false) {
|
|
1215
|
-
const uint8array = new Uint8Array(buffer);
|
|
1216
|
-
const hdrInfo = this.RGBE_ReadHeader(uint8array);
|
|
1217
|
-
const data = this.RGBE_ReadPixels(uint8array, hdrInfo);
|
|
1218
|
-
const cubeMapData = PanoramaToCubeMapTools.ConvertPanoramaToCubemap(data, hdrInfo.width, hdrInfo.height, size, supersample);
|
|
1219
|
-
return cubeMapData;
|
|
1220
|
-
}
|
|
1221
|
-
/**
|
|
1222
|
-
* Returns the pixels data extracted from an RGBE texture.
|
|
1223
|
-
* This pixels will be stored left to right up to down in the R G B order in one array.
|
|
1224
|
-
*
|
|
1225
|
-
* More information on this format are available here:
|
|
1226
|
-
* https://en.wikipedia.org/wiki/RGBE_image_format
|
|
1227
|
-
*
|
|
1228
|
-
* @param uint8array The binary file stored in an array buffer.
|
|
1229
|
-
* @param hdrInfo The header information of the file.
|
|
1230
|
-
* @returns The pixels data in RGB right to left up to down order.
|
|
1231
|
-
*/
|
|
1232
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
1233
|
-
static RGBE_ReadPixels(uint8array, hdrInfo) {
|
|
1234
|
-
return this._RGBEReadPixelsRLE(uint8array, hdrInfo);
|
|
1235
|
-
}
|
|
1236
|
-
static _RGBEReadPixelsRLE(uint8array, hdrInfo) {
|
|
1237
|
-
let num_scanlines = hdrInfo.height;
|
|
1238
|
-
const scanline_width = hdrInfo.width;
|
|
1239
|
-
let a, b, c, d, count;
|
|
1240
|
-
let dataIndex = hdrInfo.dataPosition;
|
|
1241
|
-
let index = 0, endIndex = 0, i = 0;
|
|
1242
|
-
const scanLineArrayBuffer = new ArrayBuffer(scanline_width * 4); // four channel R G B E
|
|
1243
|
-
const scanLineArray = new Uint8Array(scanLineArrayBuffer);
|
|
1244
|
-
// 3 channels of 4 bytes per pixel in float.
|
|
1245
|
-
const resultBuffer = new ArrayBuffer(hdrInfo.width * hdrInfo.height * 4 * 3);
|
|
1246
|
-
const resultArray = new Float32Array(resultBuffer);
|
|
1247
|
-
// read in each successive scanline
|
|
1248
|
-
while (num_scanlines > 0) {
|
|
1249
|
-
a = uint8array[dataIndex++];
|
|
1250
|
-
b = uint8array[dataIndex++];
|
|
1251
|
-
c = uint8array[dataIndex++];
|
|
1252
|
-
d = uint8array[dataIndex++];
|
|
1253
|
-
if (a != 2 || b != 2 || c & 0x80 || hdrInfo.width < 8 || hdrInfo.width > 32767) {
|
|
1254
|
-
return this._RGBEReadPixelsNOTRLE(uint8array, hdrInfo);
|
|
1255
|
-
}
|
|
1256
|
-
if (((c << 8) | d) != scanline_width) {
|
|
1257
|
-
throw "HDR Bad header format, wrong scan line width";
|
|
1258
|
-
}
|
|
1259
|
-
index = 0;
|
|
1260
|
-
// read each of the four channels for the scanline into the buffer
|
|
1261
|
-
for (i = 0; i < 4; i++) {
|
|
1262
|
-
endIndex = (i + 1) * scanline_width;
|
|
1263
|
-
while (index < endIndex) {
|
|
1264
|
-
a = uint8array[dataIndex++];
|
|
1265
|
-
b = uint8array[dataIndex++];
|
|
1266
|
-
if (a > 128) {
|
|
1267
|
-
// a run of the same value
|
|
1268
|
-
count = a - 128;
|
|
1269
|
-
if (count == 0 || count > endIndex - index) {
|
|
1270
|
-
throw "HDR Bad Format, bad scanline data (run)";
|
|
1271
|
-
}
|
|
1272
|
-
while (count-- > 0) {
|
|
1273
|
-
scanLineArray[index++] = b;
|
|
1274
|
-
}
|
|
1275
|
-
}
|
|
1276
|
-
else {
|
|
1277
|
-
// a non-run
|
|
1278
|
-
count = a;
|
|
1279
|
-
if (count == 0 || count > endIndex - index) {
|
|
1280
|
-
throw "HDR Bad Format, bad scanline data (non-run)";
|
|
1281
|
-
}
|
|
1282
|
-
scanLineArray[index++] = b;
|
|
1283
|
-
if (--count > 0) {
|
|
1284
|
-
for (let j = 0; j < count; j++) {
|
|
1285
|
-
scanLineArray[index++] = uint8array[dataIndex++];
|
|
1286
|
-
}
|
|
1287
|
-
}
|
|
1288
|
-
}
|
|
1289
|
-
}
|
|
1290
|
-
}
|
|
1291
|
-
// now convert data from buffer into floats
|
|
1292
|
-
for (i = 0; i < scanline_width; i++) {
|
|
1293
|
-
a = scanLineArray[i];
|
|
1294
|
-
b = scanLineArray[i + scanline_width];
|
|
1295
|
-
c = scanLineArray[i + 2 * scanline_width];
|
|
1296
|
-
d = scanLineArray[i + 3 * scanline_width];
|
|
1297
|
-
this._Rgbe2float(resultArray, a, b, c, d, (hdrInfo.height - num_scanlines) * scanline_width * 3 + i * 3);
|
|
1298
|
-
}
|
|
1299
|
-
num_scanlines--;
|
|
1300
|
-
}
|
|
1301
|
-
return resultArray;
|
|
1302
|
-
}
|
|
1303
|
-
static _RGBEReadPixelsNOTRLE(uint8array, hdrInfo) {
|
|
1304
|
-
// this file is not run length encoded
|
|
1305
|
-
// read values sequentially
|
|
1306
|
-
let num_scanlines = hdrInfo.height;
|
|
1307
|
-
const scanline_width = hdrInfo.width;
|
|
1308
|
-
let a, b, c, d, i;
|
|
1309
|
-
let dataIndex = hdrInfo.dataPosition;
|
|
1310
|
-
// 3 channels of 4 bytes per pixel in float.
|
|
1311
|
-
const resultBuffer = new ArrayBuffer(hdrInfo.width * hdrInfo.height * 4 * 3);
|
|
1312
|
-
const resultArray = new Float32Array(resultBuffer);
|
|
1313
|
-
// read in each successive scanline
|
|
1314
|
-
while (num_scanlines > 0) {
|
|
1315
|
-
for (i = 0; i < hdrInfo.width; i++) {
|
|
1316
|
-
a = uint8array[dataIndex++];
|
|
1317
|
-
b = uint8array[dataIndex++];
|
|
1318
|
-
c = uint8array[dataIndex++];
|
|
1319
|
-
d = uint8array[dataIndex++];
|
|
1320
|
-
this._Rgbe2float(resultArray, a, b, c, d, (hdrInfo.height - num_scanlines) * scanline_width * 3 + i * 3);
|
|
1321
|
-
}
|
|
1322
|
-
num_scanlines--;
|
|
1323
|
-
}
|
|
1324
|
-
return resultArray;
|
|
1325
|
-
}
|
|
1326
|
-
}
|
|
1327
|
-
|
|
1328
|
-
// Do not edit.
|
|
1329
|
-
const name$1 = "hdrFilteringVertexShader";
|
|
1330
|
-
const shader$1 = `attribute vec2 position;
|
|
1331
|
-
void main(void) {
|
|
1332
|
-
mat3 view=mat3(up,right,front);
|
|
1333
|
-
}`;
|
|
1334
|
-
// Sideeffect
|
|
1335
|
-
ShaderStore.ShadersStore[name$1] = shader$1;
|
|
1336
|
-
|
|
1337
|
-
// Do not edit.
|
|
1338
|
-
const name = "hdrFilteringPixelShader";
|
|
1339
|
-
const shader = `#include<helperFunctions>
|
|
1340
|
-
#include<importanceSampling>
|
|
1341
|
-
#include<pbrBRDFFunctions>
|
|
1342
|
-
#include<hdrFilteringFunctions>
|
|
1343
|
-
uniform float alphaG;
|
|
1344
|
-
// Sideeffect
|
|
1345
|
-
ShaderStore.ShadersStore[name] = shader;
|
|
1346
|
-
|
|
1347
|
-
/**
|
|
1348
|
-
* Filters HDR maps to get correct renderings of PBR reflections
|
|
1349
|
-
*/
|
|
1350
|
-
class HDRFiltering {
|
|
1351
|
-
/**
|
|
1352
|
-
* Instantiates HDR filter for reflection maps
|
|
1353
|
-
*
|
|
1354
|
-
* @param engine Thin engine
|
|
1355
|
-
* @param options Options
|
|
1356
|
-
*/
|
|
1357
|
-
constructor(engine, options = {}) {
|
|
1358
|
-
this._lodGenerationOffset = 0;
|
|
1359
|
-
this._lodGenerationScale = 0.8;
|
|
1360
|
-
/**
|
|
1361
|
-
* Quality switch for prefiltering. Should be set to `4096` unless
|
|
1362
|
-
* you care about baking speed.
|
|
1363
|
-
*/
|
|
1364
|
-
this.quality = 4096;
|
|
1365
|
-
/**
|
|
1366
|
-
* Scales pixel intensity for the input HDR map.
|
|
1367
|
-
*/
|
|
1368
|
-
this.hdrScale = 1;
|
|
1369
|
-
// pass
|
|
1370
|
-
this._engine = engine;
|
|
1371
|
-
this.hdrScale = options.hdrScale || this.hdrScale;
|
|
1372
|
-
this.quality = options.quality || this.quality;
|
|
1373
|
-
}
|
|
1374
|
-
_createRenderTarget(size) {
|
|
1375
|
-
let textureType = 0;
|
|
1376
|
-
if (this._engine.getCaps().textureHalfFloatRender) {
|
|
1377
|
-
textureType = 2;
|
|
1378
|
-
}
|
|
1379
|
-
else if (this._engine.getCaps().textureFloatRender) {
|
|
1380
|
-
textureType = 1;
|
|
1381
|
-
}
|
|
1382
|
-
const rtWrapper = this._engine.createRenderTargetCubeTexture(size, {
|
|
1383
|
-
format: 5,
|
|
1384
|
-
type: textureType,
|
|
1385
|
-
createMipMaps: true,
|
|
1386
|
-
generateMipMaps: false,
|
|
1387
|
-
generateDepthBuffer: false,
|
|
1388
|
-
generateStencilBuffer: false,
|
|
1389
|
-
samplingMode: 1,
|
|
1390
|
-
});
|
|
1391
|
-
this._engine.updateTextureWrappingMode(rtWrapper.texture, 0, 0, 0);
|
|
1392
|
-
this._engine.updateTextureSamplingMode(3, rtWrapper.texture, true);
|
|
1393
|
-
return rtWrapper;
|
|
1394
|
-
}
|
|
1395
|
-
_prefilterInternal(texture) {
|
|
1396
|
-
const width = texture.getSize().width;
|
|
1397
|
-
const mipmapsCount = Scalar.ILog2(width) + 1;
|
|
1398
|
-
const effect = this._effectWrapper.effect;
|
|
1399
|
-
const outputTexture = this._createRenderTarget(width);
|
|
1400
|
-
this._effectRenderer.setViewport();
|
|
1401
|
-
const intTexture = texture.getInternalTexture();
|
|
1402
|
-
if (intTexture) {
|
|
1403
|
-
// Just in case generate fresh clean mips.
|
|
1404
|
-
this._engine.updateTextureSamplingMode(3, intTexture, true);
|
|
1405
|
-
}
|
|
1406
|
-
this._effectRenderer.applyEffectWrapper(this._effectWrapper);
|
|
1407
|
-
const directions = [
|
|
1408
|
-
[new Vector3(0, 0, -1), new Vector3(0, -1, 0), new Vector3(1, 0, 0)],
|
|
1409
|
-
[new Vector3(0, 0, 1), new Vector3(0, -1, 0), new Vector3(-1, 0, 0)],
|
|
1410
|
-
[new Vector3(1, 0, 0), new Vector3(0, 0, 1), new Vector3(0, 1, 0)],
|
|
1411
|
-
[new Vector3(1, 0, 0), new Vector3(0, 0, -1), new Vector3(0, -1, 0)],
|
|
1412
|
-
[new Vector3(1, 0, 0), new Vector3(0, -1, 0), new Vector3(0, 0, 1)],
|
|
1413
|
-
[new Vector3(-1, 0, 0), new Vector3(0, -1, 0), new Vector3(0, 0, -1)], // NegativeZ
|
|
1414
|
-
];
|
|
1415
|
-
effect.setFloat("hdrScale", this.hdrScale);
|
|
1416
|
-
effect.setFloat2("vFilteringInfo", texture.getSize().width, mipmapsCount);
|
|
1417
|
-
effect.setTexture("inputTexture", texture);
|
|
1418
|
-
for (let face = 0; face < 6; face++) {
|
|
1419
|
-
effect.setVector3("up", directions[face][0]);
|
|
1420
|
-
effect.setVector3("right", directions[face][1]);
|
|
1421
|
-
effect.setVector3("front", directions[face][2]);
|
|
1422
|
-
for (let lod = 0; lod < mipmapsCount; lod++) {
|
|
1423
|
-
this._engine.bindFramebuffer(outputTexture, face, undefined, undefined, true, lod);
|
|
1424
|
-
this._effectRenderer.applyEffectWrapper(this._effectWrapper);
|
|
1425
|
-
let alpha = Math.pow(2, (lod - this._lodGenerationOffset) / this._lodGenerationScale) / width;
|
|
1426
|
-
if (lod === 0) {
|
|
1427
|
-
alpha = 0;
|
|
1428
|
-
}
|
|
1429
|
-
effect.setFloat("alphaG", alpha);
|
|
1430
|
-
this._effectRenderer.draw();
|
|
1431
|
-
}
|
|
1432
|
-
}
|
|
1433
|
-
// Cleanup
|
|
1434
|
-
this._effectRenderer.restoreStates();
|
|
1435
|
-
this._engine.restoreDefaultFramebuffer();
|
|
1436
|
-
this._engine._releaseTexture(texture._texture);
|
|
1437
|
-
// Internal Swap
|
|
1438
|
-
const type = outputTexture.texture.type;
|
|
1439
|
-
const format = outputTexture.texture.format;
|
|
1440
|
-
outputTexture._swapAndDie(texture._texture);
|
|
1441
|
-
texture._texture.type = type;
|
|
1442
|
-
texture._texture.format = format;
|
|
1443
|
-
// New settings
|
|
1444
|
-
texture.gammaSpace = false;
|
|
1445
|
-
texture.lodGenerationOffset = this._lodGenerationOffset;
|
|
1446
|
-
texture.lodGenerationScale = this._lodGenerationScale;
|
|
1447
|
-
texture._prefiltered = true;
|
|
1448
|
-
return texture;
|
|
1449
|
-
}
|
|
1450
|
-
_createEffect(texture, onCompiled) {
|
|
1451
|
-
const defines = [];
|
|
1452
|
-
if (texture.gammaSpace) {
|
|
1453
|
-
defines.push("#define GAMMA_INPUT");
|
|
1454
|
-
}
|
|
1455
|
-
defines.push("#define NUM_SAMPLES " + this.quality + "u"); // unsigned int
|
|
1456
|
-
const effectWrapper = new EffectWrapper({
|
|
1457
|
-
engine: this._engine,
|
|
1458
|
-
name: "hdrFiltering",
|
|
1459
|
-
vertexShader: "hdrFiltering",
|
|
1460
|
-
fragmentShader: "hdrFiltering",
|
|
1461
|
-
samplerNames: ["inputTexture"],
|
|
1462
|
-
uniformNames: ["vSampleDirections", "vWeights", "up", "right", "front", "vFilteringInfo", "hdrScale", "alphaG"],
|
|
1463
|
-
useShaderStore: true,
|
|
1464
|
-
defines,
|
|
1465
|
-
onCompiled: onCompiled,
|
|
1466
|
-
});
|
|
1467
|
-
return effectWrapper;
|
|
1468
|
-
}
|
|
1469
|
-
/**
|
|
1470
|
-
* Get a value indicating if the filter is ready to be used
|
|
1471
|
-
* @param texture Texture to filter
|
|
1472
|
-
* @returns true if the filter is ready
|
|
1473
|
-
*/
|
|
1474
|
-
isReady(texture) {
|
|
1475
|
-
return texture.isReady() && this._effectWrapper.effect.isReady();
|
|
1476
|
-
}
|
|
1477
|
-
/**
|
|
1478
|
-
* Prefilters a cube texture to have mipmap levels representing roughness values.
|
|
1479
|
-
* Prefiltering will be invoked at the end of next rendering pass.
|
|
1480
|
-
* This has to be done once the map is loaded, and has not been prefiltered by a third party software.
|
|
1481
|
-
* See http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf for more information
|
|
1482
|
-
* @param texture Texture to filter
|
|
1483
|
-
* @param onFinished Callback when filtering is done
|
|
1484
|
-
* @returns Promise called when prefiltering is done
|
|
1485
|
-
*/
|
|
1486
|
-
prefilter(texture, onFinished = null) {
|
|
1487
|
-
if (!this._engine._features.allowTexturePrefiltering) {
|
|
1488
|
-
Logger.Warn("HDR prefiltering is not available in WebGL 1., you can use real time filtering instead.");
|
|
1489
|
-
return Promise.reject("HDR prefiltering is not available in WebGL 1., you can use real time filtering instead.");
|
|
1490
|
-
}
|
|
1491
|
-
return new Promise((resolve) => {
|
|
1492
|
-
this._effectRenderer = new EffectRenderer(this._engine);
|
|
1493
|
-
this._effectWrapper = this._createEffect(texture);
|
|
1494
|
-
this._effectWrapper.effect.executeWhenCompiled(() => {
|
|
1495
|
-
this._prefilterInternal(texture);
|
|
1496
|
-
this._effectRenderer.dispose();
|
|
1497
|
-
this._effectWrapper.dispose();
|
|
1498
|
-
resolve();
|
|
1499
|
-
if (onFinished) {
|
|
1500
|
-
onFinished();
|
|
1501
|
-
}
|
|
1502
|
-
});
|
|
1503
|
-
});
|
|
1504
|
-
}
|
|
1505
|
-
}
|
|
1506
|
-
|
|
1507
|
-
/**
|
|
1508
|
-
* This represents a texture coming from an HDR input.
|
|
1509
|
-
*
|
|
1510
|
-
* The only supported format is currently panorama picture stored in RGBE format.
|
|
1511
|
-
* Example of such files can be found on Poly Haven: https://polyhaven.com/hdris
|
|
1512
|
-
*/
|
|
1513
|
-
class HDRCubeTexture extends BaseTexture {
|
|
1514
|
-
/**
|
|
1515
|
-
* Sets whether or not the texture is blocking during loading.
|
|
1516
|
-
*/
|
|
1517
|
-
set isBlocking(value) {
|
|
1518
|
-
this._isBlocking = value;
|
|
1519
|
-
}
|
|
1520
|
-
/**
|
|
1521
|
-
* Gets whether or not the texture is blocking during loading.
|
|
1522
|
-
*/
|
|
1523
|
-
get isBlocking() {
|
|
1524
|
-
return this._isBlocking;
|
|
1525
|
-
}
|
|
1526
|
-
/**
|
|
1527
|
-
* Sets texture matrix rotation angle around Y axis in radians.
|
|
1528
|
-
*/
|
|
1529
|
-
set rotationY(value) {
|
|
1530
|
-
this._rotationY = value;
|
|
1531
|
-
this.setReflectionTextureMatrix(Matrix.RotationY(this._rotationY));
|
|
1532
|
-
}
|
|
1533
|
-
/**
|
|
1534
|
-
* Gets texture matrix rotation angle around Y axis radians.
|
|
1535
|
-
*/
|
|
1536
|
-
get rotationY() {
|
|
1537
|
-
return this._rotationY;
|
|
1538
|
-
}
|
|
1539
|
-
/**
|
|
1540
|
-
* Gets or sets the size of the bounding box associated with the cube texture
|
|
1541
|
-
* When defined, the cubemap will switch to local mode
|
|
1542
|
-
* @see https://community.arm.com/graphics/b/blog/posts/reflections-based-on-local-cubemaps-in-unity
|
|
1543
|
-
* @example https://www.babylonjs-playground.com/#RNASML
|
|
1544
|
-
*/
|
|
1545
|
-
set boundingBoxSize(value) {
|
|
1546
|
-
if (this._boundingBoxSize && this._boundingBoxSize.equals(value)) {
|
|
1547
|
-
return;
|
|
1548
|
-
}
|
|
1549
|
-
this._boundingBoxSize = value;
|
|
1550
|
-
const scene = this.getScene();
|
|
1551
|
-
if (scene) {
|
|
1552
|
-
scene.markAllMaterialsAsDirty(1);
|
|
1553
|
-
}
|
|
1554
|
-
}
|
|
1555
|
-
get boundingBoxSize() {
|
|
1556
|
-
return this._boundingBoxSize;
|
|
1557
|
-
}
|
|
1558
|
-
/**
|
|
1559
|
-
* Instantiates an HDRTexture from the following parameters.
|
|
1560
|
-
*
|
|
1561
|
-
* @param url The location of the HDR raw data (Panorama stored in RGBE format)
|
|
1562
|
-
* @param sceneOrEngine The scene or engine the texture will be used in
|
|
1563
|
-
* @param size The cubemap desired size (the more it increases the longer the generation will be)
|
|
1564
|
-
* @param noMipmap Forces to not generate the mipmap if true
|
|
1565
|
-
* @param generateHarmonics Specifies whether you want to extract the polynomial harmonics during the generation process
|
|
1566
|
-
* @param gammaSpace Specifies if the texture will be use in gamma or linear space (the PBR material requires those texture in linear space, but the standard material would require them in Gamma space)
|
|
1567
|
-
* @param prefilterOnLoad Prefilters HDR texture to allow use of this texture as a PBR reflection texture.
|
|
1568
|
-
* @param onLoad
|
|
1569
|
-
* @param onError
|
|
1570
|
-
*/
|
|
1571
|
-
constructor(url, sceneOrEngine, size, noMipmap = false, generateHarmonics = true, gammaSpace = false, prefilterOnLoad = false, onLoad = null, onError = null, supersample = false) {
|
|
1572
|
-
var _a;
|
|
1573
|
-
super(sceneOrEngine);
|
|
1574
|
-
this._generateHarmonics = true;
|
|
1575
|
-
this._onError = null;
|
|
1576
|
-
this._isBlocking = true;
|
|
1577
|
-
this._rotationY = 0;
|
|
1578
|
-
/**
|
|
1579
|
-
* Gets or sets the center of the bounding box associated with the cube texture
|
|
1580
|
-
* It must define where the camera used to render the texture was set
|
|
1581
|
-
*/
|
|
1582
|
-
this.boundingBoxPosition = Vector3.Zero();
|
|
1583
|
-
/**
|
|
1584
|
-
* Observable triggered once the texture has been loaded.
|
|
1585
|
-
*/
|
|
1586
|
-
this.onLoadObservable = new Observable();
|
|
1587
|
-
if (!url) {
|
|
1588
|
-
return;
|
|
1589
|
-
}
|
|
1590
|
-
this._coordinatesMode = Texture.CUBIC_MODE;
|
|
1591
|
-
this.name = url;
|
|
1592
|
-
this.url = url;
|
|
1593
|
-
this.hasAlpha = false;
|
|
1594
|
-
this.isCube = true;
|
|
1595
|
-
this._textureMatrix = Matrix.Identity();
|
|
1596
|
-
this._prefilterOnLoad = prefilterOnLoad;
|
|
1597
|
-
this._onLoad = () => {
|
|
1598
|
-
this.onLoadObservable.notifyObservers(this);
|
|
1599
|
-
if (onLoad) {
|
|
1600
|
-
onLoad();
|
|
1601
|
-
}
|
|
1602
|
-
};
|
|
1603
|
-
this._onError = onError;
|
|
1604
|
-
this.gammaSpace = gammaSpace;
|
|
1605
|
-
this._noMipmap = noMipmap;
|
|
1606
|
-
this._size = size;
|
|
1607
|
-
this._supersample = supersample;
|
|
1608
|
-
this._generateHarmonics = generateHarmonics;
|
|
1609
|
-
this._texture = this._getFromCache(url, this._noMipmap, undefined, undefined, undefined, this.isCube);
|
|
1610
|
-
if (!this._texture) {
|
|
1611
|
-
if (!((_a = this.getScene()) === null || _a === void 0 ? void 0 : _a.useDelayedTextureLoading)) {
|
|
1612
|
-
this._loadTexture();
|
|
1613
|
-
}
|
|
1614
|
-
else {
|
|
1615
|
-
this.delayLoadState = 4;
|
|
1616
|
-
}
|
|
1617
|
-
}
|
|
1618
|
-
else {
|
|
1619
|
-
if (this._texture.isReady) {
|
|
1620
|
-
Tools.SetImmediate(() => this._onLoad());
|
|
1621
|
-
}
|
|
1622
|
-
else {
|
|
1623
|
-
this._texture.onLoadedObservable.add(this._onLoad);
|
|
1624
|
-
}
|
|
1625
|
-
}
|
|
1626
|
-
}
|
|
1627
|
-
/**
|
|
1628
|
-
* Get the current class name of the texture useful for serialization or dynamic coding.
|
|
1629
|
-
* @returns "HDRCubeTexture"
|
|
1630
|
-
*/
|
|
1631
|
-
getClassName() {
|
|
1632
|
-
return "HDRCubeTexture";
|
|
1633
|
-
}
|
|
1634
|
-
/**
|
|
1635
|
-
* Occurs when the file is raw .hdr file.
|
|
1636
|
-
*/
|
|
1637
|
-
_loadTexture() {
|
|
1638
|
-
const engine = this._getEngine();
|
|
1639
|
-
const caps = engine.getCaps();
|
|
1640
|
-
let textureType = 0;
|
|
1641
|
-
if (caps.textureFloat && caps.textureFloatLinearFiltering) {
|
|
1642
|
-
textureType = 1;
|
|
1643
|
-
}
|
|
1644
|
-
else if (caps.textureHalfFloat && caps.textureHalfFloatLinearFiltering) {
|
|
1645
|
-
textureType = 2;
|
|
1646
|
-
}
|
|
1647
|
-
const callback = (buffer) => {
|
|
1648
|
-
this.lodGenerationOffset = 0.0;
|
|
1649
|
-
this.lodGenerationScale = 0.8;
|
|
1650
|
-
// Extract the raw linear data.
|
|
1651
|
-
const data = HDRTools.GetCubeMapTextureData(buffer, this._size, this._supersample);
|
|
1652
|
-
// Generate harmonics if needed.
|
|
1653
|
-
if (this._generateHarmonics) {
|
|
1654
|
-
const sphericalPolynomial = CubeMapToSphericalPolynomialTools.ConvertCubeMapToSphericalPolynomial(data);
|
|
1655
|
-
this.sphericalPolynomial = sphericalPolynomial;
|
|
1656
|
-
}
|
|
1657
|
-
const results = [];
|
|
1658
|
-
let byteArray = null;
|
|
1659
|
-
let shortArray = null;
|
|
1660
|
-
// Push each faces.
|
|
1661
|
-
for (let j = 0; j < 6; j++) {
|
|
1662
|
-
// Create fallback array
|
|
1663
|
-
if (textureType === 2) {
|
|
1664
|
-
shortArray = new Uint16Array(this._size * this._size * 3);
|
|
1665
|
-
}
|
|
1666
|
-
else if (textureType === 0) {
|
|
1667
|
-
// 3 channels of 1 bytes per pixel in bytes.
|
|
1668
|
-
byteArray = new Uint8Array(this._size * this._size * 3);
|
|
1669
|
-
}
|
|
1670
|
-
const dataFace = data[HDRCubeTexture._FacesMapping[j]];
|
|
1671
|
-
// If special cases.
|
|
1672
|
-
if (this.gammaSpace || shortArray || byteArray) {
|
|
1673
|
-
for (let i = 0; i < this._size * this._size; i++) {
|
|
1674
|
-
// Put in gamma space if requested.
|
|
1675
|
-
if (this.gammaSpace) {
|
|
1676
|
-
dataFace[i * 3 + 0] = Math.pow(dataFace[i * 3 + 0], ToGammaSpace);
|
|
1677
|
-
dataFace[i * 3 + 1] = Math.pow(dataFace[i * 3 + 1], ToGammaSpace);
|
|
1678
|
-
dataFace[i * 3 + 2] = Math.pow(dataFace[i * 3 + 2], ToGammaSpace);
|
|
1679
|
-
}
|
|
1680
|
-
// Convert to half float texture for fallback.
|
|
1681
|
-
if (shortArray) {
|
|
1682
|
-
shortArray[i * 3 + 0] = ToHalfFloat(dataFace[i * 3 + 0]);
|
|
1683
|
-
shortArray[i * 3 + 1] = ToHalfFloat(dataFace[i * 3 + 1]);
|
|
1684
|
-
shortArray[i * 3 + 2] = ToHalfFloat(dataFace[i * 3 + 2]);
|
|
1685
|
-
}
|
|
1686
|
-
// Convert to int texture for fallback.
|
|
1687
|
-
if (byteArray) {
|
|
1688
|
-
let r = Math.max(dataFace[i * 3 + 0] * 255, 0);
|
|
1689
|
-
let g = Math.max(dataFace[i * 3 + 1] * 255, 0);
|
|
1690
|
-
let b = Math.max(dataFace[i * 3 + 2] * 255, 0);
|
|
1691
|
-
// May use luminance instead if the result is not accurate.
|
|
1692
|
-
const max = Math.max(Math.max(r, g), b);
|
|
1693
|
-
if (max > 255) {
|
|
1694
|
-
const scale = 255 / max;
|
|
1695
|
-
r *= scale;
|
|
1696
|
-
g *= scale;
|
|
1697
|
-
b *= scale;
|
|
1698
|
-
}
|
|
1699
|
-
byteArray[i * 3 + 0] = r;
|
|
1700
|
-
byteArray[i * 3 + 1] = g;
|
|
1701
|
-
byteArray[i * 3 + 2] = b;
|
|
1702
|
-
}
|
|
1703
|
-
}
|
|
1704
|
-
}
|
|
1705
|
-
if (shortArray) {
|
|
1706
|
-
results.push(shortArray);
|
|
1707
|
-
}
|
|
1708
|
-
else if (byteArray) {
|
|
1709
|
-
results.push(byteArray);
|
|
1710
|
-
}
|
|
1711
|
-
else {
|
|
1712
|
-
results.push(dataFace);
|
|
1713
|
-
}
|
|
1714
|
-
}
|
|
1715
|
-
return results;
|
|
1716
|
-
};
|
|
1717
|
-
if (engine._features.allowTexturePrefiltering && this._prefilterOnLoad) {
|
|
1718
|
-
const previousOnLoad = this._onLoad;
|
|
1719
|
-
const hdrFiltering = new HDRFiltering(engine);
|
|
1720
|
-
this._onLoad = () => {
|
|
1721
|
-
hdrFiltering.prefilter(this, previousOnLoad);
|
|
1722
|
-
};
|
|
1723
|
-
}
|
|
1724
|
-
this._texture = engine.createRawCubeTextureFromUrl(this.url, this.getScene(), this._size, 4, textureType, this._noMipmap, callback, null, this._onLoad, this._onError);
|
|
1725
|
-
}
|
|
1726
|
-
clone() {
|
|
1727
|
-
const newTexture = new HDRCubeTexture(this.url, this.getScene() || this._getEngine(), this._size, this._noMipmap, this._generateHarmonics, this.gammaSpace);
|
|
1728
|
-
// Base texture
|
|
1729
|
-
newTexture.level = this.level;
|
|
1730
|
-
newTexture.wrapU = this.wrapU;
|
|
1731
|
-
newTexture.wrapV = this.wrapV;
|
|
1732
|
-
newTexture.coordinatesIndex = this.coordinatesIndex;
|
|
1733
|
-
newTexture.coordinatesMode = this.coordinatesMode;
|
|
1734
|
-
return newTexture;
|
|
1735
|
-
}
|
|
1736
|
-
// Methods
|
|
1737
|
-
delayLoad() {
|
|
1738
|
-
if (this.delayLoadState !== 4) {
|
|
1739
|
-
return;
|
|
1740
|
-
}
|
|
1741
|
-
this.delayLoadState = 1;
|
|
1742
|
-
this._texture = this._getFromCache(this.url, this._noMipmap);
|
|
1743
|
-
if (!this._texture) {
|
|
1744
|
-
this._loadTexture();
|
|
1745
|
-
}
|
|
1746
|
-
}
|
|
1747
|
-
/**
|
|
1748
|
-
* Get the texture reflection matrix used to rotate/transform the reflection.
|
|
1749
|
-
* @returns the reflection matrix
|
|
1750
|
-
*/
|
|
1751
|
-
getReflectionTextureMatrix() {
|
|
1752
|
-
return this._textureMatrix;
|
|
1753
|
-
}
|
|
1754
|
-
/**
|
|
1755
|
-
* Set the texture reflection matrix used to rotate/transform the reflection.
|
|
1756
|
-
* @param value Define the reflection matrix to set
|
|
1757
|
-
*/
|
|
1758
|
-
setReflectionTextureMatrix(value) {
|
|
1759
|
-
var _a;
|
|
1760
|
-
this._textureMatrix = value;
|
|
1761
|
-
if (value.updateFlag === this._textureMatrix.updateFlag) {
|
|
1762
|
-
return;
|
|
1763
|
-
}
|
|
1764
|
-
if (value.isIdentity() !== this._textureMatrix.isIdentity()) {
|
|
1765
|
-
(_a = this.getScene()) === null || _a === void 0 ? void 0 : _a.markAllMaterialsAsDirty(1, (mat) => mat.getActiveTextures().indexOf(this) !== -1);
|
|
1766
|
-
}
|
|
1767
|
-
}
|
|
1768
|
-
/**
|
|
1769
|
-
* Dispose the texture and release its associated resources.
|
|
1770
|
-
*/
|
|
1771
|
-
dispose() {
|
|
1772
|
-
this.onLoadObservable.clear();
|
|
1773
|
-
super.dispose();
|
|
1774
|
-
}
|
|
1775
|
-
/**
|
|
1776
|
-
* Parses a JSON representation of an HDR Texture in order to create the texture
|
|
1777
|
-
* @param parsedTexture Define the JSON representation
|
|
1778
|
-
* @param scene Define the scene the texture should be created in
|
|
1779
|
-
* @param rootUrl Define the root url in case we need to load relative dependencies
|
|
1780
|
-
* @returns the newly created texture after parsing
|
|
1781
|
-
*/
|
|
1782
|
-
static Parse(parsedTexture, scene, rootUrl) {
|
|
1783
|
-
let texture = null;
|
|
1784
|
-
if (parsedTexture.name && !parsedTexture.isRenderTarget) {
|
|
1785
|
-
texture = new HDRCubeTexture(rootUrl + parsedTexture.name, scene, parsedTexture.size, parsedTexture.noMipmap, parsedTexture.generateHarmonics, parsedTexture.useInGammaSpace);
|
|
1786
|
-
texture.name = parsedTexture.name;
|
|
1787
|
-
texture.hasAlpha = parsedTexture.hasAlpha;
|
|
1788
|
-
texture.level = parsedTexture.level;
|
|
1789
|
-
texture.coordinatesMode = parsedTexture.coordinatesMode;
|
|
1790
|
-
texture.isBlocking = parsedTexture.isBlocking;
|
|
1791
|
-
}
|
|
1792
|
-
if (texture) {
|
|
1793
|
-
if (parsedTexture.boundingBoxPosition) {
|
|
1794
|
-
texture.boundingBoxPosition = Vector3.FromArray(parsedTexture.boundingBoxPosition);
|
|
1795
|
-
}
|
|
1796
|
-
if (parsedTexture.boundingBoxSize) {
|
|
1797
|
-
texture.boundingBoxSize = Vector3.FromArray(parsedTexture.boundingBoxSize);
|
|
1798
|
-
}
|
|
1799
|
-
if (parsedTexture.rotationY) {
|
|
1800
|
-
texture.rotationY = parsedTexture.rotationY;
|
|
1801
|
-
}
|
|
1802
|
-
}
|
|
1803
|
-
return texture;
|
|
1804
|
-
}
|
|
1805
|
-
serialize() {
|
|
1806
|
-
if (!this.name) {
|
|
1807
|
-
return null;
|
|
1808
|
-
}
|
|
1809
|
-
const serializationObject = {};
|
|
1810
|
-
serializationObject.name = this.name;
|
|
1811
|
-
serializationObject.hasAlpha = this.hasAlpha;
|
|
1812
|
-
serializationObject.isCube = true;
|
|
1813
|
-
serializationObject.level = this.level;
|
|
1814
|
-
serializationObject.size = this._size;
|
|
1815
|
-
serializationObject.coordinatesMode = this.coordinatesMode;
|
|
1816
|
-
serializationObject.useInGammaSpace = this.gammaSpace;
|
|
1817
|
-
serializationObject.generateHarmonics = this._generateHarmonics;
|
|
1818
|
-
serializationObject.customType = "BABYLON.HDRCubeTexture";
|
|
1819
|
-
serializationObject.noMipmap = this._noMipmap;
|
|
1820
|
-
serializationObject.isBlocking = this._isBlocking;
|
|
1821
|
-
serializationObject.rotationY = this._rotationY;
|
|
1822
|
-
return serializationObject;
|
|
1823
|
-
}
|
|
1824
|
-
}
|
|
1825
|
-
HDRCubeTexture._FacesMapping = ["right", "left", "up", "down", "front", "back"];
|
|
1826
|
-
RegisterClass("BABYLON.HDRCubeTexture", HDRCubeTexture);
|
|
1827
|
-
|
|
1828
|
-
/**
|
|
1829
|
-
* This represents a texture coming from an equirectangular image supported by the web browser canvas.
|
|
1830
|
-
*/
|
|
1831
|
-
class EquiRectangularCubeTexture extends BaseTexture {
|
|
1832
|
-
/**
|
|
1833
|
-
* Instantiates an EquiRectangularCubeTexture from the following parameters.
|
|
1834
|
-
* @param url The location of the image
|
|
1835
|
-
* @param scene The scene the texture will be used in
|
|
1836
|
-
* @param size The cubemap desired size (the more it increases the longer the generation will be)
|
|
1837
|
-
* @param noMipmap Forces to not generate the mipmap if true
|
|
1838
|
-
* @param gammaSpace Specifies if the texture will be used in gamma or linear space
|
|
1839
|
-
* (the PBR material requires those textures in linear space, but the standard material would require them in Gamma space)
|
|
1840
|
-
* @param onLoad — defines a callback called when texture is loaded
|
|
1841
|
-
* @param onError — defines a callback called if there is an error
|
|
1842
|
-
*/
|
|
1843
|
-
constructor(url, scene, size, noMipmap = false, gammaSpace = true, onLoad = null, onError = null, supersample = false) {
|
|
1844
|
-
super(scene);
|
|
1845
|
-
this._onLoad = null;
|
|
1846
|
-
this._onError = null;
|
|
1847
|
-
if (!url) {
|
|
1848
|
-
throw new Error("Image url is not set");
|
|
1849
|
-
}
|
|
1850
|
-
this._coordinatesMode = Texture.CUBIC_MODE;
|
|
1851
|
-
this.name = url;
|
|
1852
|
-
this.url = url;
|
|
1853
|
-
this._size = size;
|
|
1854
|
-
this._supersample = supersample;
|
|
1855
|
-
this._noMipmap = noMipmap;
|
|
1856
|
-
this.gammaSpace = gammaSpace;
|
|
1857
|
-
this._onLoad = onLoad;
|
|
1858
|
-
this._onError = onError;
|
|
1859
|
-
this.hasAlpha = false;
|
|
1860
|
-
this.isCube = true;
|
|
1861
|
-
this._texture = this._getFromCache(url, this._noMipmap, undefined, undefined, undefined, this.isCube);
|
|
1862
|
-
if (!this._texture) {
|
|
1863
|
-
if (!scene.useDelayedTextureLoading) {
|
|
1864
|
-
this._loadImage(this._loadTexture.bind(this), this._onError);
|
|
1865
|
-
}
|
|
1866
|
-
else {
|
|
1867
|
-
this.delayLoadState = 4;
|
|
1868
|
-
}
|
|
1869
|
-
}
|
|
1870
|
-
else if (onLoad) {
|
|
1871
|
-
if (this._texture.isReady) {
|
|
1872
|
-
Tools.SetImmediate(() => onLoad());
|
|
1873
|
-
}
|
|
1874
|
-
else {
|
|
1875
|
-
this._texture.onLoadedObservable.add(onLoad);
|
|
1876
|
-
}
|
|
1877
|
-
}
|
|
1878
|
-
}
|
|
1879
|
-
/**
|
|
1880
|
-
* Load the image data, by putting the image on a canvas and extracting its buffer.
|
|
1881
|
-
* @param loadTextureCallback
|
|
1882
|
-
* @param onError
|
|
1883
|
-
*/
|
|
1884
|
-
_loadImage(loadTextureCallback, onError) {
|
|
1885
|
-
const canvas = document.createElement("canvas");
|
|
1886
|
-
LoadImage(this.url, (image) => {
|
|
1887
|
-
this._width = image.width;
|
|
1888
|
-
this._height = image.height;
|
|
1889
|
-
canvas.width = this._width;
|
|
1890
|
-
canvas.height = this._height;
|
|
1891
|
-
const ctx = canvas.getContext("2d");
|
|
1892
|
-
ctx.drawImage(image, 0, 0);
|
|
1893
|
-
const imageData = ctx.getImageData(0, 0, image.width, image.height);
|
|
1894
|
-
this._buffer = imageData.data.buffer;
|
|
1895
|
-
canvas.remove();
|
|
1896
|
-
loadTextureCallback();
|
|
1897
|
-
}, (_, e) => {
|
|
1898
|
-
if (onError) {
|
|
1899
|
-
onError(`${this.getClassName()} could not be loaded`, e);
|
|
1900
|
-
}
|
|
1901
|
-
}, null);
|
|
1902
|
-
}
|
|
1903
|
-
/**
|
|
1904
|
-
* Convert the image buffer into a cubemap and create a CubeTexture.
|
|
1905
|
-
*/
|
|
1906
|
-
_loadTexture() {
|
|
1907
|
-
const scene = this.getScene();
|
|
1908
|
-
const callback = () => {
|
|
1909
|
-
const imageData = this._getFloat32ArrayFromArrayBuffer(this._buffer);
|
|
1910
|
-
// Extract the raw linear data.
|
|
1911
|
-
const data = PanoramaToCubeMapTools.ConvertPanoramaToCubemap(imageData, this._width, this._height, this._size, this._supersample);
|
|
1912
|
-
const results = [];
|
|
1913
|
-
// Push each faces.
|
|
1914
|
-
for (let i = 0; i < 6; i++) {
|
|
1915
|
-
const dataFace = data[EquiRectangularCubeTexture._FacesMapping[i]];
|
|
1916
|
-
results.push(dataFace);
|
|
1917
|
-
}
|
|
1918
|
-
return results;
|
|
1919
|
-
};
|
|
1920
|
-
if (!scene) {
|
|
1921
|
-
return;
|
|
1922
|
-
}
|
|
1923
|
-
this._texture = scene
|
|
1924
|
-
.getEngine()
|
|
1925
|
-
.createRawCubeTextureFromUrl(this.url, scene, this._size, 4, scene.getEngine().getCaps().textureFloat ? 1 : 7, this._noMipmap, callback, null, this._onLoad, this._onError);
|
|
1926
|
-
}
|
|
1927
|
-
/**
|
|
1928
|
-
* Convert the ArrayBuffer into a Float32Array and drop the transparency channel.
|
|
1929
|
-
* @param buffer The ArrayBuffer that should be converted.
|
|
1930
|
-
* @returns The buffer as Float32Array.
|
|
1931
|
-
*/
|
|
1932
|
-
_getFloat32ArrayFromArrayBuffer(buffer) {
|
|
1933
|
-
const dataView = new DataView(buffer);
|
|
1934
|
-
const floatImageData = new Float32Array((buffer.byteLength * 3) / 4);
|
|
1935
|
-
let k = 0;
|
|
1936
|
-
for (let i = 0; i < buffer.byteLength; i++) {
|
|
1937
|
-
// We drop the transparency channel, because we do not need/want it
|
|
1938
|
-
if ((i + 1) % 4 !== 0) {
|
|
1939
|
-
floatImageData[k++] = dataView.getUint8(i) / 255;
|
|
1940
|
-
}
|
|
1941
|
-
}
|
|
1942
|
-
return floatImageData;
|
|
1943
|
-
}
|
|
1944
|
-
/**
|
|
1945
|
-
* Get the current class name of the texture useful for serialization or dynamic coding.
|
|
1946
|
-
* @returns "EquiRectangularCubeTexture"
|
|
1947
|
-
*/
|
|
1948
|
-
getClassName() {
|
|
1949
|
-
return "EquiRectangularCubeTexture";
|
|
1950
|
-
}
|
|
1951
|
-
/**
|
|
1952
|
-
* Create a clone of the current EquiRectangularCubeTexture and return it.
|
|
1953
|
-
* @returns A clone of the current EquiRectangularCubeTexture.
|
|
1954
|
-
*/
|
|
1955
|
-
clone() {
|
|
1956
|
-
const scene = this.getScene();
|
|
1957
|
-
if (!scene) {
|
|
1958
|
-
return this;
|
|
1959
|
-
}
|
|
1960
|
-
const newTexture = new EquiRectangularCubeTexture(this.url, scene, this._size, this._noMipmap, this.gammaSpace);
|
|
1961
|
-
// Base texture
|
|
1962
|
-
newTexture.level = this.level;
|
|
1963
|
-
newTexture.wrapU = this.wrapU;
|
|
1964
|
-
newTexture.wrapV = this.wrapV;
|
|
1965
|
-
newTexture.coordinatesIndex = this.coordinatesIndex;
|
|
1966
|
-
newTexture.coordinatesMode = this.coordinatesMode;
|
|
1967
|
-
return newTexture;
|
|
1968
|
-
}
|
|
1969
|
-
}
|
|
1970
|
-
/** The six faces of the cube. */
|
|
1971
|
-
EquiRectangularCubeTexture._FacesMapping = ["right", "left", "up", "down", "front", "back"];
|
|
1972
|
-
|
|
1973
|
-
/**
|
|
1974
|
-
* Defines the list of states available for a task inside a AssetsManager
|
|
1975
|
-
*/
|
|
1976
|
-
var AssetTaskState;
|
|
1977
|
-
(function (AssetTaskState) {
|
|
1978
|
-
/**
|
|
1979
|
-
* Initialization
|
|
1980
|
-
*/
|
|
1981
|
-
AssetTaskState[AssetTaskState["INIT"] = 0] = "INIT";
|
|
1982
|
-
/**
|
|
1983
|
-
* Running
|
|
1984
|
-
*/
|
|
1985
|
-
AssetTaskState[AssetTaskState["RUNNING"] = 1] = "RUNNING";
|
|
1986
|
-
/**
|
|
1987
|
-
* Done
|
|
1988
|
-
*/
|
|
1989
|
-
AssetTaskState[AssetTaskState["DONE"] = 2] = "DONE";
|
|
1990
|
-
/**
|
|
1991
|
-
* Error
|
|
1992
|
-
*/
|
|
1993
|
-
AssetTaskState[AssetTaskState["ERROR"] = 3] = "ERROR";
|
|
1994
|
-
})(AssetTaskState || (AssetTaskState = {}));
|
|
1995
|
-
/**
|
|
1996
|
-
* Define an abstract asset task used with a AssetsManager class to load assets into a scene
|
|
1997
|
-
*/
|
|
1998
|
-
class AbstractAssetTask {
|
|
1999
|
-
/**
|
|
2000
|
-
* Creates a new AssetsManager
|
|
2001
|
-
* @param name defines the name of the task
|
|
2002
|
-
*/
|
|
2003
|
-
constructor(
|
|
2004
|
-
/**
|
|
2005
|
-
* Task name
|
|
2006
|
-
*/ name) {
|
|
2007
|
-
this.name = name;
|
|
2008
|
-
this._isCompleted = false;
|
|
2009
|
-
this._taskState = AssetTaskState.INIT;
|
|
2010
|
-
}
|
|
2011
|
-
/**
|
|
2012
|
-
* Get if the task is completed
|
|
2013
|
-
*/
|
|
2014
|
-
get isCompleted() {
|
|
2015
|
-
return this._isCompleted;
|
|
2016
|
-
}
|
|
2017
|
-
/**
|
|
2018
|
-
* Gets the current state of the task
|
|
2019
|
-
*/
|
|
2020
|
-
get taskState() {
|
|
2021
|
-
return this._taskState;
|
|
2022
|
-
}
|
|
2023
|
-
/**
|
|
2024
|
-
* Gets the current error object (if task is in error)
|
|
2025
|
-
*/
|
|
2026
|
-
get errorObject() {
|
|
2027
|
-
return this._errorObject;
|
|
2028
|
-
}
|
|
2029
|
-
/**
|
|
2030
|
-
* Internal only
|
|
2031
|
-
* @internal
|
|
2032
|
-
*/
|
|
2033
|
-
_setErrorObject(message, exception) {
|
|
2034
|
-
if (this._errorObject) {
|
|
2035
|
-
return;
|
|
2036
|
-
}
|
|
2037
|
-
this._errorObject = {
|
|
2038
|
-
message: message,
|
|
2039
|
-
exception: exception,
|
|
2040
|
-
};
|
|
2041
|
-
}
|
|
2042
|
-
/**
|
|
2043
|
-
* Execute the current task
|
|
2044
|
-
* @param scene defines the scene where you want your assets to be loaded
|
|
2045
|
-
* @param onSuccess is a callback called when the task is successfully executed
|
|
2046
|
-
* @param onError is a callback called if an error occurs
|
|
2047
|
-
*/
|
|
2048
|
-
run(scene, onSuccess, onError) {
|
|
2049
|
-
this._taskState = AssetTaskState.RUNNING;
|
|
2050
|
-
this.runTask(scene, () => {
|
|
2051
|
-
this._onDoneCallback(onSuccess, onError);
|
|
2052
|
-
}, (msg, exception) => {
|
|
2053
|
-
this._onErrorCallback(onError, msg, exception);
|
|
2054
|
-
});
|
|
2055
|
-
}
|
|
2056
|
-
/**
|
|
2057
|
-
* Execute the current task
|
|
2058
|
-
* @param scene defines the scene where you want your assets to be loaded
|
|
2059
|
-
* @param onSuccess is a callback called when the task is successfully executed
|
|
2060
|
-
* @param onError is a callback called if an error occurs
|
|
2061
|
-
*/
|
|
2062
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2063
|
-
runTask(scene, onSuccess, onError) {
|
|
2064
|
-
throw new Error("runTask is not implemented");
|
|
2065
|
-
}
|
|
2066
|
-
/**
|
|
2067
|
-
* Reset will set the task state back to INIT, so the next load call of the assets manager will execute this task again.
|
|
2068
|
-
* This can be used with failed tasks that have the reason for failure fixed.
|
|
2069
|
-
*/
|
|
2070
|
-
reset() {
|
|
2071
|
-
this._taskState = AssetTaskState.INIT;
|
|
2072
|
-
}
|
|
2073
|
-
_onErrorCallback(onError, message, exception) {
|
|
2074
|
-
this._taskState = AssetTaskState.ERROR;
|
|
2075
|
-
this._errorObject = {
|
|
2076
|
-
message: message,
|
|
2077
|
-
exception: exception,
|
|
2078
|
-
};
|
|
2079
|
-
if (this.onError) {
|
|
2080
|
-
this.onError(this, message, exception);
|
|
2081
|
-
}
|
|
2082
|
-
onError();
|
|
2083
|
-
}
|
|
2084
|
-
_onDoneCallback(onSuccess, onError) {
|
|
2085
|
-
try {
|
|
2086
|
-
this._taskState = AssetTaskState.DONE;
|
|
2087
|
-
this._isCompleted = true;
|
|
2088
|
-
if (this.onSuccess) {
|
|
2089
|
-
this.onSuccess(this);
|
|
2090
|
-
}
|
|
2091
|
-
onSuccess();
|
|
2092
|
-
}
|
|
2093
|
-
catch (e) {
|
|
2094
|
-
this._onErrorCallback(onError, "Task is done, error executing success callback(s)", e);
|
|
2095
|
-
}
|
|
2096
|
-
}
|
|
2097
|
-
}
|
|
2098
|
-
/**
|
|
2099
|
-
* Class used to share progress information about assets loading
|
|
2100
|
-
*/
|
|
2101
|
-
class AssetsProgressEvent {
|
|
2102
|
-
/**
|
|
2103
|
-
* Creates a AssetsProgressEvent
|
|
2104
|
-
* @param remainingCount defines the number of remaining tasks to process
|
|
2105
|
-
* @param totalCount defines the total number of tasks
|
|
2106
|
-
* @param task defines the task that was just processed
|
|
2107
|
-
*/
|
|
2108
|
-
constructor(remainingCount, totalCount, task) {
|
|
2109
|
-
this.remainingCount = remainingCount;
|
|
2110
|
-
this.totalCount = totalCount;
|
|
2111
|
-
this.task = task;
|
|
2112
|
-
}
|
|
2113
|
-
}
|
|
2114
|
-
/**
|
|
2115
|
-
* Define a task used by AssetsManager to load assets into a container
|
|
2116
|
-
*/
|
|
2117
|
-
class ContainerAssetTask extends AbstractAssetTask {
|
|
2118
|
-
/**
|
|
2119
|
-
* Creates a new ContainerAssetTask
|
|
2120
|
-
* @param name defines the name of the task
|
|
2121
|
-
* @param meshesNames defines the list of mesh's names you want to load
|
|
2122
|
-
* @param rootUrl defines the root url to use as a base to load your meshes and associated resources
|
|
2123
|
-
* @param sceneFilename defines the filename or File of the scene to load from
|
|
2124
|
-
*/
|
|
2125
|
-
constructor(
|
|
2126
|
-
/**
|
|
2127
|
-
* Defines the name of the task
|
|
2128
|
-
*/
|
|
2129
|
-
name,
|
|
2130
|
-
/**
|
|
2131
|
-
* Defines the list of mesh's names you want to load
|
|
2132
|
-
*/
|
|
2133
|
-
meshesNames,
|
|
2134
|
-
/**
|
|
2135
|
-
* Defines the root url to use as a base to load your meshes and associated resources
|
|
2136
|
-
*/
|
|
2137
|
-
rootUrl,
|
|
2138
|
-
/**
|
|
2139
|
-
* Defines the filename or File of the scene to load from
|
|
2140
|
-
*/
|
|
2141
|
-
sceneFilename,
|
|
2142
|
-
/**
|
|
2143
|
-
* Defines the extension to use to load the scene (if not defined, ".babylon" will be used)
|
|
2144
|
-
*/
|
|
2145
|
-
extension) {
|
|
2146
|
-
super(name);
|
|
2147
|
-
this.name = name;
|
|
2148
|
-
this.meshesNames = meshesNames;
|
|
2149
|
-
this.rootUrl = rootUrl;
|
|
2150
|
-
this.sceneFilename = sceneFilename;
|
|
2151
|
-
this.extension = extension;
|
|
2152
|
-
}
|
|
2153
|
-
/**
|
|
2154
|
-
* Execute the current task
|
|
2155
|
-
* @param scene defines the scene where you want your assets to be loaded
|
|
2156
|
-
* @param onSuccess is a callback called when the task is successfully executed
|
|
2157
|
-
* @param onError is a callback called if an error occurs
|
|
2158
|
-
*/
|
|
2159
|
-
runTask(scene, onSuccess, onError) {
|
|
2160
|
-
SceneLoader.LoadAssetContainer(this.rootUrl, this.sceneFilename, scene, (container) => {
|
|
2161
|
-
this.loadedContainer = container;
|
|
2162
|
-
this.loadedMeshes = container.meshes;
|
|
2163
|
-
this.loadedTransformNodes = container.transformNodes;
|
|
2164
|
-
this.loadedParticleSystems = container.particleSystems;
|
|
2165
|
-
this.loadedSkeletons = container.skeletons;
|
|
2166
|
-
this.loadedAnimationGroups = container.animationGroups;
|
|
2167
|
-
onSuccess();
|
|
2168
|
-
}, null, (scene, message, exception) => {
|
|
2169
|
-
onError(message, exception);
|
|
2170
|
-
}, this.extension);
|
|
2171
|
-
}
|
|
2172
|
-
}
|
|
2173
|
-
/**
|
|
2174
|
-
* Define a task used by AssetsManager to load meshes
|
|
2175
|
-
*/
|
|
2176
|
-
class MeshAssetTask extends AbstractAssetTask {
|
|
2177
|
-
/**
|
|
2178
|
-
* Creates a new MeshAssetTask
|
|
2179
|
-
* @param name defines the name of the task
|
|
2180
|
-
* @param meshesNames defines the list of mesh's names you want to load
|
|
2181
|
-
* @param rootUrl defines the root url to use as a base to load your meshes and associated resources
|
|
2182
|
-
* @param sceneFilename defines the filename or File of the scene to load from
|
|
2183
|
-
*/
|
|
2184
|
-
constructor(
|
|
2185
|
-
/**
|
|
2186
|
-
* Defines the name of the task
|
|
2187
|
-
*/
|
|
2188
|
-
name,
|
|
2189
|
-
/**
|
|
2190
|
-
* Defines the list of mesh's names you want to load
|
|
2191
|
-
*/
|
|
2192
|
-
meshesNames,
|
|
2193
|
-
/**
|
|
2194
|
-
* Defines the root url to use as a base to load your meshes and associated resources
|
|
2195
|
-
*/
|
|
2196
|
-
rootUrl,
|
|
2197
|
-
/**
|
|
2198
|
-
* Defines the filename or File of the scene to load from
|
|
2199
|
-
*/
|
|
2200
|
-
sceneFilename,
|
|
2201
|
-
/**
|
|
2202
|
-
* Defines the extension to use to load the scene (if not defined, ".babylon" will be used)
|
|
2203
|
-
*/
|
|
2204
|
-
extension) {
|
|
2205
|
-
super(name);
|
|
2206
|
-
this.name = name;
|
|
2207
|
-
this.meshesNames = meshesNames;
|
|
2208
|
-
this.rootUrl = rootUrl;
|
|
2209
|
-
this.sceneFilename = sceneFilename;
|
|
2210
|
-
this.extension = extension;
|
|
2211
|
-
}
|
|
2212
|
-
/**
|
|
2213
|
-
* Execute the current task
|
|
2214
|
-
* @param scene defines the scene where you want your assets to be loaded
|
|
2215
|
-
* @param onSuccess is a callback called when the task is successfully executed
|
|
2216
|
-
* @param onError is a callback called if an error occurs
|
|
2217
|
-
*/
|
|
2218
|
-
runTask(scene, onSuccess, onError) {
|
|
2219
|
-
SceneLoader.ImportMesh(this.meshesNames, this.rootUrl, this.sceneFilename, scene, (meshes, particleSystems, skeletons, animationGroups, transformNodes) => {
|
|
2220
|
-
this.loadedMeshes = meshes;
|
|
2221
|
-
this.loadedTransformNodes = transformNodes;
|
|
2222
|
-
this.loadedParticleSystems = particleSystems;
|
|
2223
|
-
this.loadedSkeletons = skeletons;
|
|
2224
|
-
this.loadedAnimationGroups = animationGroups;
|
|
2225
|
-
onSuccess();
|
|
2226
|
-
}, null, (scene, message, exception) => {
|
|
2227
|
-
onError(message, exception);
|
|
2228
|
-
}, this.extension);
|
|
2229
|
-
}
|
|
2230
|
-
}
|
|
2231
|
-
/**
|
|
2232
|
-
* Define a task used by AssetsManager to load text content
|
|
2233
|
-
*/
|
|
2234
|
-
class TextFileAssetTask extends AbstractAssetTask {
|
|
2235
|
-
/**
|
|
2236
|
-
* Creates a new TextFileAssetTask object
|
|
2237
|
-
* @param name defines the name of the task
|
|
2238
|
-
* @param url defines the location of the file to load
|
|
2239
|
-
*/
|
|
2240
|
-
constructor(
|
|
2241
|
-
/**
|
|
2242
|
-
* Defines the name of the task
|
|
2243
|
-
*/
|
|
2244
|
-
name,
|
|
2245
|
-
/**
|
|
2246
|
-
* Defines the location of the file to load
|
|
2247
|
-
*/
|
|
2248
|
-
url) {
|
|
2249
|
-
super(name);
|
|
2250
|
-
this.name = name;
|
|
2251
|
-
this.url = url;
|
|
2252
|
-
}
|
|
2253
|
-
/**
|
|
2254
|
-
* Execute the current task
|
|
2255
|
-
* @param scene defines the scene where you want your assets to be loaded
|
|
2256
|
-
* @param onSuccess is a callback called when the task is successfully executed
|
|
2257
|
-
* @param onError is a callback called if an error occurs
|
|
2258
|
-
*/
|
|
2259
|
-
runTask(scene, onSuccess, onError) {
|
|
2260
|
-
scene._loadFile(this.url, (data) => {
|
|
2261
|
-
this.text = data;
|
|
2262
|
-
onSuccess();
|
|
2263
|
-
}, undefined, false, false, (request, exception) => {
|
|
2264
|
-
if (request) {
|
|
2265
|
-
onError(request.status + " " + request.statusText, exception);
|
|
2266
|
-
}
|
|
2267
|
-
});
|
|
2268
|
-
}
|
|
2269
|
-
}
|
|
2270
|
-
/**
|
|
2271
|
-
* Define a task used by AssetsManager to load binary data
|
|
2272
|
-
*/
|
|
2273
|
-
class BinaryFileAssetTask extends AbstractAssetTask {
|
|
2274
|
-
/**
|
|
2275
|
-
* Creates a new BinaryFileAssetTask object
|
|
2276
|
-
* @param name defines the name of the new task
|
|
2277
|
-
* @param url defines the location of the file to load
|
|
2278
|
-
*/
|
|
2279
|
-
constructor(
|
|
2280
|
-
/**
|
|
2281
|
-
* Defines the name of the task
|
|
2282
|
-
*/
|
|
2283
|
-
name,
|
|
2284
|
-
/**
|
|
2285
|
-
* Defines the location of the file to load
|
|
2286
|
-
*/
|
|
2287
|
-
url) {
|
|
2288
|
-
super(name);
|
|
2289
|
-
this.name = name;
|
|
2290
|
-
this.url = url;
|
|
2291
|
-
}
|
|
2292
|
-
/**
|
|
2293
|
-
* Execute the current task
|
|
2294
|
-
* @param scene defines the scene where you want your assets to be loaded
|
|
2295
|
-
* @param onSuccess is a callback called when the task is successfully executed
|
|
2296
|
-
* @param onError is a callback called if an error occurs
|
|
2297
|
-
*/
|
|
2298
|
-
runTask(scene, onSuccess, onError) {
|
|
2299
|
-
scene._loadFile(this.url, (data) => {
|
|
2300
|
-
this.data = data;
|
|
2301
|
-
onSuccess();
|
|
2302
|
-
}, undefined, true, true, (request, exception) => {
|
|
2303
|
-
if (request) {
|
|
2304
|
-
onError(request.status + " " + request.statusText, exception);
|
|
2305
|
-
}
|
|
2306
|
-
});
|
|
2307
|
-
}
|
|
2308
|
-
}
|
|
2309
|
-
/**
|
|
2310
|
-
* Define a task used by AssetsManager to load images
|
|
2311
|
-
*/
|
|
2312
|
-
class ImageAssetTask extends AbstractAssetTask {
|
|
2313
|
-
/**
|
|
2314
|
-
* Creates a new ImageAssetTask
|
|
2315
|
-
* @param name defines the name of the task
|
|
2316
|
-
* @param url defines the location of the image to load
|
|
2317
|
-
*/
|
|
2318
|
-
constructor(
|
|
2319
|
-
/**
|
|
2320
|
-
* Defines the name of the task
|
|
2321
|
-
*/
|
|
2322
|
-
name,
|
|
2323
|
-
/**
|
|
2324
|
-
* Defines the location of the image to load
|
|
2325
|
-
*/
|
|
2326
|
-
url) {
|
|
2327
|
-
super(name);
|
|
2328
|
-
this.name = name;
|
|
2329
|
-
this.url = url;
|
|
2330
|
-
}
|
|
2331
|
-
/**
|
|
2332
|
-
* Execute the current task
|
|
2333
|
-
* @param scene defines the scene where you want your assets to be loaded
|
|
2334
|
-
* @param onSuccess is a callback called when the task is successfully executed
|
|
2335
|
-
* @param onError is a callback called if an error occurs
|
|
2336
|
-
*/
|
|
2337
|
-
runTask(scene, onSuccess, onError) {
|
|
2338
|
-
const img = new Image();
|
|
2339
|
-
Tools.SetCorsBehavior(this.url, img);
|
|
2340
|
-
img.onload = () => {
|
|
2341
|
-
this.image = img;
|
|
2342
|
-
onSuccess();
|
|
2343
|
-
};
|
|
2344
|
-
img.onerror = (err) => {
|
|
2345
|
-
onError("Error loading image", err);
|
|
2346
|
-
};
|
|
2347
|
-
img.src = this.url;
|
|
2348
|
-
}
|
|
2349
|
-
}
|
|
2350
|
-
/**
|
|
2351
|
-
* Define a task used by AssetsManager to load 2D textures
|
|
2352
|
-
*/
|
|
2353
|
-
class TextureAssetTask extends AbstractAssetTask {
|
|
2354
|
-
/**
|
|
2355
|
-
* Creates a new TextureAssetTask object
|
|
2356
|
-
* @param name defines the name of the task
|
|
2357
|
-
* @param url defines the location of the file to load
|
|
2358
|
-
* @param noMipmap defines if mipmap should not be generated (default is false)
|
|
2359
|
-
* @param invertY defines if texture must be inverted on Y axis (default is true)
|
|
2360
|
-
* @param samplingMode defines the sampling mode to use (default is Texture.TRILINEAR_SAMPLINGMODE)
|
|
2361
|
-
*/
|
|
2362
|
-
constructor(
|
|
2363
|
-
/**
|
|
2364
|
-
* Defines the name of the task
|
|
2365
|
-
*/
|
|
2366
|
-
name,
|
|
2367
|
-
/**
|
|
2368
|
-
* Defines the location of the file to load
|
|
2369
|
-
*/
|
|
2370
|
-
url,
|
|
2371
|
-
/**
|
|
2372
|
-
* Defines if mipmap should not be generated (default is false)
|
|
2373
|
-
*/
|
|
2374
|
-
noMipmap,
|
|
2375
|
-
/**
|
|
2376
|
-
* Defines if texture must be inverted on Y axis (default is true)
|
|
2377
|
-
*/
|
|
2378
|
-
invertY = true,
|
|
2379
|
-
/**
|
|
2380
|
-
* Defines the sampling mode to use (default is Texture.TRILINEAR_SAMPLINGMODE)
|
|
2381
|
-
*/
|
|
2382
|
-
samplingMode = Texture.TRILINEAR_SAMPLINGMODE) {
|
|
2383
|
-
super(name);
|
|
2384
|
-
this.name = name;
|
|
2385
|
-
this.url = url;
|
|
2386
|
-
this.noMipmap = noMipmap;
|
|
2387
|
-
this.invertY = invertY;
|
|
2388
|
-
this.samplingMode = samplingMode;
|
|
2389
|
-
}
|
|
2390
|
-
/**
|
|
2391
|
-
* Execute the current task
|
|
2392
|
-
* @param scene defines the scene where you want your assets to be loaded
|
|
2393
|
-
* @param onSuccess is a callback called when the task is successfully executed
|
|
2394
|
-
* @param onError is a callback called if an error occurs
|
|
2395
|
-
*/
|
|
2396
|
-
runTask(scene, onSuccess, onError) {
|
|
2397
|
-
const onload = () => {
|
|
2398
|
-
onSuccess();
|
|
2399
|
-
};
|
|
2400
|
-
const onerror = (message, exception) => {
|
|
2401
|
-
onError(message, exception);
|
|
2402
|
-
};
|
|
2403
|
-
this.texture = new Texture(this.url, scene, this.noMipmap, this.invertY, this.samplingMode, onload, onerror);
|
|
2404
|
-
}
|
|
2405
|
-
}
|
|
2406
|
-
/**
|
|
2407
|
-
* Define a task used by AssetsManager to load cube textures
|
|
2408
|
-
*/
|
|
2409
|
-
class CubeTextureAssetTask extends AbstractAssetTask {
|
|
2410
|
-
/**
|
|
2411
|
-
* Creates a new CubeTextureAssetTask
|
|
2412
|
-
* @param name defines the name of the task
|
|
2413
|
-
* @param url defines the location of the files to load (You have to specify the folder where the files are + filename with no extension)
|
|
2414
|
-
* @param extensions defines the extensions to use to load files (["_px", "_py", "_pz", "_nx", "_ny", "_nz"] by default)
|
|
2415
|
-
* @param noMipmap defines if mipmaps should not be generated (default is false)
|
|
2416
|
-
* @param files defines the explicit list of files (undefined by default)
|
|
2417
|
-
* @param prefiltered
|
|
2418
|
-
*/
|
|
2419
|
-
constructor(
|
|
2420
|
-
/**
|
|
2421
|
-
* Defines the name of the task
|
|
2422
|
-
*/
|
|
2423
|
-
name,
|
|
2424
|
-
/**
|
|
2425
|
-
* Defines the location of the files to load (You have to specify the folder where the files are + filename with no extension)
|
|
2426
|
-
*/
|
|
2427
|
-
url,
|
|
2428
|
-
/**
|
|
2429
|
-
* Defines the extensions to use to load files (["_px", "_py", "_pz", "_nx", "_ny", "_nz"] by default)
|
|
2430
|
-
*/
|
|
2431
|
-
extensions,
|
|
2432
|
-
/**
|
|
2433
|
-
* Defines if mipmaps should not be generated (default is false)
|
|
2434
|
-
*/
|
|
2435
|
-
noMipmap,
|
|
2436
|
-
/**
|
|
2437
|
-
* Defines the explicit list of files (undefined by default)
|
|
2438
|
-
*/
|
|
2439
|
-
files,
|
|
2440
|
-
/**
|
|
2441
|
-
* Defines the prefiltered texture option (default is false)
|
|
2442
|
-
*/
|
|
2443
|
-
prefiltered) {
|
|
2444
|
-
super(name);
|
|
2445
|
-
this.name = name;
|
|
2446
|
-
this.url = url;
|
|
2447
|
-
this.extensions = extensions;
|
|
2448
|
-
this.noMipmap = noMipmap;
|
|
2449
|
-
this.files = files;
|
|
2450
|
-
this.prefiltered = prefiltered;
|
|
2451
|
-
}
|
|
2452
|
-
/**
|
|
2453
|
-
* Execute the current task
|
|
2454
|
-
* @param scene defines the scene where you want your assets to be loaded
|
|
2455
|
-
* @param onSuccess is a callback called when the task is successfully executed
|
|
2456
|
-
* @param onError is a callback called if an error occurs
|
|
2457
|
-
*/
|
|
2458
|
-
runTask(scene, onSuccess, onError) {
|
|
2459
|
-
const onload = () => {
|
|
2460
|
-
onSuccess();
|
|
2461
|
-
};
|
|
2462
|
-
const onerror = (message, exception) => {
|
|
2463
|
-
onError(message, exception);
|
|
2464
|
-
};
|
|
2465
|
-
this.texture = new CubeTexture(this.url, scene, this.extensions, this.noMipmap, this.files, onload, onerror, undefined, this.prefiltered);
|
|
2466
|
-
}
|
|
2467
|
-
}
|
|
2468
|
-
/**
|
|
2469
|
-
* Define a task used by AssetsManager to load HDR cube textures
|
|
2470
|
-
*/
|
|
2471
|
-
class HDRCubeTextureAssetTask extends AbstractAssetTask {
|
|
2472
|
-
/**
|
|
2473
|
-
* Creates a new HDRCubeTextureAssetTask object
|
|
2474
|
-
* @param name defines the name of the task
|
|
2475
|
-
* @param url defines the location of the file to load
|
|
2476
|
-
* @param size defines the desired size (the more it increases the longer the generation will be) If the size is omitted this implies you are using a preprocessed cubemap.
|
|
2477
|
-
* @param noMipmap defines if mipmaps should not be generated (default is false)
|
|
2478
|
-
* @param generateHarmonics specifies whether you want to extract the polynomial harmonics during the generation process (default is true)
|
|
2479
|
-
* @param gammaSpace specifies if the texture will be use in gamma or linear space (the PBR material requires those texture in linear space, but the standard material would require them in Gamma space) (default is false)
|
|
2480
|
-
* @param reserved Internal use only
|
|
2481
|
-
*/
|
|
2482
|
-
constructor(
|
|
2483
|
-
/**
|
|
2484
|
-
* Defines the name of the task
|
|
2485
|
-
*/
|
|
2486
|
-
name,
|
|
2487
|
-
/**
|
|
2488
|
-
* Defines the location of the file to load
|
|
2489
|
-
*/
|
|
2490
|
-
url,
|
|
2491
|
-
/**
|
|
2492
|
-
* Defines the desired size (the more it increases the longer the generation will be)
|
|
2493
|
-
*/
|
|
2494
|
-
size,
|
|
2495
|
-
/**
|
|
2496
|
-
* Defines if mipmaps should not be generated (default is false)
|
|
2497
|
-
*/
|
|
2498
|
-
noMipmap = false,
|
|
2499
|
-
/**
|
|
2500
|
-
* Specifies whether you want to extract the polynomial harmonics during the generation process (default is true)
|
|
2501
|
-
*/
|
|
2502
|
-
generateHarmonics = true,
|
|
2503
|
-
/**
|
|
2504
|
-
* Specifies if the texture will be use in gamma or linear space (the PBR material requires those texture in linear space, but the standard material would require them in Gamma space) (default is false)
|
|
2505
|
-
*/
|
|
2506
|
-
gammaSpace = false,
|
|
2507
|
-
/**
|
|
2508
|
-
* Internal Use Only
|
|
2509
|
-
*/
|
|
2510
|
-
reserved = false) {
|
|
2511
|
-
super(name);
|
|
2512
|
-
this.name = name;
|
|
2513
|
-
this.url = url;
|
|
2514
|
-
this.size = size;
|
|
2515
|
-
this.noMipmap = noMipmap;
|
|
2516
|
-
this.generateHarmonics = generateHarmonics;
|
|
2517
|
-
this.gammaSpace = gammaSpace;
|
|
2518
|
-
this.reserved = reserved;
|
|
2519
|
-
}
|
|
2520
|
-
/**
|
|
2521
|
-
* Execute the current task
|
|
2522
|
-
* @param scene defines the scene where you want your assets to be loaded
|
|
2523
|
-
* @param onSuccess is a callback called when the task is successfully executed
|
|
2524
|
-
* @param onError is a callback called if an error occurs
|
|
2525
|
-
*/
|
|
2526
|
-
runTask(scene, onSuccess, onError) {
|
|
2527
|
-
const onload = () => {
|
|
2528
|
-
onSuccess();
|
|
2529
|
-
};
|
|
2530
|
-
const onerror = (message, exception) => {
|
|
2531
|
-
onError(message, exception);
|
|
2532
|
-
};
|
|
2533
|
-
this.texture = new HDRCubeTexture(this.url, scene, this.size, this.noMipmap, this.generateHarmonics, this.gammaSpace, this.reserved, onload, onerror);
|
|
2534
|
-
}
|
|
2535
|
-
}
|
|
2536
|
-
/**
|
|
2537
|
-
* Define a task used by AssetsManager to load Equirectangular cube textures
|
|
2538
|
-
*/
|
|
2539
|
-
class EquiRectangularCubeTextureAssetTask extends AbstractAssetTask {
|
|
2540
|
-
/**
|
|
2541
|
-
* Creates a new EquiRectangularCubeTextureAssetTask object
|
|
2542
|
-
* @param name defines the name of the task
|
|
2543
|
-
* @param url defines the location of the file to load
|
|
2544
|
-
* @param size defines the desired size (the more it increases the longer the generation will be)
|
|
2545
|
-
* If the size is omitted this implies you are using a preprocessed cubemap.
|
|
2546
|
-
* @param noMipmap defines if mipmaps should not be generated (default is false)
|
|
2547
|
-
* @param gammaSpace specifies if the texture will be used in gamma or linear space
|
|
2548
|
-
* (the PBR material requires those texture in linear space, but the standard material would require them in Gamma space)
|
|
2549
|
-
* (default is true)
|
|
2550
|
-
*/
|
|
2551
|
-
constructor(
|
|
2552
|
-
/**
|
|
2553
|
-
* Defines the name of the task
|
|
2554
|
-
*/
|
|
2555
|
-
name,
|
|
2556
|
-
/**
|
|
2557
|
-
* Defines the location of the file to load
|
|
2558
|
-
*/
|
|
2559
|
-
url,
|
|
2560
|
-
/**
|
|
2561
|
-
* Defines the desired size (the more it increases the longer the generation will be)
|
|
2562
|
-
*/
|
|
2563
|
-
size,
|
|
2564
|
-
/**
|
|
2565
|
-
* Defines if mipmaps should not be generated (default is false)
|
|
2566
|
-
*/
|
|
2567
|
-
noMipmap = false,
|
|
2568
|
-
/**
|
|
2569
|
-
* Specifies if the texture will be use in gamma or linear space (the PBR material requires those texture in linear space,
|
|
2570
|
-
* but the standard material would require them in Gamma space) (default is true)
|
|
2571
|
-
*/
|
|
2572
|
-
gammaSpace = true) {
|
|
2573
|
-
super(name);
|
|
2574
|
-
this.name = name;
|
|
2575
|
-
this.url = url;
|
|
2576
|
-
this.size = size;
|
|
2577
|
-
this.noMipmap = noMipmap;
|
|
2578
|
-
this.gammaSpace = gammaSpace;
|
|
2579
|
-
}
|
|
2580
|
-
/**
|
|
2581
|
-
* Execute the current task
|
|
2582
|
-
* @param scene defines the scene where you want your assets to be loaded
|
|
2583
|
-
* @param onSuccess is a callback called when the task is successfully executed
|
|
2584
|
-
* @param onError is a callback called if an error occurs
|
|
2585
|
-
*/
|
|
2586
|
-
runTask(scene, onSuccess, onError) {
|
|
2587
|
-
const onload = () => {
|
|
2588
|
-
onSuccess();
|
|
2589
|
-
};
|
|
2590
|
-
const onerror = (message, exception) => {
|
|
2591
|
-
onError(message, exception);
|
|
2592
|
-
};
|
|
2593
|
-
this.texture = new EquiRectangularCubeTexture(this.url, scene, this.size, this.noMipmap, this.gammaSpace, onload, onerror);
|
|
2594
|
-
}
|
|
2595
|
-
}
|
|
2596
|
-
/**
|
|
2597
|
-
* This class can be used to easily import assets into a scene
|
|
2598
|
-
* @see https://doc.babylonjs.com/features/featuresDeepDive/importers/assetManager
|
|
2599
|
-
*/
|
|
2600
|
-
class AssetsManager {
|
|
2601
|
-
/**
|
|
2602
|
-
* Creates a new AssetsManager
|
|
2603
|
-
* @param scene defines the scene to work on
|
|
2604
|
-
*/
|
|
2605
|
-
constructor(scene) {
|
|
2606
|
-
this._isLoading = false;
|
|
2607
|
-
this._tasks = new Array();
|
|
2608
|
-
this._waitingTasksCount = 0;
|
|
2609
|
-
this._totalTasksCount = 0;
|
|
2610
|
-
/**
|
|
2611
|
-
* Observable called when all tasks are processed
|
|
2612
|
-
*/
|
|
2613
|
-
this.onTaskSuccessObservable = new Observable();
|
|
2614
|
-
/**
|
|
2615
|
-
* Observable called when a task had an error
|
|
2616
|
-
*/
|
|
2617
|
-
this.onTaskErrorObservable = new Observable();
|
|
2618
|
-
/**
|
|
2619
|
-
* Observable called when all tasks were executed
|
|
2620
|
-
*/
|
|
2621
|
-
this.onTasksDoneObservable = new Observable();
|
|
2622
|
-
/**
|
|
2623
|
-
* Observable called when a task is done (whatever the result is)
|
|
2624
|
-
*/
|
|
2625
|
-
this.onProgressObservable = new Observable();
|
|
2626
|
-
/**
|
|
2627
|
-
* Gets or sets a boolean defining if the AssetsManager should use the default loading screen
|
|
2628
|
-
* @see https://doc.babylonjs.com/features/featuresDeepDive/scene/customLoadingScreen
|
|
2629
|
-
*/
|
|
2630
|
-
this.useDefaultLoadingScreen = true;
|
|
2631
|
-
/**
|
|
2632
|
-
* Gets or sets a boolean defining if the AssetsManager should automatically hide the loading screen
|
|
2633
|
-
* when all assets have been downloaded.
|
|
2634
|
-
* If set to false, you need to manually call in hideLoadingUI() once your scene is ready.
|
|
2635
|
-
*/
|
|
2636
|
-
this.autoHideLoadingUI = true;
|
|
2637
|
-
this._scene = scene || EngineStore.LastCreatedScene;
|
|
2638
|
-
}
|
|
2639
|
-
/**
|
|
2640
|
-
* Add a ContainerAssetTask to the list of active tasks
|
|
2641
|
-
* @param taskName defines the name of the new task
|
|
2642
|
-
* @param meshesNames defines the name of meshes to load
|
|
2643
|
-
* @param rootUrl defines the root url to use to locate files
|
|
2644
|
-
* @param sceneFilename defines the filename of the scene file or the File itself
|
|
2645
|
-
* @param extension defines the extension to use to load the file
|
|
2646
|
-
* @returns a new ContainerAssetTask object
|
|
2647
|
-
*/
|
|
2648
|
-
addContainerTask(taskName, meshesNames, rootUrl, sceneFilename, extension) {
|
|
2649
|
-
const task = new ContainerAssetTask(taskName, meshesNames, rootUrl, sceneFilename, extension);
|
|
2650
|
-
this._tasks.push(task);
|
|
2651
|
-
return task;
|
|
2652
|
-
}
|
|
2653
|
-
/**
|
|
2654
|
-
* Add a MeshAssetTask to the list of active tasks
|
|
2655
|
-
* @param taskName defines the name of the new task
|
|
2656
|
-
* @param meshesNames defines the name of meshes to load
|
|
2657
|
-
* @param rootUrl defines the root url to use to locate files
|
|
2658
|
-
* @param sceneFilename defines the filename of the scene file or the File itself
|
|
2659
|
-
* @param extension defines the extension to use to load the file
|
|
2660
|
-
* @returns a new MeshAssetTask object
|
|
2661
|
-
*/
|
|
2662
|
-
addMeshTask(taskName, meshesNames, rootUrl, sceneFilename, extension) {
|
|
2663
|
-
const task = new MeshAssetTask(taskName, meshesNames, rootUrl, sceneFilename, extension);
|
|
2664
|
-
this._tasks.push(task);
|
|
2665
|
-
return task;
|
|
2666
|
-
}
|
|
2667
|
-
/**
|
|
2668
|
-
* Add a TextFileAssetTask to the list of active tasks
|
|
2669
|
-
* @param taskName defines the name of the new task
|
|
2670
|
-
* @param url defines the url of the file to load
|
|
2671
|
-
* @returns a new TextFileAssetTask object
|
|
2672
|
-
*/
|
|
2673
|
-
addTextFileTask(taskName, url) {
|
|
2674
|
-
const task = new TextFileAssetTask(taskName, url);
|
|
2675
|
-
this._tasks.push(task);
|
|
2676
|
-
return task;
|
|
2677
|
-
}
|
|
2678
|
-
/**
|
|
2679
|
-
* Add a BinaryFileAssetTask to the list of active tasks
|
|
2680
|
-
* @param taskName defines the name of the new task
|
|
2681
|
-
* @param url defines the url of the file to load
|
|
2682
|
-
* @returns a new BinaryFileAssetTask object
|
|
2683
|
-
*/
|
|
2684
|
-
addBinaryFileTask(taskName, url) {
|
|
2685
|
-
const task = new BinaryFileAssetTask(taskName, url);
|
|
2686
|
-
this._tasks.push(task);
|
|
2687
|
-
return task;
|
|
2688
|
-
}
|
|
2689
|
-
/**
|
|
2690
|
-
* Add a ImageAssetTask to the list of active tasks
|
|
2691
|
-
* @param taskName defines the name of the new task
|
|
2692
|
-
* @param url defines the url of the file to load
|
|
2693
|
-
* @returns a new ImageAssetTask object
|
|
2694
|
-
*/
|
|
2695
|
-
addImageTask(taskName, url) {
|
|
2696
|
-
const task = new ImageAssetTask(taskName, url);
|
|
2697
|
-
this._tasks.push(task);
|
|
2698
|
-
return task;
|
|
2699
|
-
}
|
|
2700
|
-
/**
|
|
2701
|
-
* Add a TextureAssetTask to the list of active tasks
|
|
2702
|
-
* @param taskName defines the name of the new task
|
|
2703
|
-
* @param url defines the url of the file to load
|
|
2704
|
-
* @param noMipmap defines if the texture must not receive mipmaps (false by default)
|
|
2705
|
-
* @param invertY defines if you want to invert Y axis of the loaded texture (true by default)
|
|
2706
|
-
* @param samplingMode defines the sampling mode to use (Texture.TRILINEAR_SAMPLINGMODE by default)
|
|
2707
|
-
* @returns a new TextureAssetTask object
|
|
2708
|
-
*/
|
|
2709
|
-
addTextureTask(taskName, url, noMipmap, invertY, samplingMode = Texture.TRILINEAR_SAMPLINGMODE) {
|
|
2710
|
-
const task = new TextureAssetTask(taskName, url, noMipmap, invertY, samplingMode);
|
|
2711
|
-
this._tasks.push(task);
|
|
2712
|
-
return task;
|
|
2713
|
-
}
|
|
2714
|
-
/**
|
|
2715
|
-
* Add a CubeTextureAssetTask to the list of active tasks
|
|
2716
|
-
* @param taskName defines the name of the new task
|
|
2717
|
-
* @param url defines the url of the file to load
|
|
2718
|
-
* @param extensions defines the extension to use to load the cube map (can be null)
|
|
2719
|
-
* @param noMipmap defines if the texture must not receive mipmaps (false by default)
|
|
2720
|
-
* @param files defines the list of files to load (can be null)
|
|
2721
|
-
* @param prefiltered defines the prefiltered texture option (default is false)
|
|
2722
|
-
* @returns a new CubeTextureAssetTask object
|
|
2723
|
-
*/
|
|
2724
|
-
addCubeTextureTask(taskName, url, extensions, noMipmap, files, prefiltered) {
|
|
2725
|
-
const task = new CubeTextureAssetTask(taskName, url, extensions, noMipmap, files, prefiltered);
|
|
2726
|
-
this._tasks.push(task);
|
|
2727
|
-
return task;
|
|
2728
|
-
}
|
|
2729
|
-
/**
|
|
2730
|
-
*
|
|
2731
|
-
* Add a HDRCubeTextureAssetTask to the list of active tasks
|
|
2732
|
-
* @param taskName defines the name of the new task
|
|
2733
|
-
* @param url defines the url of the file to load
|
|
2734
|
-
* @param size defines the size you want for the cubemap (can be null)
|
|
2735
|
-
* @param noMipmap defines if the texture must not receive mipmaps (false by default)
|
|
2736
|
-
* @param generateHarmonics defines if you want to automatically generate (true by default)
|
|
2737
|
-
* @param gammaSpace specifies if the texture will be use in gamma or linear space (the PBR material requires those texture in linear space, but the standard material would require them in Gamma space) (default is false)
|
|
2738
|
-
* @param reserved Internal use only
|
|
2739
|
-
* @returns a new HDRCubeTextureAssetTask object
|
|
2740
|
-
*/
|
|
2741
|
-
addHDRCubeTextureTask(taskName, url, size, noMipmap = false, generateHarmonics = true, gammaSpace = false, reserved = false) {
|
|
2742
|
-
const task = new HDRCubeTextureAssetTask(taskName, url, size, noMipmap, generateHarmonics, gammaSpace, reserved);
|
|
2743
|
-
this._tasks.push(task);
|
|
2744
|
-
return task;
|
|
2745
|
-
}
|
|
2746
|
-
/**
|
|
2747
|
-
*
|
|
2748
|
-
* Add a EquiRectangularCubeTextureAssetTask to the list of active tasks
|
|
2749
|
-
* @param taskName defines the name of the new task
|
|
2750
|
-
* @param url defines the url of the file to load
|
|
2751
|
-
* @param size defines the size you want for the cubemap (can be null)
|
|
2752
|
-
* @param noMipmap defines if the texture must not receive mipmaps (false by default)
|
|
2753
|
-
* @param gammaSpace Specifies if the texture will be used in gamma or linear space
|
|
2754
|
-
* (the PBR material requires those textures in linear space, but the standard material would require them in Gamma space)
|
|
2755
|
-
* @returns a new EquiRectangularCubeTextureAssetTask object
|
|
2756
|
-
*/
|
|
2757
|
-
addEquiRectangularCubeTextureAssetTask(taskName, url, size, noMipmap = false, gammaSpace = true) {
|
|
2758
|
-
const task = new EquiRectangularCubeTextureAssetTask(taskName, url, size, noMipmap, gammaSpace);
|
|
2759
|
-
this._tasks.push(task);
|
|
2760
|
-
return task;
|
|
2761
|
-
}
|
|
2762
|
-
/**
|
|
2763
|
-
* Remove a task from the assets manager.
|
|
2764
|
-
* @param task the task to remove
|
|
2765
|
-
*/
|
|
2766
|
-
removeTask(task) {
|
|
2767
|
-
const index = this._tasks.indexOf(task);
|
|
2768
|
-
if (index > -1) {
|
|
2769
|
-
this._tasks.splice(index, 1);
|
|
2770
|
-
}
|
|
2771
|
-
}
|
|
2772
|
-
_decreaseWaitingTasksCount(task) {
|
|
2773
|
-
this._waitingTasksCount--;
|
|
2774
|
-
try {
|
|
2775
|
-
if (this.onProgress) {
|
|
2776
|
-
this.onProgress(this._waitingTasksCount, this._totalTasksCount, task);
|
|
2777
|
-
}
|
|
2778
|
-
this.onProgressObservable.notifyObservers(new AssetsProgressEvent(this._waitingTasksCount, this._totalTasksCount, task));
|
|
2779
|
-
}
|
|
2780
|
-
catch (e) {
|
|
2781
|
-
Logger.Error("Error running progress callbacks.");
|
|
2782
|
-
console.log(e);
|
|
2783
|
-
}
|
|
2784
|
-
if (this._waitingTasksCount === 0) {
|
|
2785
|
-
try {
|
|
2786
|
-
const currentTasks = this._tasks.slice();
|
|
2787
|
-
if (this.onFinish) {
|
|
2788
|
-
// Calling onFinish with immutable array of tasks
|
|
2789
|
-
this.onFinish(currentTasks);
|
|
2790
|
-
}
|
|
2791
|
-
// Let's remove successful tasks
|
|
2792
|
-
for (const task of currentTasks) {
|
|
2793
|
-
if (task.taskState === AssetTaskState.DONE) {
|
|
2794
|
-
const index = this._tasks.indexOf(task);
|
|
2795
|
-
if (index > -1) {
|
|
2796
|
-
this._tasks.splice(index, 1);
|
|
2797
|
-
}
|
|
2798
|
-
}
|
|
2799
|
-
}
|
|
2800
|
-
this.onTasksDoneObservable.notifyObservers(this._tasks);
|
|
2801
|
-
}
|
|
2802
|
-
catch (e) {
|
|
2803
|
-
Logger.Error("Error running tasks-done callbacks.");
|
|
2804
|
-
console.log(e);
|
|
2805
|
-
}
|
|
2806
|
-
this._isLoading = false;
|
|
2807
|
-
if (this.autoHideLoadingUI) {
|
|
2808
|
-
this._scene.getEngine().hideLoadingUI();
|
|
2809
|
-
}
|
|
2810
|
-
}
|
|
2811
|
-
}
|
|
2812
|
-
_runTask(task) {
|
|
2813
|
-
const done = () => {
|
|
2814
|
-
try {
|
|
2815
|
-
if (this.onTaskSuccess) {
|
|
2816
|
-
this.onTaskSuccess(task);
|
|
2817
|
-
}
|
|
2818
|
-
this.onTaskSuccessObservable.notifyObservers(task);
|
|
2819
|
-
this._decreaseWaitingTasksCount(task);
|
|
2820
|
-
}
|
|
2821
|
-
catch (e) {
|
|
2822
|
-
error("Error executing task success callbacks", e);
|
|
2823
|
-
}
|
|
2824
|
-
};
|
|
2825
|
-
const error = (message, exception) => {
|
|
2826
|
-
task._setErrorObject(message, exception);
|
|
2827
|
-
if (this.onTaskError) {
|
|
2828
|
-
this.onTaskError(task);
|
|
2829
|
-
}
|
|
2830
|
-
else if (!task.onError) {
|
|
2831
|
-
Logger.Error(this._formatTaskErrorMessage(task));
|
|
2832
|
-
}
|
|
2833
|
-
this.onTaskErrorObservable.notifyObservers(task);
|
|
2834
|
-
this._decreaseWaitingTasksCount(task);
|
|
2835
|
-
};
|
|
2836
|
-
task.run(this._scene, done, error);
|
|
2837
|
-
}
|
|
2838
|
-
_formatTaskErrorMessage(task) {
|
|
2839
|
-
let errorMessage = "Unable to complete task " + task.name;
|
|
2840
|
-
if (task.errorObject.message) {
|
|
2841
|
-
errorMessage += `: ${task.errorObject.message}`;
|
|
2842
|
-
}
|
|
2843
|
-
if (task.errorObject.exception) {
|
|
2844
|
-
errorMessage += `: ${task.errorObject.exception}`;
|
|
2845
|
-
}
|
|
2846
|
-
return errorMessage;
|
|
2847
|
-
}
|
|
2848
|
-
/**
|
|
2849
|
-
* Reset the AssetsManager and remove all tasks
|
|
2850
|
-
* @returns the current instance of the AssetsManager
|
|
2851
|
-
*/
|
|
2852
|
-
reset() {
|
|
2853
|
-
this._isLoading = false;
|
|
2854
|
-
this._tasks = new Array();
|
|
2855
|
-
return this;
|
|
2856
|
-
}
|
|
2857
|
-
/**
|
|
2858
|
-
* Start the loading process
|
|
2859
|
-
* @returns the current instance of the AssetsManager
|
|
2860
|
-
*/
|
|
2861
|
-
load() {
|
|
2862
|
-
if (this._isLoading) {
|
|
2863
|
-
return this;
|
|
2864
|
-
}
|
|
2865
|
-
this._isLoading = true;
|
|
2866
|
-
this._waitingTasksCount = this._tasks.length;
|
|
2867
|
-
this._totalTasksCount = this._tasks.length;
|
|
2868
|
-
if (this._waitingTasksCount === 0) {
|
|
2869
|
-
this._isLoading = false;
|
|
2870
|
-
if (this.onFinish) {
|
|
2871
|
-
this.onFinish(this._tasks);
|
|
2872
|
-
}
|
|
2873
|
-
this.onTasksDoneObservable.notifyObservers(this._tasks);
|
|
2874
|
-
return this;
|
|
2875
|
-
}
|
|
2876
|
-
if (this.useDefaultLoadingScreen) {
|
|
2877
|
-
this._scene.getEngine().displayLoadingUI();
|
|
2878
|
-
}
|
|
2879
|
-
for (let index = 0; index < this._tasks.length; index++) {
|
|
2880
|
-
const task = this._tasks[index];
|
|
2881
|
-
if (task.taskState === AssetTaskState.INIT) {
|
|
2882
|
-
this._runTask(task);
|
|
2883
|
-
}
|
|
2884
|
-
}
|
|
2885
|
-
return this;
|
|
2886
|
-
}
|
|
2887
|
-
/**
|
|
2888
|
-
* Start the loading process as an async operation
|
|
2889
|
-
* @returns a promise returning the list of failed tasks
|
|
2890
|
-
*/
|
|
2891
|
-
loadAsync() {
|
|
2892
|
-
return new Promise((resolve, reject) => {
|
|
2893
|
-
if (this._isLoading) {
|
|
2894
|
-
resolve();
|
|
2895
|
-
return;
|
|
2896
|
-
}
|
|
2897
|
-
this.onTasksDoneObservable.addOnce((remainingTasks) => {
|
|
2898
|
-
if (remainingTasks && remainingTasks.length) {
|
|
2899
|
-
reject(remainingTasks);
|
|
2900
|
-
}
|
|
2901
|
-
else {
|
|
2902
|
-
resolve();
|
|
2903
|
-
}
|
|
2904
|
-
});
|
|
2905
|
-
this.load();
|
|
2906
|
-
});
|
|
2907
|
-
}
|
|
2908
|
-
}
|
|
2909
|
-
|
|
2910
|
-
/**
|
|
2911
|
-
* Management object used to manage model and material variants
|
|
2912
|
-
* for a specific instance of the 3D preview. This class should exist for
|
|
2913
|
-
* the lifetime of any preview to track state relating to variant changes.
|
|
2914
|
-
*/
|
|
2915
|
-
class VariantManager {
|
|
2916
|
-
constructor(scene, renameClonedAsset, setBaseModelEnabled) {
|
|
2917
|
-
/**
|
|
2918
|
-
* Store encountered materials
|
|
2919
|
-
*/
|
|
2920
|
-
this.materialVariantMap = new Map();
|
|
2921
|
-
/**
|
|
2922
|
-
* A list of model variant applications that replaced the base model,
|
|
2923
|
-
* we store these internally to avoid having to lookup and pass in the
|
|
2924
|
-
* flag from step data.
|
|
2925
|
-
*/
|
|
2926
|
-
this.keysThatRemovedBaseModel = [];
|
|
2927
|
-
/**
|
|
2928
|
-
* A map of string to asset container which represents the currently loaded
|
|
2929
|
-
* asset container for a given key. This allows us to know what data to unload when loading
|
|
2930
|
-
* new data for a key.
|
|
2931
|
-
*/
|
|
2932
|
-
this.loadedContainerForKey = new Map();
|
|
2933
|
-
/**
|
|
2934
|
-
* A map of string to material array which represents the currently loaded
|
|
2935
|
-
* materials for a given key. This allows us to know what materials are in use by
|
|
2936
|
-
* a given key.
|
|
2937
|
-
*/
|
|
2938
|
-
this.loadedMaterialsForKey = new Map();
|
|
2939
|
-
this.scene = scene;
|
|
2940
|
-
this.renameClonedAsset = renameClonedAsset;
|
|
2941
|
-
this.setBaseModelEnabled = setBaseModelEnabled;
|
|
2942
|
-
}
|
|
2943
|
-
/**
|
|
2944
|
-
* Apply a material variant to a given scene.
|
|
2945
|
-
* @param targetMaterial The name of the material in the scene we should be targeting.
|
|
2946
|
-
* @param material The material variant to apply.
|
|
2947
|
-
* @param onProgress A progress callback function for loading bars and event timing.
|
|
2948
|
-
* @param removeWhenUndefined material application is an additive process, setting this bool to true will
|
|
2949
|
-
* instead remove material textures when they aren't defined. this is useful for material editor applications
|
|
2950
|
-
* where we want to undo changes are remove effects from display.
|
|
2951
|
-
*/
|
|
2952
|
-
applyMaterial(targetMaterial, material, onProgress, removeWhenUndefined) {
|
|
2953
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
2954
|
-
return new Promise((resolve) => {
|
|
2955
|
-
// Keep track of material changes
|
|
2956
|
-
const existingMaterialResource = this.materialVariantMap.get(targetMaterial);
|
|
2957
|
-
this.materialVariantMap.set(targetMaterial, Object.assign(Object.assign({}, existingMaterialResource), material));
|
|
2958
|
-
// Rename the target to match this instance.
|
|
2959
|
-
const targetMaterialName = this.renameClonedAsset(targetMaterial);
|
|
2960
|
-
// Attempt to find the requested material on this object.
|
|
2961
|
-
const targetedMaterials = this.scene.materials.filter((mat) => mat.name === targetMaterialName);
|
|
2962
|
-
// At this point we know the scene has been loaded. If the target material doesn't exist then
|
|
2963
|
-
// the step wasn't configured correctly to begin with so just ignore the request.
|
|
2964
|
-
if (targetedMaterials.length === 0) {
|
|
2965
|
-
resolve();
|
|
2966
|
-
return;
|
|
2967
|
-
}
|
|
2968
|
-
// Create an async task for each type of available texture given.
|
|
2969
|
-
const assetsManager = new AssetsManager(this.scene);
|
|
2970
|
-
assetsManager.useDefaultLoadingScreen = false;
|
|
2971
|
-
// Loop through the materials found in scene that match our target material name and
|
|
2972
|
-
// notify the asset manager of the various material values that need to change on each.
|
|
2973
|
-
targetedMaterials.forEach((targetedMaterial) => calculateMaterialProperties(material, targetedMaterial, assetsManager, removeWhenUndefined));
|
|
2974
|
-
// Notify caller on progress towards loading material changes.
|
|
2975
|
-
assetsManager.onProgress = (remaining, total, task) => {
|
|
2976
|
-
onProgress && onProgress((remaining / total) * 100, 100, task.name);
|
|
2977
|
-
};
|
|
2978
|
-
// Execute the configured texture tasks. For each task received, we iterate ver each targeted material and
|
|
2979
|
-
// apply the requirements of the task.
|
|
2980
|
-
assetsManager.onFinish = (tasks) => {
|
|
2981
|
-
tasks.forEach((task) => {
|
|
2982
|
-
const textureTask = task;
|
|
2983
|
-
onProgress && onProgress(100, 100, task.name);
|
|
2984
|
-
targetedMaterials.forEach((targetMat) => applyDownloadedTexture(task.name, targetMat, material, textureTask.texture));
|
|
2985
|
-
});
|
|
2986
|
-
resolve();
|
|
2987
|
-
};
|
|
2988
|
-
assetsManager.loadAsync();
|
|
2989
|
-
});
|
|
2990
|
-
});
|
|
2991
|
-
}
|
|
2992
|
-
/**
|
|
2993
|
-
* Applies a model variant.
|
|
2994
|
-
* @param key The key to uniquely identify this model variant application.
|
|
2995
|
-
* @param replaceProductModel When true, we should replace the base product model.
|
|
2996
|
-
* @param model The details for the new model, when undefined we should remove the variant associated to the given key.
|
|
2997
|
-
* @param onProgress A load progress callback that can be used for loading bars and event timing.
|
|
2998
|
-
*/
|
|
2999
|
-
applyModel(key, replaceProductModel, model, onProgress) {
|
|
3000
|
-
var _a, _b;
|
|
3001
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
3002
|
-
/**
|
|
3003
|
-
* If we're adding a new model to the scene and the key hasn't been
|
|
3004
|
-
* encountered before and the product model is being replaced, let's
|
|
3005
|
-
* store the key so we know to replace the product model when encountered later.
|
|
3006
|
-
*/
|
|
3007
|
-
if (model &&
|
|
3008
|
-
replaceProductModel &&
|
|
3009
|
-
!this.keysThatRemovedBaseModel.includes(key)) {
|
|
3010
|
-
this.keysThatRemovedBaseModel.push(key);
|
|
3011
|
-
}
|
|
3012
|
-
// When no model details are provided that means
|
|
3013
|
-
// the model variant has been requested to be removed entirely. We remove that
|
|
3014
|
-
// and also re-add any base model if it was removed to fit this variant.
|
|
3015
|
-
if (!model) {
|
|
3016
|
-
if (this.keysThatRemovedBaseModel.includes(key)) {
|
|
3017
|
-
this.setBaseModelEnabled(true);
|
|
3018
|
-
}
|
|
3019
|
-
(_a = this.loadedContainerForKey.get(key)) === null || _a === void 0 ? void 0 : _a.dispose();
|
|
3020
|
-
this.loadedContainerForKey.delete(key);
|
|
3021
|
-
this.loadedMaterialsForKey.delete(key);
|
|
3022
|
-
return Promise.resolve(undefined);
|
|
3023
|
-
}
|
|
3024
|
-
// Remove any existing asset for the given key.
|
|
3025
|
-
if (this.loadedContainerForKey.has(key)) {
|
|
3026
|
-
(_b = this.loadedContainerForKey.get(key)) === null || _b === void 0 ? void 0 : _b.dispose();
|
|
3027
|
-
this.loadedContainerForKey.delete(key);
|
|
3028
|
-
this.loadedMaterialsForKey.delete(key);
|
|
3029
|
-
}
|
|
3030
|
-
// Remove product base model if required.
|
|
3031
|
-
if (replaceProductModel) {
|
|
3032
|
-
this.setBaseModelEnabled(false);
|
|
3033
|
-
}
|
|
3034
|
-
// Add new model to scene.
|
|
3035
|
-
const container = yield getAssetContainer(model, this.scene, onProgress);
|
|
3036
|
-
const instance = container.instantiateModelsToScene(this.renameClonedAsset, true);
|
|
3037
|
-
this.loadedContainerForKey.set(key, instance);
|
|
3038
|
-
// Store all materials used by this model.
|
|
3039
|
-
this.loadedMaterialsForKey.set(key, getAllMaterialsForInstance(instance));
|
|
3040
|
-
// Reapply any encountered material variants to the scene, this ensures
|
|
3041
|
-
// no material information is lost.
|
|
3042
|
-
const promiseList = [];
|
|
3043
|
-
this.materialVariantMap.forEach((value, key) => __awaiter(this, void 0, void 0, function* () {
|
|
3044
|
-
promiseList.push(this.applyMaterial(key, value));
|
|
3045
|
-
}));
|
|
3046
|
-
yield Promise.all(promiseList);
|
|
3047
|
-
return instance;
|
|
3048
|
-
});
|
|
3049
|
-
}
|
|
3050
|
-
dispose() {
|
|
3051
|
-
this.loadedContainerForKey.forEach((value) => value === null || value === void 0 ? void 0 : value.dispose());
|
|
3052
|
-
this.loadedContainerForKey.clear();
|
|
3053
|
-
this.loadedMaterialsForKey.forEach((value) => value.forEach((mat) => mat === null || mat === void 0 ? void 0 : mat.dispose()));
|
|
3054
|
-
this.loadedMaterialsForKey.clear();
|
|
3055
|
-
this.materialVariantMap.clear();
|
|
3056
|
-
this.keysThatRemovedBaseModel = [];
|
|
3057
|
-
}
|
|
3058
|
-
getAllMaterials() {
|
|
3059
|
-
const materials = [];
|
|
3060
|
-
this.loadedMaterialsForKey.forEach((value) => {
|
|
3061
|
-
value.forEach((mat) => {
|
|
3062
|
-
if (!materials.includes(mat)) {
|
|
3063
|
-
materials.push(mat);
|
|
3064
|
-
}
|
|
3065
|
-
});
|
|
3066
|
-
});
|
|
3067
|
-
return materials;
|
|
3068
|
-
}
|
|
3069
|
-
getAnimationGroups() {
|
|
3070
|
-
const animationGroups = [];
|
|
3071
|
-
this.loadedContainerForKey.forEach((value) => {
|
|
3072
|
-
animationGroups.push(...value.animationGroups);
|
|
3073
|
-
});
|
|
3074
|
-
return animationGroups;
|
|
3075
|
-
}
|
|
3076
|
-
}
|
|
3077
|
-
function getAllMaterialsForInstance(modelInstance) {
|
|
3078
|
-
const materials = [];
|
|
3079
|
-
modelInstance.rootNodes.forEach((node) => {
|
|
3080
|
-
node.getChildMeshes().forEach((mesh) => {
|
|
3081
|
-
if (mesh.material && !materials.includes(mesh.material)) {
|
|
3082
|
-
materials.push(mesh.material);
|
|
3083
|
-
}
|
|
3084
|
-
if (mesh.subMeshes) {
|
|
3085
|
-
mesh.subMeshes.forEach((subMesh) => {
|
|
3086
|
-
const mat = subMesh.getMaterial(false);
|
|
3087
|
-
if (mat && !materials.includes(mat)) {
|
|
3088
|
-
materials.push(mat);
|
|
3089
|
-
}
|
|
3090
|
-
});
|
|
3091
|
-
}
|
|
3092
|
-
});
|
|
3093
|
-
});
|
|
3094
|
-
return materials;
|
|
3095
|
-
}
|
|
3096
|
-
|
|
3097
|
-
export { CubeTexture as C, VariantManager as V, getAllMaterialsForInstance as g };
|