@preference-sl/pref-viewer 2.10.0-beta.25 → 2.10.0-beta.26
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/package.json +5 -5
- package/src/index.js +254 -337
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@preference-sl/pref-viewer",
|
|
3
|
-
"version": "2.10.0-beta.
|
|
3
|
+
"version": "2.10.0-beta.26",
|
|
4
4
|
"description": "Web Component to preview GLTF models with Babylon.js",
|
|
5
5
|
"author": "Alex Moreno Palacio <amoreno@preference.es>",
|
|
6
6
|
"scripts": {
|
|
@@ -34,10 +34,10 @@
|
|
|
34
34
|
"index.d.ts"
|
|
35
35
|
],
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@babylonjs/core": "^8.
|
|
38
|
-
"@babylonjs/loaders": "^8.
|
|
39
|
-
"@babylonjs/serializers": "^8.
|
|
40
|
-
"babylonjs-gltf2interface": "^8.
|
|
37
|
+
"@babylonjs/core": "^8.31.3",
|
|
38
|
+
"@babylonjs/loaders": "^8.31.3",
|
|
39
|
+
"@babylonjs/serializers": "^8.31.3",
|
|
40
|
+
"babylonjs-gltf2interface": "^8.31.3"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"esbuild": "^0.25.10",
|
package/src/index.js
CHANGED
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
* </pref-viewer>
|
|
40
40
|
* ```
|
|
41
41
|
*/
|
|
42
|
-
import { Engine, Scene, ArcRotateCamera, Vector3, Color4, HemisphericLight, DirectionalLight, PointLight, ShadowGenerator, LoadAssetContainerAsync, Tools, WebXRSessionManager, WebXRDefaultExperience, MeshBuilder, WebXRFeatureName } from "@babylonjs/core";
|
|
42
|
+
import { Engine, Scene, ArcRotateCamera, Vector3, Color4, HemisphericLight, DirectionalLight, PointLight, ShadowGenerator, LoadAssetContainerAsync, Tools, WebXRSessionManager, WebXRDefaultExperience, MeshBuilder, WebXRFeatureName, HDRCubeTexture, IblShadowsRenderPipeline } from "@babylonjs/core";
|
|
43
43
|
import "@babylonjs/loaders";
|
|
44
44
|
import { USDZExportAsync, GLTF2Export } from "@babylonjs/serializers";
|
|
45
45
|
import "@babylonjs/loaders/glTF/2.0/Extensions/KHR_draco_mesh_compression";
|
|
@@ -61,7 +61,7 @@ class PrefViewer extends HTMLElement {
|
|
|
61
61
|
visible: false,
|
|
62
62
|
size: null,
|
|
63
63
|
timeStamp: null,
|
|
64
|
-
changed:
|
|
64
|
+
changed: false,
|
|
65
65
|
},
|
|
66
66
|
environment: {
|
|
67
67
|
name: "environment",
|
|
@@ -71,7 +71,7 @@ class PrefViewer extends HTMLElement {
|
|
|
71
71
|
visible: false,
|
|
72
72
|
size: null,
|
|
73
73
|
timeStamp: null,
|
|
74
|
-
changed:
|
|
74
|
+
changed: false,
|
|
75
75
|
},
|
|
76
76
|
materials: {
|
|
77
77
|
name: "materials",
|
|
@@ -81,35 +81,35 @@ class PrefViewer extends HTMLElement {
|
|
|
81
81
|
visible: false,
|
|
82
82
|
size: null,
|
|
83
83
|
timeStamp: null,
|
|
84
|
-
changed:
|
|
84
|
+
changed: false,
|
|
85
85
|
},
|
|
86
86
|
},
|
|
87
87
|
options: {
|
|
88
88
|
camera: {
|
|
89
89
|
value: null,
|
|
90
90
|
locked: true,
|
|
91
|
-
changed:
|
|
91
|
+
changed: false,
|
|
92
92
|
},
|
|
93
93
|
materials: {
|
|
94
94
|
innerWall: {
|
|
95
95
|
value: null,
|
|
96
96
|
prefix: "innerWall",
|
|
97
|
-
changed:
|
|
97
|
+
changed: false,
|
|
98
98
|
},
|
|
99
99
|
outerWall: {
|
|
100
100
|
value: null,
|
|
101
101
|
prefix: "outerWall",
|
|
102
|
-
changed:
|
|
102
|
+
changed: false,
|
|
103
103
|
},
|
|
104
104
|
innerFloor: {
|
|
105
105
|
value: null,
|
|
106
106
|
prefix: "innerFloor",
|
|
107
|
-
changed:
|
|
107
|
+
changed: false,
|
|
108
108
|
},
|
|
109
109
|
outerFloor: {
|
|
110
110
|
value: null,
|
|
111
111
|
prefix: "outerFloor",
|
|
112
|
-
changed:
|
|
112
|
+
changed: false,
|
|
113
113
|
},
|
|
114
114
|
},
|
|
115
115
|
},
|
|
@@ -131,13 +131,11 @@ class PrefViewer extends HTMLElement {
|
|
|
131
131
|
|
|
132
132
|
constructor() {
|
|
133
133
|
super();
|
|
134
|
-
console.log("PrefViewer: constructor()");
|
|
135
134
|
this.attachShadow({ mode: "open" });
|
|
136
135
|
this.#createCanvas();
|
|
137
136
|
this.#wrapCanvas();
|
|
138
137
|
// Point to whichever version you packaged or want to use:
|
|
139
138
|
const DRACO_BASE = "https://www.gstatic.com/draco/versioned/decoders/1.5.7";
|
|
140
|
-
console.log("PrefViewer: DRACO config base =", DRACO_BASE);
|
|
141
139
|
DracoCompression.Configuration.decoder = {
|
|
142
140
|
// loader for the “wrapper” that pulls in the real WASM
|
|
143
141
|
wasmUrl: `${DRACO_BASE}/draco_wasm_wrapper_gltf.js`,
|
|
@@ -153,7 +151,6 @@ class PrefViewer extends HTMLElement {
|
|
|
153
151
|
}
|
|
154
152
|
|
|
155
153
|
attributeChangedCallback(name, _old, value) {
|
|
156
|
-
console.log("PrefViewer: attributeChangedCallback()", { name, old: _old, value });
|
|
157
154
|
let data = null;
|
|
158
155
|
switch (name) {
|
|
159
156
|
case "config":
|
|
@@ -168,7 +165,6 @@ class PrefViewer extends HTMLElement {
|
|
|
168
165
|
case "show-model":
|
|
169
166
|
data = value.toLowerCase?.() === "true";
|
|
170
167
|
if (this.initialized) {
|
|
171
|
-
console.log("PrefViewer: toggling model visibility (attr)", data);
|
|
172
168
|
data ? this.showModel() : this.hideModel();
|
|
173
169
|
} else {
|
|
174
170
|
this.#data.containers.model.show = data;
|
|
@@ -177,7 +173,6 @@ class PrefViewer extends HTMLElement {
|
|
|
177
173
|
case "show-scene":
|
|
178
174
|
data = value.toLowerCase?.() === "true";
|
|
179
175
|
if (this.initialized) {
|
|
180
|
-
console.log("PrefViewer: toggling scene visibility (attr)", data);
|
|
181
176
|
data ? this.showScene() : this.hideScene();
|
|
182
177
|
} else {
|
|
183
178
|
this.#data.containers.environment.show = data;
|
|
@@ -187,7 +182,6 @@ class PrefViewer extends HTMLElement {
|
|
|
187
182
|
}
|
|
188
183
|
|
|
189
184
|
connectedCallback() {
|
|
190
|
-
console.log("PrefViewer: connectedCallback()");
|
|
191
185
|
if (!this.hasAttribute("config")) {
|
|
192
186
|
const error = 'PrefViewer: provide "models" as array of model and environment';
|
|
193
187
|
console.error(error);
|
|
@@ -204,19 +198,16 @@ class PrefViewer extends HTMLElement {
|
|
|
204
198
|
|
|
205
199
|
this.#initializeBabylon();
|
|
206
200
|
this.initialized = true;
|
|
207
|
-
console.log("PrefViewer: initialized = true, loading containers…");
|
|
208
201
|
this.#loadContainers(true, true, true);
|
|
209
202
|
}
|
|
210
203
|
|
|
211
204
|
disconnectedCallback() {
|
|
212
|
-
console.log("PrefViewer: disconnectedCallback()");
|
|
213
205
|
this.#disposeEngine();
|
|
214
206
|
this.#canvasResizeObserver.disconnect();
|
|
215
207
|
}
|
|
216
208
|
|
|
217
209
|
// Web Component
|
|
218
210
|
#createCanvas() {
|
|
219
|
-
console.log("PrefViewer: #createCanvas()");
|
|
220
211
|
this.#canvas = document.createElement("canvas");
|
|
221
212
|
Object.assign(this.#canvas.style, {
|
|
222
213
|
width: "100%",
|
|
@@ -227,7 +218,6 @@ class PrefViewer extends HTMLElement {
|
|
|
227
218
|
}
|
|
228
219
|
|
|
229
220
|
#wrapCanvas() {
|
|
230
|
-
console.log("PrefViewer: #wrapCanvas()");
|
|
231
221
|
this.#wrapper = document.createElement("div");
|
|
232
222
|
Object.assign(this.#wrapper.style, {
|
|
233
223
|
width: "100%",
|
|
@@ -239,7 +229,6 @@ class PrefViewer extends HTMLElement {
|
|
|
239
229
|
}
|
|
240
230
|
|
|
241
231
|
#setStatusSceneLoading() {
|
|
242
|
-
console.log("PrefViewer: #setStatusSceneLoading()");
|
|
243
232
|
this.loaded = false;
|
|
244
233
|
this.loading = true;
|
|
245
234
|
if (this.hasAttribute("loaded")) {
|
|
@@ -256,29 +245,28 @@ class PrefViewer extends HTMLElement {
|
|
|
256
245
|
}
|
|
257
246
|
|
|
258
247
|
#setStatusSceneLoaded() {
|
|
259
|
-
console.log("PrefViewer: #setStatusSceneLoaded()");
|
|
260
248
|
this.loaded = true;
|
|
261
249
|
this.loading = false;
|
|
262
250
|
|
|
263
251
|
const toLoadDetail = {
|
|
264
|
-
container_model: !!this.#data.containers.model.changed
|
|
265
|
-
container_environment: !!this.#data.containers.environment.changed
|
|
266
|
-
container_materials: !!this.#data.containers.materials.changed
|
|
267
|
-
options_camera: !!this.#data.options.camera.changed
|
|
268
|
-
options_innerWallMaterial: !!this.#data.options.materials.innerWall.changed
|
|
269
|
-
options_outerWallMaterial: !!this.#data.options.materials.outerWall.changed
|
|
270
|
-
options_innerFloorMaterial: !!this.#data.options.materials.innerFloor.changed
|
|
271
|
-
options_outerFloorMaterial: !!this.#data.options.materials.outerFloor.changed
|
|
252
|
+
container_model: !!this.#data.containers.model.changed,
|
|
253
|
+
container_environment: !!this.#data.containers.environment.changed,
|
|
254
|
+
container_materials: !!this.#data.containers.materials.changed,
|
|
255
|
+
options_camera: !!this.#data.options.camera.changed,
|
|
256
|
+
options_innerWallMaterial: !!this.#data.options.materials.innerWall.changed,
|
|
257
|
+
options_outerWallMaterial: !!this.#data.options.materials.outerWall.changed,
|
|
258
|
+
options_innerFloorMaterial: !!this.#data.options.materials.innerFloor.changed,
|
|
259
|
+
options_outerFloorMaterial: !!this.#data.options.materials.outerFloor.changed,
|
|
272
260
|
};
|
|
273
261
|
const loadedDetail = {
|
|
274
|
-
container_model: !!this.#data.containers.model.changed
|
|
275
|
-
container_environment: !!this.#data.containers.environment.changed
|
|
276
|
-
container_materials: !!this.#data.containers.materials.changed
|
|
277
|
-
options_camera: !!this.#data.options.camera.changed
|
|
278
|
-
options_innerWallMaterial: !!this.#data.options.materials.innerWall.changed
|
|
279
|
-
options_outerWallMaterial: !!this.#data.options.materials.outerWall.changed
|
|
280
|
-
options_innerFloorMaterial: !!this.#data.options.materials.innerFloor.changed
|
|
281
|
-
options_outerFloorMaterial: !!this.#data.options.materials.outerFloor.changed
|
|
262
|
+
container_model: !!this.#data.containers.model.changed?.success,
|
|
263
|
+
container_environment: !!this.#data.containers.environment.changed?.success,
|
|
264
|
+
container_materials: !!this.#data.containers.materials.changed?.success,
|
|
265
|
+
options_camera: !!this.#data.options.camera.changed?.success,
|
|
266
|
+
options_innerWallMaterial: !!this.#data.options.materials.innerWall.changed?.success,
|
|
267
|
+
options_outerWallMaterial: !!this.#data.options.materials.outerWall.changed?.success,
|
|
268
|
+
options_innerFloorMaterial: !!this.#data.options.materials.innerFloor.changed?.success,
|
|
269
|
+
options_outerFloorMaterial: !!this.#data.options.materials.outerFloor.changed?.success,
|
|
282
270
|
};
|
|
283
271
|
|
|
284
272
|
const detail = {
|
|
@@ -298,11 +286,10 @@ class PrefViewer extends HTMLElement {
|
|
|
298
286
|
detail: detail,
|
|
299
287
|
})
|
|
300
288
|
);
|
|
301
|
-
|
|
289
|
+
this.#resetChangedFlags();
|
|
302
290
|
}
|
|
303
291
|
|
|
304
292
|
#setStatusOptionsLoading() {
|
|
305
|
-
console.log("PrefViewer: #setStatusOptionsLoading()");
|
|
306
293
|
this.dispatchEvent(
|
|
307
294
|
new CustomEvent("options-loading", {
|
|
308
295
|
bubbles: true,
|
|
@@ -313,18 +300,19 @@ class PrefViewer extends HTMLElement {
|
|
|
313
300
|
}
|
|
314
301
|
|
|
315
302
|
#setStatusOptionsLoaded() {
|
|
316
|
-
console.log("PrefViewer: #setStatusOptionsLoaded()");
|
|
317
303
|
const toLoadDetail = {
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
304
|
+
camera: !!this.#data.options.camera.changed,
|
|
305
|
+
innerWallMaterial: !!this.#data.options.materials.innerWall.changed,
|
|
306
|
+
outerWallMaterial: !!this.#data.options.materials.outerWall.changed,
|
|
307
|
+
innerFloorMaterial: !!this.#data.options.materials.innerFloor.changed,
|
|
308
|
+
outerFloorMaterial: !!this.#data.options.materials.outerFloor.changed,
|
|
322
309
|
};
|
|
323
310
|
const loadedDetail = {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
311
|
+
camera: !!this.#data.options.camera.changed?.success,
|
|
312
|
+
innerWallMaterial: !!this.#data.options.materials.innerWall.changed?.success,
|
|
313
|
+
outerWallMaterial: !!this.#data.options.materials.outerWall.changed?.success,
|
|
314
|
+
innerFloorMaterial: !!this.#data.options.materials.innerFloor.changed?.success,
|
|
315
|
+
outerFloorMaterial: !!this.#data.options.materials.outerFloor.changed?.success,
|
|
328
316
|
};
|
|
329
317
|
|
|
330
318
|
const detail = {
|
|
@@ -340,7 +328,7 @@ class PrefViewer extends HTMLElement {
|
|
|
340
328
|
detail: detail,
|
|
341
329
|
})
|
|
342
330
|
);
|
|
343
|
-
|
|
331
|
+
this.#resetChangedFlags();
|
|
344
332
|
}
|
|
345
333
|
|
|
346
334
|
// Data
|
|
@@ -348,18 +336,10 @@ class PrefViewer extends HTMLElement {
|
|
|
348
336
|
if (!options || !options.camera) {
|
|
349
337
|
return false;
|
|
350
338
|
}
|
|
351
|
-
const
|
|
352
|
-
|
|
353
|
-
this.#data.options.camera.
|
|
354
|
-
|
|
355
|
-
pending: changed,
|
|
356
|
-
success: false,
|
|
357
|
-
oldValue: changed ? this.#data.options.camera.value : this.#data.options.camera.changed.oldValue,
|
|
358
|
-
oldLocked: changed ? this.#data.options.camera.locked : this.#data.options.camera.changed.oldLocked,
|
|
359
|
-
};
|
|
360
|
-
if (changed) this.#data.options.camera.value = options.camera;
|
|
361
|
-
|
|
362
|
-
return changed;
|
|
339
|
+
const cameraChanged = options.camera && options.camera !== this.#data.options.camera.value ? true : false;
|
|
340
|
+
this.#data.options.camera.changed = cameraChanged ? { oldValue: this.#data.options.camera.value, success: false } : false;
|
|
341
|
+
this.#data.options.camera.value = cameraChanged ? options.camera : this.#data.options.camera.value;
|
|
342
|
+
return cameraChanged;
|
|
363
343
|
}
|
|
364
344
|
|
|
365
345
|
#checkMaterialsChanged(options) {
|
|
@@ -369,68 +349,53 @@ class PrefViewer extends HTMLElement {
|
|
|
369
349
|
let someChanged = false;
|
|
370
350
|
Object.keys(this.#data.options.materials).forEach((material) => {
|
|
371
351
|
const key = `${material}Material`;
|
|
372
|
-
const
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
console.log("PrefViewer: #checkMaterialsChanged()", { key, incoming, previous: prev, materialChanged });
|
|
377
|
-
materialState.changed = {
|
|
378
|
-
...materialState.changed,
|
|
379
|
-
pending: materialChanged,
|
|
380
|
-
success: false,
|
|
381
|
-
oldValue: materialChanged ? prev : materialState.changed.oldValue,
|
|
382
|
-
};
|
|
383
|
-
materialState.value = materialChanged ? incoming : prev;
|
|
384
|
-
someChanged = someChanged || materialChanged;
|
|
352
|
+
const materialChanged = options[key] && options[key] !== this.#data.options.materials[material].value ? true : false;
|
|
353
|
+
this.#data.options.materials[material].changed = materialChanged ? { oldValue: this.#data.options.materials[material].value, success: false } : false;
|
|
354
|
+
this.#data.options.materials[material].value = materialChanged ? options[key] : this.#data.options.materials[material].value;
|
|
355
|
+
someChanged = someChanged || this.#data.options.materials[material].changed;
|
|
385
356
|
});
|
|
386
357
|
return someChanged;
|
|
387
358
|
}
|
|
388
359
|
|
|
389
|
-
#storeChangedFlagsForContainer(container) {
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
container.changed
|
|
360
|
+
#storeChangedFlagsForContainer(container, success) {
|
|
361
|
+
if (success) {
|
|
362
|
+
container.timeStamp = container.changed.timeStamp;
|
|
363
|
+
container.size = container.changed.size;
|
|
364
|
+
container.changed.success = success;
|
|
365
|
+
} else if (container.changed) {
|
|
366
|
+
container.source = container.changed.source;
|
|
367
|
+
container.changed = false;
|
|
368
|
+
} else {
|
|
369
|
+
container.changed = false;
|
|
370
|
+
}
|
|
395
371
|
}
|
|
396
372
|
|
|
397
373
|
#resetChangedFlags() {
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
node.changed.pending = false;
|
|
402
|
-
};
|
|
403
|
-
Object.values(this.#data.containers).forEach(reset);
|
|
404
|
-
Object.values(this.#data.options.materials).forEach(reset);
|
|
405
|
-
reset(this.#data.options.camera);
|
|
374
|
+
Object.values(this.#data.containers).forEach((container) => (container.changed = false));
|
|
375
|
+
Object.values(this.#data.options.materials).forEach((material) => (material.changed = false));
|
|
376
|
+
this.#data.options.camera.changed = false;
|
|
406
377
|
}
|
|
407
378
|
|
|
408
379
|
// Babylon.js
|
|
409
380
|
async #initializeBabylon() {
|
|
410
|
-
console.log("PrefViewer: #initializeBabylon() START");
|
|
411
381
|
this.#engine = new Engine(this.#canvas, true, { alpha: true });
|
|
412
|
-
this.#engine.disableUniformBuffers = true;
|
|
413
|
-
console.log("PrefViewer: Engine created", { disableUBO: this.#engine.disableUniformBuffers });
|
|
414
|
-
|
|
382
|
+
this.#engine.disableUniformBuffers = true;
|
|
415
383
|
this.#scene = new Scene(this.#engine);
|
|
416
384
|
this.#scene.clearColor = new Color4(1, 1, 1, 1);
|
|
417
|
-
console.log("PrefViewer: Scene created, clearColor set to white");
|
|
418
|
-
|
|
419
385
|
this.#createCamera();
|
|
420
386
|
this.#createLights();
|
|
421
387
|
this.#setupInteraction();
|
|
422
|
-
|
|
423
|
-
this.#engine.runRenderLoop(() => this.#scene && this.#scene.render());
|
|
424
|
-
console.log("PrefViewer: runRenderLoop started");
|
|
425
|
-
this.#canvasResizeObserver.observe(this.#canvas);
|
|
426
|
-
console.log("PrefViewer: ResizeObserver attached");
|
|
427
|
-
|
|
428
388
|
await this.#createXRExperience();
|
|
429
|
-
|
|
389
|
+
this.#engine.runRenderLoop(this.#renderLoop);
|
|
390
|
+
this.#canvasResizeObserver.observe(this.#canvas);
|
|
430
391
|
}
|
|
431
392
|
|
|
432
|
-
|
|
433
|
-
|
|
393
|
+
// If this function is defined as '#renderLoop() {}' it is not executed in 'this.#engine.runRenderLoop(this.#renderLoop)'
|
|
394
|
+
#renderLoop = () => {
|
|
395
|
+
this.#scene && this.#scene.render();
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
#addStylesToARButton() {
|
|
434
399
|
const css = '.babylonVRicon { color: #868686; border-color: #868686; border-style: solid; margin-left: 10px; height: 50px; width: 80px; background-color: rgba(51,51,51,0.7); background-image: url(data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%222048%22%20height%3D%221152%22%20viewBox%3D%220%200%202048%201152%22%20version%3D%221.1%22%3E%3Cpath%20transform%3D%22rotate%28180%201024%2C576.0000000000001%29%22%20d%3D%22m1109%2C896q17%2C0%2030%2C-12t13%2C-30t-12.5%2C-30.5t-30.5%2C-12.5l-170%2C0q-18%2C0%20-30.5%2C12.5t-12.5%2C30.5t13%2C30t30%2C12l170%2C0zm-85%2C256q59%2C0%20132.5%2C-1.5t154.5%2C-5.5t164.5%2C-11.5t163%2C-20t150%2C-30t124.5%2C-41.5q23%2C-11%2042%2C-24t38%2C-30q27%2C-25%2041%2C-61.5t14%2C-72.5l0%2C-257q0%2C-123%20-47%2C-232t-128%2C-190t-190%2C-128t-232%2C-47l-81%2C0q-37%2C0%20-68.5%2C14t-60.5%2C34.5t-55.5%2C45t-53%2C45t-53%2C34.5t-55.5%2C14t-55.5%2C-14t-53%2C-34.5t-53%2C-45t-55.5%2C-45t-60.5%2C-34.5t-68.5%2C-14l-81%2C0q-123%2C0%20-232%2C47t-190%2C128t-128%2C190t-47%2C232l0%2C257q0%2C68%2038%2C115t97%2C73q54%2C24%20124.5%2C41.5t150%2C30t163%2C20t164.5%2C11.5t154.5%2C5.5t132.5%2C1.5zm939%2C-298q0%2C39%20-24.5%2C67t-58.5%2C42q-54%2C23%20-122%2C39.5t-143.5%2C28t-155.5%2C19t-157%2C11t-148.5%2C5t-129.5%2C1.5q-59%2C0%20-130%2C-1.5t-148%2C-5t-157%2C-11t-155.5%2C-19t-143.5%2C-28t-122%2C-39.5q-34%2C-14%20-58.5%2C-42t-24.5%2C-67l0%2C-257q0%2C-106%2040.5%2C-199t110%2C-162.5t162.5%2C-109.5t199%2C-40l81%2C0q27%2C0%2052%2C14t50%2C34.5t51%2C44.5t55.5%2C44.5t63.5%2C34.5t74%2C14t74%2C-14t63.5%2C-34.5t55.5%2C-44.5t51%2C-44.5t50%2C-34.5t52%2C-14l14%2C0q37%2C0%2070%2C0.5t64.5%2C4.5t63.5%2C12t68%2C23q71%2C30%20128.5%2C78.5t98.5%2C110t63.5%2C133.5t22.5%2C149l0%2C257z%22%20fill%3D%22white%22%20/%3E%3C/svg%3E%0A); background-size: 80%; background-repeat:no-repeat; background-position: center; border: none; outline: none; transition: transform 0.125s ease-out } .babylonVRicon:hover { transform: scale(1.05) } .babylonVRicon:active {background-color: rgba(51,51,51,1) } .babylonVRicon:focus {background-color: rgba(51,51,51,1) }.babylonVRicon.vrdisplaypresenting { background-image: none;} .vrdisplaypresenting::after { content: "EXIT"} .xr-error::after { content: "ERROR"}';
|
|
435
400
|
const style = document.createElement("style");
|
|
436
401
|
style.appendChild(document.createTextNode(css));
|
|
@@ -438,15 +403,12 @@ class PrefViewer extends HTMLElement {
|
|
|
438
403
|
}
|
|
439
404
|
|
|
440
405
|
async #createXRExperience() {
|
|
441
|
-
console.log("PrefViewer: #createXRExperience() START");
|
|
442
406
|
if (this.#XRExperience) {
|
|
443
|
-
console.log("PrefViewer: XR already exists, skipping.");
|
|
444
407
|
return true;
|
|
445
408
|
}
|
|
446
409
|
|
|
447
410
|
const sessionMode = "immersive-ar";
|
|
448
411
|
const sessionSupported = await WebXRSessionManager.IsSessionSupportedAsync(sessionMode);
|
|
449
|
-
console.log("PrefViewer: WebXR session supported =", sessionSupported);
|
|
450
412
|
if (!sessionSupported) {
|
|
451
413
|
console.info("PrefViewer: WebXR in mode AR is not supported");
|
|
452
414
|
return false;
|
|
@@ -467,7 +429,6 @@ class PrefViewer extends HTMLElement {
|
|
|
467
429
|
};
|
|
468
430
|
|
|
469
431
|
this.#XRExperience = await WebXRDefaultExperience.CreateAsync(this.#scene, options);
|
|
470
|
-
console.log("PrefViewer: XR experience created");
|
|
471
432
|
|
|
472
433
|
const featuresManager = this.#XRExperience.baseExperience.featuresManager;
|
|
473
434
|
featuresManager.enableFeature(WebXRFeatureName.TELEPORTATION, "stable", {
|
|
@@ -477,43 +438,39 @@ class PrefViewer extends HTMLElement {
|
|
|
477
438
|
});
|
|
478
439
|
|
|
479
440
|
this.#XRExperience.baseExperience.sessionManager.onXRReady.add(() => {
|
|
480
|
-
console.log("PrefViewer: onXRReady - syncing camera pose");
|
|
481
441
|
// Set the initial position of xrCamera: use nonVRCamera, which contains a copy of the original this.#scene.activeCamera before entering XR
|
|
482
442
|
this.#XRExperience.baseExperience.camera.setTransformationFromNonVRCamera(this.#XRExperience.baseExperience._nonVRCamera);
|
|
483
443
|
this.#XRExperience.baseExperience.camera.setTarget(Vector3.Zero());
|
|
484
444
|
this.#XRExperience.baseExperience.onInitialXRPoseSetObservable.notifyObservers(this.#XRExperience.baseExperience.camera);
|
|
485
445
|
});
|
|
486
446
|
|
|
487
|
-
this
|
|
447
|
+
this.#addStylesToARButton();
|
|
488
448
|
} catch (error) {
|
|
489
449
|
console.warn("PrefViewer: failed to create WebXR experience", error);
|
|
490
450
|
this.#XRExperience = null;
|
|
491
451
|
}
|
|
492
|
-
console.log("PrefViewer: #createXRExperience() END");
|
|
493
452
|
}
|
|
494
453
|
|
|
495
454
|
#canvasResizeObserver = new ResizeObserver(() => this.#engine && this.#engine.resize());
|
|
496
455
|
|
|
497
456
|
#createCamera() {
|
|
498
|
-
console.log("PrefViewer: #createCamera()");
|
|
499
457
|
this.#camera = new ArcRotateCamera("camera", (3 * Math.PI) / 2, Math.PI * 0.47, 10, Vector3.Zero(), this.#scene);
|
|
500
458
|
this.#camera.upperBetaLimit = Math.PI * 0.48;
|
|
501
459
|
this.#camera.lowerBetaLimit = Math.PI * 0.25;
|
|
502
460
|
this.#camera.lowerRadiusLimit = 5;
|
|
503
461
|
this.#camera.upperRadiusLimit = 20;
|
|
504
|
-
this.#camera.metadata = { locked: false }
|
|
462
|
+
this.#camera.metadata = { locked: false };
|
|
505
463
|
this.#camera.attachControl(this.#canvas, true);
|
|
506
464
|
this.#scene.activeCamera = this.#camera;
|
|
507
|
-
console.log("PrefViewer: camera configured", {
|
|
508
|
-
upperBetaLimit: this.#camera.upperBetaLimit,
|
|
509
|
-
lowerBetaLimit: this.#camera.lowerBetaLimit,
|
|
510
|
-
lowerRadiusLimit: this.#camera.lowerRadiusLimit,
|
|
511
|
-
upperRadiusLimit: this.#camera.upperRadiusLimit
|
|
512
|
-
});
|
|
513
465
|
}
|
|
514
466
|
|
|
515
467
|
#createLights() {
|
|
516
|
-
|
|
468
|
+
this.#initEnvironmentTexture();
|
|
469
|
+
|
|
470
|
+
if (this.#scene.environmentTexture) {
|
|
471
|
+
return true;
|
|
472
|
+
}
|
|
473
|
+
|
|
517
474
|
// 1) Stronger ambient fill
|
|
518
475
|
this.#hemiLight = new HemisphericLight("hemiLight", new Vector3(-10, 10, -10), this.#scene);
|
|
519
476
|
this.#hemiLight.intensity = 0.6;
|
|
@@ -523,7 +480,7 @@ class PrefViewer extends HTMLElement {
|
|
|
523
480
|
this.#dirLight.position = new Vector3(5, 4, 5); // light is IN FRONT + ABOVE + to the RIGHT
|
|
524
481
|
this.#dirLight.intensity = 0.6;
|
|
525
482
|
|
|
526
|
-
// 3) Soft shadows
|
|
483
|
+
// // 3) Soft shadows
|
|
527
484
|
this.#shadowGen = new ShadowGenerator(1024, this.#dirLight);
|
|
528
485
|
this.#shadowGen.useBlurExponentialShadowMap = true;
|
|
529
486
|
this.#shadowGen.blurKernel = 16;
|
|
@@ -533,21 +490,103 @@ class PrefViewer extends HTMLElement {
|
|
|
533
490
|
this.#cameraLight = new PointLight("pl", this.#camera.position, this.#scene);
|
|
534
491
|
this.#cameraLight.parent = this.#camera;
|
|
535
492
|
this.#cameraLight.intensity = 0.3;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
#initEnvironmentTexture() {
|
|
496
|
+
return false;
|
|
497
|
+
if (this.#scene.environmentTexture) {
|
|
498
|
+
return true;
|
|
499
|
+
}
|
|
500
|
+
const hdrTextureURI = "../src/environments/noon_grass.hdr";
|
|
501
|
+
const hdrTexture = new HDRCubeTexture(hdrTextureURI, this.#scene, 128);
|
|
502
|
+
hdrTexture.gammaSpace = true;
|
|
503
|
+
hdrTexture._noMipmap = false;
|
|
504
|
+
hdrTexture.level = 2.0;
|
|
505
|
+
this.#scene.environmentTexture = hdrTexture;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
#initIBLShadows() {
|
|
509
|
+
if (!this.#scene.environmentTexture) {
|
|
510
|
+
return false;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
let createIBLShadowPipeline = function (scene) {
|
|
514
|
+
const pipeline = new IblShadowsRenderPipeline(
|
|
515
|
+
"iblShadowsPipeline",
|
|
516
|
+
scene,
|
|
517
|
+
{
|
|
518
|
+
resolutionExp: 7,
|
|
519
|
+
sampleDirections: 2,
|
|
520
|
+
ssShadowsEnabled: true,
|
|
521
|
+
shadowRemanence: 0.8,
|
|
522
|
+
triPlanarVoxelization: true,
|
|
523
|
+
shadowOpacity: 0.8,
|
|
524
|
+
},
|
|
525
|
+
[scene.activeCamera]
|
|
526
|
+
);
|
|
527
|
+
pipeline.allowDebugPasses = false;
|
|
528
|
+
pipeline.gbufferDebugEnabled = true;
|
|
529
|
+
pipeline.importanceSamplingDebugEnabled = false;
|
|
530
|
+
pipeline.voxelDebugEnabled = false;
|
|
531
|
+
pipeline.voxelDebugDisplayMip = 1;
|
|
532
|
+
pipeline.voxelDebugAxis = 2;
|
|
533
|
+
pipeline.voxelTracingDebugEnabled = false;
|
|
534
|
+
pipeline.spatialBlurPassDebugEnabled = false;
|
|
535
|
+
pipeline.accumulationPassDebugEnabled = false;
|
|
536
|
+
return pipeline;
|
|
537
|
+
};
|
|
538
|
+
|
|
539
|
+
let iblShadowsPipeline = createIBLShadowPipeline(this.#scene);
|
|
540
|
+
|
|
541
|
+
this.#scene.meshes.forEach((mesh) => {
|
|
542
|
+
if (mesh.id.startsWith("__root__") || mesh.name === "hdri") {
|
|
543
|
+
return false;
|
|
544
|
+
}
|
|
545
|
+
iblShadowsPipeline.addShadowCastingMesh(mesh);
|
|
546
|
+
iblShadowsPipeline.updateSceneBounds();
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
this.#scene.materials.forEach((material) => {
|
|
550
|
+
iblShadowsPipeline.addShadowReceivingMaterial(material);
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
#initShadows() {
|
|
555
|
+
if (!this.#scene.environmentTexture) {
|
|
556
|
+
this.#initIBLShadows();
|
|
557
|
+
return true;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
this.#scene.meshes.forEach((mesh) => {
|
|
561
|
+
if (mesh.id.startsWith("__root__")) {
|
|
562
|
+
return false;
|
|
563
|
+
}
|
|
564
|
+
mesh.receiveShadows = true;
|
|
565
|
+
if (!mesh.name === "hdri") {
|
|
566
|
+
this.#shadowGen.addShadowCaster(mesh, true);
|
|
567
|
+
}
|
|
568
|
+
});
|
|
569
|
+
}
|
|
536
570
|
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
571
|
+
#setMaxSimultaneousLights() {
|
|
572
|
+
let lightsNumber = 1; // Como mínimo una luz correspondiente a la textura de environmentTexture
|
|
573
|
+
this.#scene.lights.forEach((light) => {
|
|
574
|
+
if (light.isEnabled()) {
|
|
575
|
+
++lightsNumber;
|
|
576
|
+
}
|
|
542
577
|
});
|
|
578
|
+
if (this.#scene.materials) {
|
|
579
|
+
this.#scene.materials.forEach((material) => (material.maxSimultaneousLights = lightsNumber));
|
|
580
|
+
}
|
|
543
581
|
}
|
|
544
582
|
|
|
545
583
|
#setupInteraction() {
|
|
546
|
-
console.log("PrefViewer: #setupInteraction()");
|
|
547
584
|
this.#canvas.addEventListener("wheel", (event) => {
|
|
548
585
|
if (!this.#scene || !this.#camera) {
|
|
549
586
|
return false;
|
|
550
587
|
}
|
|
588
|
+
//const pick = this.#scene.pick(this.#scene.pointerX, this.#scene.pointerY);
|
|
589
|
+
//this.#camera.target = pick.hit ? pick.pickedPoint.clone() : this.#camera.target;
|
|
551
590
|
if (!this.#scene.activeCamera.metadata?.locked) {
|
|
552
591
|
this.#scene.activeCamera.inertialRadiusOffset -= event.deltaY * this.#scene.activeCamera.wheelPrecision * 0.001;
|
|
553
592
|
}
|
|
@@ -556,10 +595,7 @@ class PrefViewer extends HTMLElement {
|
|
|
556
595
|
}
|
|
557
596
|
|
|
558
597
|
#disposeEngine() {
|
|
559
|
-
console.log("PrefViewer: #disposeEngine()");
|
|
560
598
|
if (!this.#engine) return;
|
|
561
|
-
this.#shadowGen?.dispose();
|
|
562
|
-
this.#scene?.lights?.slice().forEach(l => l.dispose());
|
|
563
599
|
this.#engine.dispose();
|
|
564
600
|
this.#engine = this.#scene = this.#camera = null;
|
|
565
601
|
this.#hemiLight = this.#dirLight = this.#cameraLight = null;
|
|
@@ -568,7 +604,6 @@ class PrefViewer extends HTMLElement {
|
|
|
568
604
|
|
|
569
605
|
// Utility methods for loading gltf/glb
|
|
570
606
|
async #getServerFileDataHeader(uri) {
|
|
571
|
-
console.log("PrefViewer: #getServerFileDataHeader()", uri);
|
|
572
607
|
return new Promise((resolve) => {
|
|
573
608
|
const xhr = new XMLHttpRequest();
|
|
574
609
|
xhr.open("HEAD", uri, true);
|
|
@@ -577,15 +612,12 @@ class PrefViewer extends HTMLElement {
|
|
|
577
612
|
if (xhr.status === 200) {
|
|
578
613
|
const size = parseInt(xhr.getResponseHeader("Content-Length"));
|
|
579
614
|
const timeStamp = new Date(xhr.getResponseHeader("Last-Modified")).toISOString();
|
|
580
|
-
console.log("PrefViewer: HEAD ok", { size, timeStamp });
|
|
581
615
|
resolve([size, timeStamp]);
|
|
582
616
|
} else {
|
|
583
|
-
console.warn("PrefViewer: HEAD failed", xhr.status);
|
|
584
617
|
resolve([0, null]);
|
|
585
618
|
}
|
|
586
619
|
};
|
|
587
620
|
xhr.onerror = () => {
|
|
588
|
-
console.warn("PrefViewer: HEAD network error");
|
|
589
621
|
resolve([0, null]);
|
|
590
622
|
};
|
|
591
623
|
xhr.send();
|
|
@@ -594,14 +626,11 @@ class PrefViewer extends HTMLElement {
|
|
|
594
626
|
|
|
595
627
|
#transformUrl(url) {
|
|
596
628
|
return new Promise((resolve) => {
|
|
597
|
-
|
|
598
|
-
console.log("PrefViewer: #transformUrl()", { in: url, out: transformed });
|
|
599
|
-
resolve(transformed);
|
|
629
|
+
resolve(url.replace(/^blob:[^/]+\//i, "").replace(/\\/g, "/"));
|
|
600
630
|
});
|
|
601
631
|
}
|
|
602
632
|
|
|
603
633
|
#decodeBase64(base64) {
|
|
604
|
-
console.log("PrefViewer: #decodeBase64() START");
|
|
605
634
|
const [, payload] = base64.split(",");
|
|
606
635
|
const raw = payload || base64;
|
|
607
636
|
let decoded = "";
|
|
@@ -611,73 +640,55 @@ class PrefViewer extends HTMLElement {
|
|
|
611
640
|
try {
|
|
612
641
|
decoded = atob(raw);
|
|
613
642
|
} catch {
|
|
614
|
-
console.warn("PrefViewer: base64 decode failed (not base64?)");
|
|
615
643
|
return { blob, extension, size };
|
|
616
644
|
}
|
|
617
645
|
let isJson = false;
|
|
618
646
|
try {
|
|
619
647
|
JSON.parse(decoded);
|
|
620
648
|
isJson = true;
|
|
621
|
-
} catch {
|
|
649
|
+
} catch {}
|
|
622
650
|
extension = isJson ? ".gltf" : ".glb";
|
|
623
651
|
const type = isJson ? "model/gltf+json" : "model/gltf-binary";
|
|
624
652
|
const array = Uint8Array.from(decoded, (c) => c.charCodeAt(0));
|
|
625
653
|
blob = new Blob([array], { type });
|
|
626
|
-
console.log("PrefViewer: #decodeBase64() END", { extension, size, type });
|
|
627
654
|
return { blob, extension, size };
|
|
628
655
|
}
|
|
629
656
|
|
|
630
657
|
async #initStorage(db, table) {
|
|
631
|
-
console.log("PrefViewer: #initStorage()", { db, table });
|
|
632
658
|
if (window.gltfDB && window.gltfDB.name === db && window.gltfDB.objectStoreNames.contains(table)) {
|
|
633
|
-
console.log("PrefViewer: existing DB connection reused");
|
|
634
659
|
return true;
|
|
635
660
|
}
|
|
636
661
|
await initDb(db, table);
|
|
637
|
-
console.log("PrefViewer: DB initialized");
|
|
638
662
|
}
|
|
639
663
|
|
|
640
664
|
// Methods for managing Asset Containers
|
|
641
665
|
#setVisibilityOfWallAndFloorInModel(show) {
|
|
642
|
-
console.log("PrefViewer: #setVisibilityOfWallAndFloorInModel()", { incomingShow: show });
|
|
643
666
|
if (!this.#data.containers.model.assetContainer || !this.#data.containers.model.visible) {
|
|
644
|
-
console.log("PrefViewer: no model assetContainer or not visible, skip visibility set");
|
|
645
667
|
return false;
|
|
646
668
|
}
|
|
647
669
|
show = show !== undefined ? show : this.#data.containers.environment.visible;
|
|
648
670
|
const prefixes = Object.values(this.#data.options.materials).map((material) => material.prefix);
|
|
649
|
-
console.log("PrefViewer: toggling meshes with prefixes", prefixes, "->", show);
|
|
650
671
|
this.#data.containers.model.assetContainer.meshes.filter((meshToFilter) => prefixes.some((prefix) => meshToFilter.name.startsWith(prefix))).forEach((mesh) => mesh.setEnabled(show));
|
|
651
672
|
}
|
|
652
673
|
|
|
653
674
|
#setOptionsMaterial(optionMaterial) {
|
|
654
|
-
console.log("PrefViewer: #setOptionsMaterial()", { optionMaterial });
|
|
655
675
|
if (!optionMaterial || !optionMaterial.prefix || !optionMaterial.value) {
|
|
656
|
-
console.log("PrefViewer: optionMaterial incomplete, skipping");
|
|
657
676
|
return false;
|
|
658
677
|
}
|
|
659
|
-
|
|
660
|
-
const material = this.#data.containers.materials.assetContainer?.materials
|
|
661
|
-
.find((mat) => mat.name === optionMaterial.value) || null;
|
|
662
|
-
|
|
678
|
+
|
|
679
|
+
const material = this.#data.containers.materials.assetContainer?.materials.find((mat) => mat.name === optionMaterial.value) || null;
|
|
663
680
|
if (!material) {
|
|
664
|
-
console.warn("PrefViewer: material not found", optionMaterial.value);
|
|
665
681
|
return false;
|
|
666
682
|
}
|
|
667
|
-
|
|
668
|
-
const hadExplicitChange = !!optionMaterial.changed.pending;
|
|
669
|
-
|
|
683
|
+
|
|
670
684
|
const containers = [];
|
|
671
|
-
if (this.#data.containers.model.assetContainer &&
|
|
672
|
-
(this.#data.containers.model.changed.pending || this.#data.containers.materials.changed.pending || optionMaterial.changed.pending)) {
|
|
685
|
+
if (this.#data.containers.model.assetContainer && (this.#data.containers.model.changed || this.#data.containers.materials.changed || optionMaterial.changed)) {
|
|
673
686
|
containers.push(this.#data.containers.model.assetContainer);
|
|
674
687
|
}
|
|
675
|
-
if (this.#data.containers.environment.assetContainer &&
|
|
676
|
-
(this.#data.containers.environment.changed.pending || this.#data.containers.materials.changed.pending || optionMaterial.changed.pending)) {
|
|
688
|
+
if (this.#data.containers.environment.assetContainer && (this.#data.containers.environment.changed || this.#data.containers.materials.changed || optionMaterial.changed)) {
|
|
677
689
|
containers.push(this.#data.containers.environment.assetContainer);
|
|
678
690
|
}
|
|
679
691
|
if (containers.length === 0) {
|
|
680
|
-
console.log("PrefViewer: no containers require material update");
|
|
681
692
|
return false;
|
|
682
693
|
}
|
|
683
694
|
|
|
@@ -691,15 +702,9 @@ class PrefViewer extends HTMLElement {
|
|
|
691
702
|
})
|
|
692
703
|
);
|
|
693
704
|
|
|
694
|
-
console.log("PrefViewer: material assignment result", {
|
|
695
|
-
prefix: optionMaterial.prefix, material: optionMaterial.value, someSetted
|
|
696
|
-
});
|
|
697
|
-
|
|
698
705
|
if (someSetted) {
|
|
699
706
|
optionMaterial.changed.success = true;
|
|
700
|
-
|
|
701
|
-
} else if (hadExplicitChange) {
|
|
702
|
-
// Solo revertimos si el usuario pidió el cambio y falló
|
|
707
|
+
} else {
|
|
703
708
|
optionMaterial.value = optionMaterial.changed.oldValue;
|
|
704
709
|
}
|
|
705
710
|
|
|
@@ -707,140 +712,72 @@ class PrefViewer extends HTMLElement {
|
|
|
707
712
|
}
|
|
708
713
|
|
|
709
714
|
#setOptionsMaterials() {
|
|
710
|
-
console.log("PrefViewer: #setOptionsMaterials() START");
|
|
711
715
|
let someSetted = false;
|
|
712
716
|
Object.values(this.#data.options.materials).forEach((material) => {
|
|
713
717
|
let settedMaterial = this.#setOptionsMaterial(material);
|
|
714
718
|
someSetted = someSetted || settedMaterial;
|
|
715
719
|
});
|
|
716
|
-
console.log("PrefViewer: #setOptionsMaterials() END", { someSetted });
|
|
717
720
|
return someSetted;
|
|
718
721
|
}
|
|
719
722
|
|
|
720
723
|
#setOptionsCamera() {
|
|
721
|
-
|
|
722
|
-
requested: this.#data.options.camera.value,
|
|
723
|
-
changed: this.#data.options.camera.changed,
|
|
724
|
-
modelChanged: this.#data.containers.model.changed,
|
|
725
|
-
envChanged: this.#data.containers.environment.changed
|
|
726
|
-
});
|
|
727
|
-
|
|
728
|
-
const camState = this.#data.options.camera;
|
|
729
|
-
|
|
730
|
-
if (!camState.value && !camState.changed.pending && !this.#data.containers.model.changed.pending && !this.#data.containers.environment.changed.pending) {
|
|
724
|
+
if (!this.#data.options.camera.value || (!this.#data.options.camera.changed && !this.#data.containers.model.changed && !this.#data.containers.environment.changed)) {
|
|
731
725
|
return false;
|
|
732
726
|
}
|
|
733
727
|
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
let camera =
|
|
737
|
-
this.#data.containers.model.assetContainer?.cameras.find(c => c.name === camState.value) ||
|
|
738
|
-
this.#data.containers.environment.assetContainer?.cameras.find(c => c.name === camState.value) ||
|
|
739
|
-
null;
|
|
740
|
-
|
|
728
|
+
let camera = this.#data.containers.model.assetContainer?.cameras.find((thisCamera) => thisCamera.name === this.#data.options.camera.value) || this.#data.containers.environment.assetContainer?.cameras.find((thisCamera) => thisCamera.name === this.#data.options.camera.value) || null;
|
|
741
729
|
if (!camera) {
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
if (camera) {
|
|
750
|
-
camera.metadata = { locked: camState.changed.oldLocked };
|
|
751
|
-
camState.value = camState.changed.oldValue;
|
|
752
|
-
camState.locked = camState.changed.oldLocked;
|
|
753
|
-
camState.changed.success = false;
|
|
754
|
-
camState.changed.pending = false;
|
|
755
|
-
} else {
|
|
756
|
-
// Fallback a la cámara por defecto del componente
|
|
757
|
-
camera = this.#camera;
|
|
758
|
-
camState.value = null;
|
|
759
|
-
camState.locked = this.#camera.metadata.locked;
|
|
760
|
-
camState.changed.success = false;
|
|
761
|
-
camState.changed.pending = false;
|
|
762
|
-
}
|
|
730
|
+
if (this.#data.options.camera.changed?.oldValue && this.#data.options.camera.changed?.oldValue !== this.#data.options.camera.value) {
|
|
731
|
+
camera = this.#data.containers.model.assetContainer?.cameras.find((thisCamera) => thisCamera.name === this.#data.options.camera.changed.oldValue) || this.#data.containers.environment.assetContainer?.cameras.find((thisCamera) => thisCamera.name === his.#data.options.camera.changed.oldValue) || null;
|
|
732
|
+
}
|
|
733
|
+
if (camera) {
|
|
734
|
+
camera.metadata = { locked: this.#data.options.camera.changed.oldLocked };
|
|
735
|
+
this.#data.options.camera.value = this.#data.options.camera.changed.oldValue;
|
|
736
|
+
this.#data.options.camera.locked = this.#data.options.camera.changed.oldLocked;
|
|
763
737
|
} else {
|
|
764
|
-
// No hubo cambio explícito: usa fallback sin tocar changed
|
|
765
738
|
camera = this.#camera;
|
|
766
|
-
|
|
767
|
-
|
|
739
|
+
this.#data.options.camera.value = null;
|
|
740
|
+
this.#data.options.camera.locked = this.#camera.metadata.locked;
|
|
768
741
|
}
|
|
742
|
+
this.#data.options.camera.changed.success = false;
|
|
769
743
|
} else {
|
|
770
|
-
camera.metadata = { locked:
|
|
771
|
-
// Marca success si hubo cambio explícito
|
|
772
|
-
if (hadExplicitChange) {
|
|
773
|
-
camState.changed.success = true;
|
|
774
|
-
camState.changed.pending = false;
|
|
775
|
-
}
|
|
744
|
+
camera.metadata = { locked: this.#data.options.camera.locked };
|
|
776
745
|
}
|
|
777
|
-
|
|
778
|
-
if (!camState.locked && camState.value !== null) {
|
|
746
|
+
if (!this.#data.options.camera.locked && this.#data.options.camera.value !== null) {
|
|
779
747
|
camera.attachControl(this.#canvas, true);
|
|
780
748
|
}
|
|
781
749
|
this.#scene.activeCamera = camera;
|
|
782
|
-
console.log("PrefViewer: active camera set", { name: camera.name, locked: camera.metadata?.locked });
|
|
783
750
|
return true;
|
|
784
751
|
}
|
|
785
752
|
|
|
786
753
|
#addContainer(container) {
|
|
787
|
-
console.log("PrefViewer: #addContainer()", { name: container.name, hasContainer: !!container.assetContainer, visible: container.visible, show: container.show });
|
|
788
754
|
if (container.assetContainer && !container.visible && container.show) {
|
|
789
755
|
container.assetContainer.addAllToScene();
|
|
790
756
|
container.visible = true;
|
|
791
|
-
console.log("PrefViewer: container added to scene", container.name);
|
|
792
757
|
}
|
|
793
758
|
}
|
|
794
759
|
|
|
795
760
|
#removeContainer(container) {
|
|
796
|
-
console.log("PrefViewer: #removeContainer()", { name: container.name, hasContainer: !!container.assetContainer, visible: container.visible });
|
|
797
761
|
if (container.assetContainer && container.visible) {
|
|
798
762
|
container.assetContainer.removeAllFromScene();
|
|
799
763
|
container.visible = false;
|
|
800
|
-
console.log("PrefViewer: container removed from scene", container.name);
|
|
801
764
|
}
|
|
802
765
|
}
|
|
803
766
|
|
|
804
767
|
#replaceContainer(container, newAssetContainer) {
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
if (old) {
|
|
809
|
-
if (container.visible) { old.removeAllFromScene(); }
|
|
810
|
-
old.dispose(); // <- importante
|
|
811
|
-
console.log("PrefViewer: old container disposed", container.name);
|
|
768
|
+
if (container.assetContainer) {
|
|
769
|
+
container.assetContainer.dispose();
|
|
770
|
+
container.assetContainer = null;
|
|
812
771
|
}
|
|
813
|
-
|
|
814
|
-
// 2) asigna el nuevo y prepara
|
|
772
|
+
this.#scene.getEngine().releaseEffects();
|
|
815
773
|
container.assetContainer = newAssetContainer;
|
|
816
|
-
|
|
817
|
-
// Opcional: limitar luces por material para ganar margen
|
|
818
|
-
container.assetContainer.materials?.forEach(m => {
|
|
819
|
-
if ("maxSimultaneousLights" in m) {
|
|
820
|
-
m.maxSimultaneousLights = 2; // 2–3 suele ir bien
|
|
821
|
-
}
|
|
822
|
-
});
|
|
823
|
-
|
|
824
|
-
// 3) sombras solo para los meshes que te interesen (mejor que todos)
|
|
825
|
-
container.assetContainer.meshes.forEach(mesh => {
|
|
826
|
-
mesh.receiveShadows = true;
|
|
827
|
-
this.#shadowGen.addShadowCaster(mesh, true);
|
|
828
|
-
});
|
|
829
|
-
|
|
830
|
-
// 4) añade a escena
|
|
831
774
|
this.#addContainer(container);
|
|
832
|
-
|
|
833
|
-
// 5) fuerza recompilación con defines correctos del nuevo estado
|
|
834
|
-
this.#scene.getEngine().releaseEffects();
|
|
835
|
-
console.log("PrefViewer: container replaced and effects released", container.name);
|
|
836
775
|
}
|
|
837
776
|
|
|
838
777
|
async #loadAssetContainer(container) {
|
|
839
|
-
console.log("PrefViewer: #loadAssetContainer() START", { name: container?.name, storage: container?.storage });
|
|
840
778
|
let storage = container?.storage;
|
|
841
779
|
|
|
842
780
|
if (!storage) {
|
|
843
|
-
console.log("PrefViewer: no storage, skipping", container?.name);
|
|
844
781
|
return false;
|
|
845
782
|
}
|
|
846
783
|
|
|
@@ -851,22 +788,14 @@ class PrefViewer extends HTMLElement {
|
|
|
851
788
|
const object = await loadModel(storage.id, storage.table);
|
|
852
789
|
source = object.data;
|
|
853
790
|
if (object.timeStamp === container.timeStamp) {
|
|
854
|
-
|
|
791
|
+
container.changed = false;
|
|
855
792
|
return false;
|
|
856
793
|
} else {
|
|
857
|
-
container.changed
|
|
858
|
-
...container.changed,
|
|
859
|
-
pending: true,
|
|
860
|
-
success: false,
|
|
861
|
-
timeStamp: object.timeStamp,
|
|
862
|
-
size: object.size,
|
|
863
|
-
};
|
|
864
|
-
console.log("PrefViewer: DB entry changed", container.changed);
|
|
794
|
+
Object.assign(container.changed, { timeStamp: object.timeStamp, size: object.size, success: false });
|
|
865
795
|
}
|
|
866
796
|
}
|
|
867
797
|
|
|
868
798
|
if (!source) {
|
|
869
|
-
console.log("PrefViewer: no source after storage resolution", container.name);
|
|
870
799
|
return false;
|
|
871
800
|
}
|
|
872
801
|
|
|
@@ -877,40 +806,27 @@ class PrefViewer extends HTMLElement {
|
|
|
877
806
|
file = new File([blob], `${container.name}${extension}`, {
|
|
878
807
|
type: blob.type,
|
|
879
808
|
});
|
|
880
|
-
if (!container.changed
|
|
809
|
+
if (!container.changed) {
|
|
881
810
|
if (container.timeStamp === null && container.size === size) {
|
|
882
|
-
|
|
811
|
+
container.changed = false;
|
|
883
812
|
return false;
|
|
884
813
|
} else {
|
|
885
|
-
container.changed
|
|
886
|
-
...container.changed,
|
|
887
|
-
pending: true,
|
|
888
|
-
success: false,
|
|
889
|
-
timeStamp: null,
|
|
890
|
-
size: size,
|
|
891
|
-
};
|
|
814
|
+
Object.assign(container.changed, { timeStamp: null, size: size, success: false });
|
|
892
815
|
}
|
|
893
816
|
}
|
|
894
|
-
console.log("PrefViewer: prepared File from base64", { name: file.name, size: file.size, type: file.type });
|
|
895
817
|
} else {
|
|
896
818
|
const extMatch = source.match(/\.(gltf|glb)(\?|#|$)/i);
|
|
897
819
|
extension = extMatch ? `.${extMatch[1].toLowerCase()}` : ".gltf";
|
|
898
820
|
const [fileSize, fileTimeStamp] = await this.#getServerFileDataHeader(source);
|
|
899
821
|
if (container.size === fileSize && container.timeStamp === fileTimeStamp) {
|
|
900
|
-
|
|
822
|
+
container.changed = false;
|
|
901
823
|
return false;
|
|
902
824
|
} else {
|
|
903
|
-
container.changed
|
|
904
|
-
...container.changed,
|
|
905
|
-
pending: true,
|
|
906
|
-
success: false,
|
|
907
|
-
timeStamp: fileTimeStamp,
|
|
908
|
-
size: fileSize,
|
|
909
|
-
};
|
|
910
|
-
console.log("PrefViewer: remote file changed", container.changed);
|
|
825
|
+
Object.assign(container.changed, { timeStamp: fileTimeStamp, size: fileSize, success: false });
|
|
911
826
|
}
|
|
912
827
|
}
|
|
913
828
|
|
|
829
|
+
// https://doc.babylonjs.com/typedoc/interfaces/BABYLON.LoadAssetContainerOptions
|
|
914
830
|
let options = {
|
|
915
831
|
pluginExtension: extension,
|
|
916
832
|
pluginOptions: {
|
|
@@ -921,58 +837,56 @@ class PrefViewer extends HTMLElement {
|
|
|
921
837
|
},
|
|
922
838
|
};
|
|
923
839
|
|
|
924
|
-
console.log("PrefViewer: calling LoadAssetContainerAsync()", { extension });
|
|
925
840
|
return LoadAssetContainerAsync(file || source, this.#scene, options);
|
|
926
841
|
}
|
|
927
842
|
|
|
928
843
|
async #loadContainers(loadModel = true, loadEnvironment = true, loadMaterials = true) {
|
|
929
|
-
|
|
844
|
+
this.#setStatusSceneLoading();
|
|
845
|
+
this.#engine.stopRenderLoop(this.#renderLoop);
|
|
846
|
+
|
|
930
847
|
const promiseArray = [];
|
|
931
848
|
promiseArray.push(loadModel ? this.#loadAssetContainer(this.#data.containers.model) : false);
|
|
932
849
|
promiseArray.push(loadEnvironment ? this.#loadAssetContainer(this.#data.containers.environment) : false);
|
|
933
850
|
promiseArray.push(loadMaterials ? this.#loadAssetContainer(this.#data.containers.materials) : false);
|
|
934
851
|
|
|
935
|
-
this.#setStatusSceneLoading();
|
|
936
|
-
|
|
937
852
|
Promise.allSettled(promiseArray)
|
|
938
853
|
.then(async (values) => {
|
|
939
|
-
console.log("PrefViewer: Promise.allSettled results", values);
|
|
940
854
|
const modelContainer = values[0];
|
|
941
855
|
const environmentContainer = values[1];
|
|
942
856
|
const materialsContainer = values[2];
|
|
943
857
|
|
|
858
|
+
this.#removeContainer(this.#data.containers.model);
|
|
859
|
+
this.#removeContainer(this.#data.containers.environment);
|
|
860
|
+
this.#removeContainer(this.#data.containers.materials);
|
|
861
|
+
|
|
944
862
|
if (modelContainer.status === "fulfilled" && modelContainer.value) {
|
|
945
|
-
|
|
946
|
-
this.#stripImportedLights(modelContainer.value);
|
|
863
|
+
modelContainer.value.lights = [];
|
|
947
864
|
this.#replaceContainer(this.#data.containers.model, modelContainer.value);
|
|
948
|
-
this.#storeChangedFlagsForContainer(this.#data.containers.model);
|
|
865
|
+
this.#storeChangedFlagsForContainer(this.#data.containers.model, true);
|
|
949
866
|
} else {
|
|
950
|
-
|
|
951
|
-
this.#
|
|
867
|
+
this.#addContainer(this.#data.containers.model);
|
|
868
|
+
this.#storeChangedFlagsForContainer(this.#data.containers.model, false);
|
|
952
869
|
}
|
|
953
870
|
|
|
954
871
|
if (environmentContainer.status === "fulfilled" && environmentContainer.value) {
|
|
955
|
-
console.log("PrefViewer: environment container fulfilled, applying");
|
|
956
|
-
this.#stripImportedLights(environmentContainer.value);
|
|
957
872
|
this.#replaceContainer(this.#data.containers.environment, environmentContainer.value);
|
|
958
|
-
this.#storeChangedFlagsForContainer(this.#data.containers.environment);
|
|
873
|
+
this.#storeChangedFlagsForContainer(this.#data.containers.environment, true);
|
|
959
874
|
} else {
|
|
960
|
-
|
|
961
|
-
this.#
|
|
875
|
+
this.#addContainer(this.#data.containers.environment);
|
|
876
|
+
this.#storeChangedFlagsForContainer(this.#data.containers.environment, false);
|
|
962
877
|
}
|
|
963
878
|
|
|
964
879
|
if (materialsContainer.status === "fulfilled" && materialsContainer.value) {
|
|
965
|
-
console.log("PrefViewer: materials container fulfilled, applying");
|
|
966
|
-
this.#stripImportedLights(materialsContainer.value);
|
|
967
880
|
this.#replaceContainer(this.#data.containers.materials, materialsContainer.value);
|
|
968
|
-
this.#storeChangedFlagsForContainer(this.#data.containers.materials);
|
|
881
|
+
this.#storeChangedFlagsForContainer(this.#data.containers.materials, true);
|
|
882
|
+
} else {
|
|
883
|
+
this.#addContainer(this.#data.containers.materials);
|
|
884
|
+
this.#storeChangedFlagsForContainer(this.#data.containers.materials, false);
|
|
969
885
|
}
|
|
970
886
|
|
|
971
887
|
this.#setOptionsMaterials();
|
|
972
888
|
this.#setOptionsCamera();
|
|
973
889
|
this.#setVisibilityOfWallAndFloorInModel();
|
|
974
|
-
this.#setStatusSceneLoaded();
|
|
975
|
-
this.#resetChangedFlags();
|
|
976
890
|
})
|
|
977
891
|
.catch((error) => {
|
|
978
892
|
this.loaded = true;
|
|
@@ -985,34 +899,36 @@ class PrefViewer extends HTMLElement {
|
|
|
985
899
|
detail: { error: error },
|
|
986
900
|
})
|
|
987
901
|
);
|
|
902
|
+
})
|
|
903
|
+
.finally(() => {
|
|
904
|
+
this.#setMaxSimultaneousLights();
|
|
905
|
+
this.#initShadows();
|
|
906
|
+
this.#setStatusSceneLoaded();
|
|
907
|
+
this.#engine.runRenderLoop(this.#renderLoop);
|
|
988
908
|
});
|
|
989
909
|
}
|
|
990
910
|
|
|
991
|
-
#stripImportedLights(container) {
|
|
992
|
-
console.log("PrefViewer: #stripImportedLights()", { lights: container?.lights?.length || 0 });
|
|
993
|
-
// El glTF puede traer KHR_lights_punctual: bórralas antes de añadir a la escena
|
|
994
|
-
if (container?.lights?.length) {
|
|
995
|
-
// Clonar para no mutar mientras iteras
|
|
996
|
-
container.lights.slice().forEach(l => l.dispose());
|
|
997
|
-
console.log("PrefViewer: stripped punctual lights from imported asset");
|
|
998
|
-
}
|
|
999
|
-
}
|
|
1000
|
-
|
|
1001
911
|
// Public Methods
|
|
1002
912
|
loadConfig(config) {
|
|
1003
|
-
console.log("PrefViewer: loadConfig()", config);
|
|
1004
913
|
config = typeof config === "string" ? JSON.parse(config) : config;
|
|
1005
914
|
if (!config) {
|
|
1006
|
-
console.warn("PrefViewer: loadConfig() no config provided");
|
|
1007
915
|
return false;
|
|
1008
916
|
}
|
|
1009
917
|
|
|
1010
918
|
// Containers
|
|
1011
|
-
|
|
919
|
+
const loadModel = !!config.model?.storage;
|
|
920
|
+
this.#data.containers.model.changed = loadModel ? { storage: this.#data.containers.model.storage } : false;
|
|
921
|
+
this.#data.containers.model.storage = loadModel ? config.model.storage : this.#data.containers.model.storage;
|
|
1012
922
|
this.#data.containers.model.show = config.model?.visible !== undefined ? config.model.visible : this.#data.containers.model.show;
|
|
1013
|
-
|
|
923
|
+
|
|
924
|
+
const loadEnvironment = !!config.scene?.storage;
|
|
925
|
+
this.#data.containers.environment.changed = loadEnvironment ? { storage: this.#data.containers.environment.storage } : false;
|
|
926
|
+
this.#data.containers.environment.storage = loadEnvironment ? config.scene.storage : this.#data.containers.environment.storage;
|
|
1014
927
|
this.#data.containers.environment.show = config.scene?.visible !== undefined ? config.scene.visible : this.#data.containers.environment.show;
|
|
1015
|
-
|
|
928
|
+
|
|
929
|
+
const loadMaterials = !!config.materials?.storage;
|
|
930
|
+
this.#data.containers.materials.changed = loadMaterials ? { storage: this.#data.containers.materials.storage } : false;
|
|
931
|
+
this.#data.containers.materials.storage = loadMaterials ? config.materials.storage : this.#data.containers.materials.storage;
|
|
1016
932
|
|
|
1017
933
|
// Options
|
|
1018
934
|
if (config.options) {
|
|
@@ -1020,11 +936,10 @@ class PrefViewer extends HTMLElement {
|
|
|
1020
936
|
this.#checkMaterialsChanged(config.options);
|
|
1021
937
|
}
|
|
1022
938
|
|
|
1023
|
-
this.initialized && this.#loadContainers(
|
|
939
|
+
this.initialized && this.#loadContainers(loadModel, loadEnvironment, loadMaterials);
|
|
1024
940
|
}
|
|
1025
941
|
|
|
1026
942
|
setOptions(options) {
|
|
1027
|
-
console.log("PrefViewer: setOptions()", options);
|
|
1028
943
|
if (!options) {
|
|
1029
944
|
return false;
|
|
1030
945
|
}
|
|
@@ -1040,69 +955,73 @@ class PrefViewer extends HTMLElement {
|
|
|
1040
955
|
}
|
|
1041
956
|
|
|
1042
957
|
this.#setStatusOptionsLoaded();
|
|
1043
|
-
this.#resetChangedFlags();
|
|
1044
958
|
|
|
1045
959
|
return someSetted;
|
|
1046
960
|
}
|
|
1047
961
|
|
|
1048
962
|
loadModel(model) {
|
|
1049
|
-
console.log("PrefViewer: loadModel()", model);
|
|
1050
963
|
model = typeof model === "string" ? JSON.parse(model) : model;
|
|
1051
964
|
if (!model) {
|
|
1052
|
-
console.warn("PrefViewer: loadModel() no model provided");
|
|
1053
965
|
return false;
|
|
1054
966
|
}
|
|
1055
|
-
|
|
967
|
+
const loadModel = !!model.storage;
|
|
968
|
+
this.#data.containers.model.changed = loadModel ? { storage: this.#data.containers.model.storage } : false;
|
|
969
|
+
this.#data.containers.model.storage = loadModel ? model.storage : this.#data.containers.model.storage;
|
|
1056
970
|
this.#data.containers.model.show = model.visible !== undefined ? model.visible : this.#data.containers.model.show;
|
|
1057
|
-
this.initialized && this.#loadContainers(
|
|
971
|
+
this.initialized && this.#loadContainers(loadModel, false, false);
|
|
1058
972
|
}
|
|
1059
973
|
|
|
1060
974
|
loadScene(scene) {
|
|
1061
|
-
console.log("PrefViewer: loadScene()", scene);
|
|
1062
975
|
scene = typeof scene === "string" ? JSON.parse(scene) : scene;
|
|
1063
976
|
if (!scene) {
|
|
1064
|
-
console.warn("PrefViewer: loadScene() no scene provided");
|
|
1065
977
|
return false;
|
|
1066
978
|
}
|
|
1067
|
-
|
|
979
|
+
const loadEnvironment = !!scene.storage;
|
|
980
|
+
this.#data.containers.environment.changed = loadEnvironment ? { storage: this.#data.containers.environment.storage } : false;
|
|
981
|
+
this.#data.containers.environment.storage = loadEnvironment ? scene.storage : this.#data.containers.environment.storage;
|
|
1068
982
|
this.#data.containers.environment.show = scene.visible !== undefined ? scene.visible : this.#data.containers.environment.show;
|
|
1069
|
-
this.initialized && this.#loadContainers(false,
|
|
983
|
+
this.initialized && this.#loadContainers(false, loadEnvironment, false);
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
loadMaterials(materials) {
|
|
987
|
+
materials = typeof materials === "string" ? JSON.parse(materials) : materials;
|
|
988
|
+
if (!materials) {
|
|
989
|
+
return false;
|
|
990
|
+
}
|
|
991
|
+
const loadMaterials = !!materials.storage;
|
|
992
|
+
this.#data.containers.materials.changed = loadMaterials ? { storage: this.#data.containers.materials.storage } : false;
|
|
993
|
+
this.#data.containers.materials.storage = loadMaterials ? materials.storage : this.#data.containers.materials.storage;
|
|
994
|
+
this.initialized && this.#loadContainers(false, false, loadMaterials);
|
|
1070
995
|
}
|
|
1071
996
|
|
|
1072
997
|
showModel() {
|
|
1073
|
-
console.log("PrefViewer: showModel()");
|
|
1074
998
|
this.#data.containers.model.show = true;
|
|
1075
999
|
this.#addContainer(this.#data.containers.model);
|
|
1076
1000
|
}
|
|
1077
1001
|
|
|
1078
1002
|
hideModel() {
|
|
1079
|
-
console.log("PrefViewer: hideModel()");
|
|
1080
1003
|
this.#data.containers.model.show = false;
|
|
1081
1004
|
this.#removeContainer(this.#data.containers.model);
|
|
1082
1005
|
}
|
|
1083
1006
|
|
|
1084
1007
|
showScene() {
|
|
1085
|
-
console.log("PrefViewer: showScene()");
|
|
1086
1008
|
this.#data.containers.environment.show = true;
|
|
1087
1009
|
this.#addContainer(this.#data.containers.environment);
|
|
1088
1010
|
this.#setVisibilityOfWallAndFloorInModel();
|
|
1089
1011
|
}
|
|
1090
1012
|
|
|
1091
1013
|
hideScene() {
|
|
1092
|
-
console.log("PrefViewer: hideScene()");
|
|
1093
1014
|
this.#data.containers.environment.show = false;
|
|
1094
1015
|
this.#removeContainer(this.#data.containers.environment);
|
|
1095
1016
|
this.#setVisibilityOfWallAndFloorInModel();
|
|
1096
1017
|
}
|
|
1097
1018
|
|
|
1098
1019
|
downloadModelGLB() {
|
|
1099
|
-
console.log("PrefViewer: downloadModelGLB()");
|
|
1100
1020
|
const fileName = "model";
|
|
1101
1021
|
GLTF2Export.GLBAsync(this.#data.containers.model.assetContainer, fileName, { exportWithoutWaitingForScene: true }).then((glb) => glb.downloadFiles());
|
|
1102
1022
|
}
|
|
1103
1023
|
|
|
1104
1024
|
downloadModelUSDZ() {
|
|
1105
|
-
console.log("PrefViewer: downloadModelUSDZ()");
|
|
1106
1025
|
const fileName = "model";
|
|
1107
1026
|
USDZExportAsync(this.#data.containers.model.assetContainer).then((response) => {
|
|
1108
1027
|
if (response) {
|
|
@@ -1112,7 +1031,6 @@ class PrefViewer extends HTMLElement {
|
|
|
1112
1031
|
}
|
|
1113
1032
|
|
|
1114
1033
|
downloadModelAndSceneUSDZ() {
|
|
1115
|
-
console.log("PrefViewer: downloadModelAndSceneUSDZ()");
|
|
1116
1034
|
const fileName = "scene";
|
|
1117
1035
|
USDZExportAsync(this.#scene).then((response) => {
|
|
1118
1036
|
if (response) {
|
|
@@ -1122,7 +1040,6 @@ class PrefViewer extends HTMLElement {
|
|
|
1122
1040
|
}
|
|
1123
1041
|
|
|
1124
1042
|
downloadModelAndSceneGLB() {
|
|
1125
|
-
console.log("PrefViewer: downloadModelAndSceneGLB()");
|
|
1126
1043
|
const fileName = "scene";
|
|
1127
1044
|
GLTF2Export.GLBAsync(this.#scene, fileName, { exportWithoutWaitingForScene: true }).then((glb) => glb.downloadFiles());
|
|
1128
1045
|
}
|