@preference-sl/pref-viewer 2.17.2-beta.1 → 2.18.0-beta.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/README.md CHANGED
@@ -521,6 +521,8 @@ Render settings are persisted in `localStorage` under the `pref-viewer/render-se
521
521
 
522
522
  The showroom daylight background uses a shared linear HDR color calibrated with exposure and ACES tone mapping for the current light studio gray target, `#d9d9d9`, in a scene-less view. Both the static look and time-of-day cycle use this same daylight value; the cycle retains its dark night endpoint. Scene geometry can cover the background. The internal `BabylonJSController.config.look.showroom.backgroundDay` value is not a public background-color option and must be recalibrated if tone mapping or exposure changes.
523
523
 
524
+ The model's transmissive glass (`KHR_materials_transmission`, as authored by the SDK) also carries a base color alpha of `0.15`, which would multiply its reflection away and leave it flat grey. The viewer sets that alpha to `1` and `metallicF0Factor` to `3` (`BabylonJSController.config.look.glass`, internal like the showroom look) so the environment reflection reads while the glass stays see-through through transmission. Glass in the environment glTF is unaffected: it is simplified to alpha blending instead.
525
+
524
526
  ## Environment map and scene lights
525
527
 
526
528
  `options.ibl.url` accepts two formats, chosen by the URL's extension (query and hash ignored):
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@preference-sl/pref-viewer",
3
- "version": "2.17.2-beta.1",
3
+ "version": "2.18.0-beta.0",
4
4
  "description": "Web Component to preview GLTF models with Babylon.js",
5
5
  "author": "Alex Moreno Palacio <amoreno@preference.es>",
6
6
  "scripts": {
@@ -216,6 +216,14 @@ export default class BabylonJSController {
216
216
  // Re-solve these if exposure, contrast or the tonemapping curve change.
217
217
  backgroundDay: [1.424, 1.424, 1.424],
218
218
  },
219
+ // The model's physical glass (KHR_materials_transmission). The SDK also authors it with a
220
+ // baseColor alpha of 0.15, which multiplies the reflection away; the viewer sets the alpha
221
+ // to 1 and raises the dielectric F0 (MaterialUtils.tunePhysicalGlassMaterial) so the
222
+ // environment reads on the glass while transmission keeps it see-through.
223
+ glass: {
224
+ alpha: 1,
225
+ metallicF0Factor: 3,
226
+ },
219
227
  },
220
228
  pointerPicking: {
221
229
  movePickIntervalMs: 50, // Cap expensive scene.pick calls to ~20 Hz while moving the pointer
@@ -2863,6 +2871,21 @@ export default class BabylonJSController {
2863
2871
  assetContainer.lights = [];
2864
2872
  }
2865
2873
 
2874
+ /**
2875
+ * Gives the model container's physical glass (KHR_materials_transmission) a visible reflection.
2876
+ * Model container only: environment glass is simplified instead (see
2877
+ * #assetContainer_simplifyTransmissiveMaterials), so it is never tuned here.
2878
+ * @private
2879
+ * @param {AssetContainer} assetContainer - Model container whose glass materials should be tuned.
2880
+ * @returns {void}
2881
+ */
2882
+ #assetContainer_tuneModelGlass(assetContainer) {
2883
+ const look = BabylonJSController.config.look.glass;
2884
+ assetContainer.materials?.forEach((mat) => {
2885
+ MaterialUtils.tunePhysicalGlassMaterial(mat, look);
2886
+ });
2887
+ }
2888
+
2866
2889
  /**
2867
2890
  * Strips KHR_materials_transmission, KHR_materials_ior and KHR_materials_volume from
2868
2891
  * environment-container (scene) materials, converting them to simple alpha blending.
@@ -3078,6 +3101,7 @@ export default class BabylonJSController {
3078
3101
  if (container.state.name === "model") {
3079
3102
  this.#assetContainer_deleteLights(assetContainer);
3080
3103
  this.#assetContainer_stopAnimations(assetContainer);
3104
+ this.#assetContainer_tuneModelGlass(assetContainer);
3081
3105
  newModelMetadata = { ...(container.state.update.metadata ?? {}) };
3082
3106
  }
3083
3107
  if (container.state.name === "model" || container.state.name === "environment") {
@@ -3396,7 +3420,8 @@ export default class BabylonJSController {
3396
3420
  getViewport: () => ({ width: this.#canvas.clientWidth, height: this.#canvas.clientHeight }),
3397
3421
  getCulture: this.#viewCubeConfig.getCulture,
3398
3422
  onLayout: this.#viewCubeConfig.onLayout,
3399
- requestRender: () => this.#requestRender({ frames: 2 }),
3423
+ // A cube drag is pointer interaction like a main-canvas drag: keep the loop continuous for the same window.
3424
+ requestRender: (options) => this.#requestRender({ frames: 2, continuousMs: options?.interaction ? BabylonJSController.config.render.interactionMs : 0 }),
3400
3425
  });
3401
3426
  }
3402
3427
 
@@ -139,7 +139,7 @@ export default class BabylonJSViewCubeController {
139
139
  * @param {function(import("@babylonjs/core").Camera|null|undefined): boolean} host.isLocked - Reports whether navigation is forbidden for the supplied camera, including unavailable cameras or active XR.
140
140
  * @param {function(): (ViewCubeBounds|null)} host.getBounds - Returns current model-only world bounds and their eight corners; null when geometry is unusable. Excludes the environment.
141
141
  * @param {function(): {width: number, height: number}} host.getViewport - Returns the current scene viewport dimensions in CSS pixels.
142
- * @param {function(): void} host.requestRender - Requests rendering through the host scheduler after accepted navigation.
142
+ * @param {function(Object=): void} host.requestRender - Requests rendering through the host scheduler after accepted navigation; `{ interaction: true }` marks a pointer drag step, for which the host keeps rendering continuously as it does for its own canvas drags.
143
143
  * @param {function(): string} [host.getCulture] - Returns the current localization culture; omitted callbacks use the translator's default culture.
144
144
  * @param {function(number, number): void} [host.onLayout] - Receives the measured cube viewport height and scene viewport height, in CSS pixels; zero cube height clears the menu offset, and disposal reports (0, 0).
145
145
  * @param {function(ViewCubeRendererOptions): BabylonJSViewCubeRenderer} [host.createRenderer] - Renderer factory, mainly for tests; defaults to a BabylonJSViewCubeRenderer with its own Engine.
@@ -581,7 +581,9 @@ export default class BabylonJSViewCubeController {
581
581
  const direction = directionFromAngles(applyDragDelta(angles, dAlpha, dBeta));
582
582
  this.#writePose(camera, pose.target.add(new Vector3(direction.x, direction.y, direction.z).scale(pose.distance)), pose.target, pose.distance);
583
583
  }
584
- this.#host.requestRender();
584
+ // A drag is pointer interaction: the host keeps its loop continuous for its interaction window, as it does for a
585
+ // main-canvas drag. A plain one-frame request would let its idle throttle pace the drag (seen at ~8 fps).
586
+ this.#host.requestRender({ interaction: true });
585
587
  }
586
588
 
587
589
  /**
@@ -47,6 +47,36 @@ export default class MaterialUtils {
47
47
  return Boolean(mat?.subSurface?.isRefractionEnabled || mat?.subSurface?.isTranslucencyEnabled);
48
48
  }
49
49
 
50
+ /**
51
+ * Gives the model's physical glass a visible reflection.
52
+ *
53
+ * The SDK authors window glass with KHR_materials_transmission AND a baseColor alpha of 0.15 in
54
+ * alpha-blend. Babylon's transmission extension turns on `transparencyAsCoverage` for the whole
55
+ * GLB, which makes `useSpecularOverAlpha` / `useRadianceOverAlpha` false, so the ~4 % Fresnel
56
+ * reflection is multiplied by that alpha and the glass reads as flat grey. Setting the alpha to
57
+ * 1, raising the dielectric F0 and re-enabling the over-alpha reflections lets the environment
58
+ * show up on the glass while transmission keeps it see-through.
59
+ *
60
+ * Only physical glass (see `isPrefViewerPhysicalGlassMaterial`) is touched; `transparencyMode`
61
+ * and `subSurface` are left as authored so the glass stays in the transparent pass.
62
+ * @public
63
+ * @static
64
+ * @param {import("@babylonjs/core").PBRMaterial|null|undefined} mat - Material to tune.
65
+ * @param {{ alpha?: number, metallicF0Factor?: number }} [look] - Glass look; defaults to alpha 1 and F0 factor 3.
66
+ * @returns {boolean} True when the material was physical glass and has been changed.
67
+ */
68
+ static tunePhysicalGlassMaterial(mat, look = {}) {
69
+ if (!MaterialUtils.isPrefViewerPhysicalGlassMaterial(mat)) {
70
+ return false;
71
+ }
72
+
73
+ mat.alpha = look?.alpha ?? 1;
74
+ mat.metallicF0Factor = look?.metallicF0Factor ?? 3;
75
+ mat.useSpecularOverAlpha = true;
76
+ mat.useRadianceOverAlpha = true;
77
+ return true;
78
+ }
79
+
50
80
  /**
51
81
  * Returns true when a material should be placed in the transparent rendering group (renderingGroupId=1).
52
82
  *