@preference-sl/pref-viewer 2.12.0-beta.5 → 2.12.0-beta.6

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@preference-sl/pref-viewer",
3
- "version": "2.12.0-beta.5",
3
+ "version": "2.12.0-beta.6",
4
4
  "description": "Web Component to preview GLTF models with Babylon.js",
5
5
  "author": "Alex Moreno Palacio <amoreno@preference.es>",
6
6
  "scripts": {
@@ -313,18 +313,27 @@ export default class BabylonJSController {
313
313
  }
314
314
 
315
315
  // 1) Stronger ambient fill
316
- this.#hemiLight = new HemisphericLight("PrefViewerHemiLight", new Vector3(-10, 10, -10), this.#scene);
317
- this.#hemiLight.intensity = 0.6;
316
+ this.#hemiLight = this.#scene.getLightByName("PrefViewerHemiLight");
317
+ if (!this.#hemiLight) {
318
+ this.#hemiLight = new HemisphericLight("PrefViewerHemiLight", new Vector3(-10, 10, -10), this.#scene);
319
+ this.#hemiLight.intensity = 0.6;
320
+ }
318
321
 
319
322
  // 2) Directional light from the front-right, angled slightly down
320
- this.#dirLight = new DirectionalLight("PrefViewerDirLight", new Vector3(-10, 10, -10), this.#scene);
321
- this.#dirLight.position = new Vector3(5, 4, 5); // light is IN FRONT + ABOVE + to the RIGHT
322
- this.#dirLight.intensity = 0.6;
323
+ this.#dirLight = this.#scene.getLightByName("PrefViewerDirLight");
324
+ if (!this.#dirLight) {
325
+ this.#dirLight = new DirectionalLight("PrefViewerDirLight", new Vector3(-10, 10, -10), this.#scene);
326
+ this.#dirLight.position = new Vector3(5, 4, 5); // light is IN FRONT + ABOVE + to the RIGHT
327
+ this.#dirLight.intensity = 0.6;
328
+ }
323
329
 
324
330
  // 3) Camera‐attached headlight
325
- this.#cameraLight = new PointLight("PrefViewerCameraLight", this.#camera.position, this.#scene);
326
- this.#cameraLight.parent = this.#camera;
327
- this.#cameraLight.intensity = 0.3;
331
+ this.#cameraLight = this.#scene.getLightByName("PrefViewerCameraLight");
332
+ if (!this.#cameraLight) {
333
+ this.#cameraLight = new PointLight("PrefViewerCameraLight", this.#camera.position, this.#scene);
334
+ this.#cameraLight.parent = this.#camera;
335
+ this.#cameraLight.intensity = 0.3;
336
+ }
328
337
  }
329
338
 
330
339
  /**
@@ -375,6 +384,13 @@ export default class BabylonJSController {
375
384
  ssaoPipeline.radius = 0.0001;
376
385
  ssaoPipeline.totalStrength = 1;
377
386
  ssaoPipeline.base = 0.6;
387
+
388
+ // Configure SSAO to calculate only once instead of every frame for better performance
389
+ if (ssaoPipeline._ssaoPostProcess) {
390
+ ssaoPipeline._ssaoPostProcess.autoClear = false;
391
+ ssaoPipeline._ssaoPostProcess.samples = 1;
392
+ }
393
+
378
394
  this.#scene.postProcessRenderPipelineManager.update();
379
395
  return true;
380
396
  } else {
@@ -447,6 +463,14 @@ export default class BabylonJSController {
447
463
  defaultPipeline.grain.animated = false;
448
464
  defaultPipeline.grain.intensity = 3;
449
465
 
466
+ // Configure post-processes to calculate only once instead of every frame for better performance
467
+ if (defaultPipeline.fxaa?._postProcess) {
468
+ defaultPipeline.fxaa._postProcess.autoClear = false;
469
+ }
470
+ if (defaultPipeline.grain?._postProcess) {
471
+ defaultPipeline.grain._postProcess.autoClear = false;
472
+ }
473
+
450
474
  this.#scene.postProcessRenderPipelineManager.update();
451
475
  return true;
452
476
  } else {
@@ -533,8 +557,15 @@ export default class BabylonJSController {
533
557
 
534
558
  Object.assign(iblShadowsRenderPipeline, pipelineProps);
535
559
 
560
+ if (iblShadowsRenderPipeline._ssaoPostProcess) {
561
+ iblShadowsRenderPipeline._ssaoPostProcess.autoClear = false;
562
+ iblShadowsRenderPipeline._ssaoPostProcess.samples = 1;
563
+ }
564
+
536
565
  this.#scene.meshes.forEach((mesh) => {
537
- if (mesh.id.startsWith("__root__") || mesh.name === "hdri") {
566
+ const isRootMesh = mesh.id.startsWith("__root__");
567
+ const isHDRIMesh = mesh.name?.toLowerCase() === "hdri";
568
+ if (isRootMesh || isHDRIMesh) {
538
569
  return false;
539
570
  }
540
571
  iblShadowsRenderPipeline.addShadowCastingMesh(mesh);
@@ -578,7 +609,7 @@ export default class BabylonJSController {
578
609
  if (mesh.id.startsWith("__root__")) {
579
610
  return false;
580
611
  }
581
- if (mesh.name !== "hdri") {
612
+ if (mesh.name?.toLowerCase() !== "hdri") {
582
613
  shadowGenerator.addShadowCaster(mesh, true);
583
614
  }
584
615
  mesh.receiveShadows = true;
@@ -618,7 +649,7 @@ export default class BabylonJSController {
618
649
  if (mesh.id.startsWith("__root__")) {
619
650
  return false;
620
651
  }
621
- if (mesh.name !== "hdri") {
652
+ if (mesh.name?.toLowerCase() !== "hdri") {
622
653
  shadowGenerator.addShadowCaster(mesh, true);
623
654
  }
624
655
  });
@@ -1341,6 +1372,13 @@ export default class BabylonJSController {
1341
1372
  }
1342
1373
  }
1343
1374
 
1375
+ /**
1376
+ * Configures realistic glass material properties for all materials whose names include "Glass".
1377
+ * @private
1378
+ * @param {AssetContainer} [assetContainer] - The asset container with materials to process. If undefined, uses the model container.
1379
+ * @returns {void}
1380
+ * @note This method assumes that glass materials are named with the substring "Glass".
1381
+ */
1344
1382
  #forceReflectionsInModelGlasses(assetContainer) {
1345
1383
  if (assetContainer === undefined) {
1346
1384
  assetContainer = this.#containers.model.assetContainer;
@@ -1350,7 +1388,7 @@ export default class BabylonJSController {
1350
1388
  }
1351
1389
  assetContainer.materials?.forEach(material => {
1352
1390
  if (material && material.name && material.name.includes("Glass")) {
1353
- material.metallic = 1.0;
1391
+ material.metallic = 0.25;
1354
1392
  material.environmentIntensity = 1.0;
1355
1393
  }
1356
1394
  });
@@ -169,7 +169,7 @@ export class FileStorage {
169
169
  let file = undefined;
170
170
  return new Promise((resolve) => {
171
171
  const xhr = new XMLHttpRequest();
172
- xhr.open("GET", uri, true);
172
+ xhr.open("GET", encodeURI(uri), true);
173
173
  xhr.responseType = "blob";
174
174
  xhr.onload = () => {
175
175
  if (xhr.status === 200) {
@@ -205,7 +205,7 @@ export class FileStorage {
205
205
  let timeStamp = null;
206
206
  return new Promise((resolve) => {
207
207
  const xhr = new XMLHttpRequest();
208
- xhr.open("HEAD", uri, true);
208
+ xhr.open("HEAD", encodeURI(uri), true);
209
209
  xhr.responseType = "blob";
210
210
  xhr.onload = () => {
211
211
  if (xhr.status === 200) {
@@ -238,7 +238,7 @@ export class FileStorage {
238
238
  let size = 0;
239
239
  return new Promise((resolve) => {
240
240
  const xhr = new XMLHttpRequest();
241
- xhr.open("HEAD", uri, true);
241
+ xhr.open("HEAD", encodeURI(uri), true);
242
242
  xhr.responseType = "blob";
243
243
  xhr.onload = () => {
244
244
  if (xhr.status === 200) {