@preference-sl/pref-viewer 2.17.0-beta.3 → 2.17.0-beta.5
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 +59 -36
- package/package.json +1 -1
- package/src/babylonjs-controller.js +13 -6
- package/src/babylonjs-view-cube-controller.js +569 -213
- package/src/babylonjs-view-cube-renderer.js +507 -0
- package/src/styles.js +0 -88
- package/src/view-cube-orbit-math.js +199 -0
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
- Native custom elements: `<pref-viewer>`, `<pref-viewer-2d>`, `<pref-viewer-3d>`, `<pref-viewer-dialog>`, and `<pref-viewer-menu-3d>`.
|
|
8
8
|
- Babylon.js-based 3D visualization for glTF and GLB assets.
|
|
9
|
-
- Default-enabled ViewCube with 26 selectable orientations
|
|
9
|
+
- Default-enabled, draggable 3D ViewCube with 26 selectable orientations: click a face, edge or corner for a smooth, model-fitted view, or drag the cube to orbit the model. It follows the camera in real time and works with perspective and orthographic cameras.
|
|
10
10
|
- Model-only, geometry-dependent orbital zoom protection with near-plane sampling, independent of ViewCube visibility.
|
|
11
11
|
- Viewer dialogs above the render menu and ViewCube, with background pointer-input protection.
|
|
12
12
|
- Proportional mouse-wheel zoom for unlocked orbital cameras: increments decrease as the camera approaches its target, using Babylon's native input without an additional viewer zoom increment. Wheel sensitivity is currently an internal setting, not a public attribute or option.
|
|
@@ -88,8 +88,8 @@ viewer.setOptions({
|
|
|
88
88
|
intensity: 1,
|
|
89
89
|
shadows: true,
|
|
90
90
|
},
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
render: {
|
|
92
|
+
lightingTimeOfDay: 0.5,
|
|
93
93
|
},
|
|
94
94
|
});
|
|
95
95
|
```
|
|
@@ -239,13 +239,13 @@ Storage descriptors are passed through `model.storage`, `scene.storage`, `materi
|
|
|
239
239
|
|
|
240
240
|
## ViewCube
|
|
241
241
|
|
|
242
|
-
The ViewCube reflects the effective active camera orientation and offers **26 views: six faces, twelve edges and eight corners**. Click any region to change orientation smoothly and refit the model assetContainer. Every accepted click refits, even when selecting the current orientation: previous pan, framing and zoom are discarded. Environment geometry is excluded from this fit; only visible, enabled model meshes with valid geometry contribute to bounds. Hidden or disabled model geometry, including auxiliary walls/floors hidden by viewer options, does not enlarge the fit.
|
|
242
|
+
The ViewCube reflects the effective active camera orientation and offers **26 views: six faces, twelve edges and eight corners**. Click any region to change orientation smoothly and refit the model assetContainer, or drag the cube to orbit the model (see [Dragging the cube](#dragging-the-cube)). Every accepted click refits, even when selecting the current orientation: previous pan, framing and zoom are discarded. Environment geometry is excluded from this fit; only visible, enabled model meshes with valid geometry contribute to bounds. Hidden or disabled model geometry, including auxiliary walls/floors hidden by viewer options, does not enlarge the fit.
|
|
243
243
|
|
|
244
|
-
The active camera retains its identity and perspective or orthographic projection. Navigation supports Babylon ArcRotateCamera, FreeCamera and UniversalCamera, including supported parent transforms. Other camera classes, locked cameras and active XR tracked cameras are display-only. Selection does nothing when usable model bounds, a supported camera or positive viewport dimensions are unavailable.
|
|
244
|
+
The active camera retains its identity and perspective or orthographic projection. Navigation supports Babylon ArcRotateCamera, FreeCamera and UniversalCamera, including supported parent transforms. Other camera classes, locked cameras and active XR tracked cameras are display-only: the cube keeps following the camera, but hover, click and drag do nothing. Selection does nothing when usable model bounds, a supported camera or positive viewport dimensions are unavailable.
|
|
245
245
|
|
|
246
246
|
### Orientation and feedback
|
|
247
247
|
|
|
248
|
-
The inner view is the principal model view. English ViewCube labels
|
|
248
|
+
The inner view is the principal model view. English ViewCube face labels read `Inner` and `Outer`; Spanish labels are `Interior` and `Exterior`. Labels are drawn on the cube faces exactly as translated and follow culture changes. Face names use this world-axis convention:
|
|
249
249
|
|
|
250
250
|
| Direction | World axis | Reference |
|
|
251
251
|
| --- | --- | --- |
|
|
@@ -256,17 +256,37 @@ The inner view is the principal model view. English ViewCube labels use `Inner`
|
|
|
256
256
|
| Top / Superior | +Y | Looks down toward the model. |
|
|
257
257
|
| Bottom / Inferior | -Y | Looks up toward the model. |
|
|
258
258
|
|
|
259
|
-
The cube
|
|
259
|
+
The cube is drawn on its own small canvas, with a separate Babylon.js engine and virtual scene, in a PrefSketch-style look: six square labelled faces, thin bars on the twelve edges and small spheres on the eight corners; there are no chamfers. Every part of an edge or corner selects the same orientation. The cube is always drawn with an orthographic camera, whatever the projection or FOV of the viewer camera, and it follows only the direction of the camera, independent of model zoom. It lives in its own scene, so it adds nothing to the model scene, to model picking or to exports.
|
|
260
|
+
|
|
261
|
+
Hover paints the region under the pointer with `styles.colorPrimary` (`--pref-viewer-color-primary`). Any CSS colour syntax is accepted: hex, `rgb()`, `hsl()` or a named colour. The angularly nearest of the 26 views is shown as the current region, painted with the primary colour mixed 25% into the face fill; hover takes precedence until the pointer leaves. A primary-colour change is picked up within 250 ms, or immediately after a resize, a culture change or re-enabling the cube. The rest of the palette (face fill, borders, label text, edge bars and corner spheres) is a fixed light palette and is not configurable. There are no region tooltips.
|
|
262
|
+
|
|
263
|
+
Edges and corners are thin, so selection has a tolerance: a front-facing edge or corner whose centre is within 8 CSS pixels of the pointer is picked ahead of the face under it, corners before edges. On cubes smaller than 96 px the tolerance shrinks to a twelfth of the cube side so face centres stay selectable. Hover and click use the same pick, so the highlighted region is the one a click selects.
|
|
264
|
+
|
|
265
|
+
### Dragging the cube
|
|
266
|
+
|
|
267
|
+
Press on the cube and move the pointer more than 3 CSS pixels to drag it. Dragging orbits the viewer camera around its target at 0.012 radians per pixel, in the same direction as dragging the model with the mouse on the main canvas: the model follows the pointer, and the cube follows the camera. Elevation stops just short of the poles and the camera keeps world +Y as up. Dragging works with ArcRotateCamera, FreeCamera and UniversalCamera; authored alpha/beta limits of an ArcRotateCamera keep being enforced by Babylon on the next frame.
|
|
260
268
|
|
|
261
|
-
|
|
269
|
+
The whole cube canvas is the drag surface, including its transparent corners, and a press on it never starts a gesture on the main camera. A press that moves 3 pixels or less is a click. A drag never selects a region, even if it ends where it started, and it cancels a running click transition. Locked cameras, active XR tracked cameras and unsupported camera classes keep the cube display-only. The cursor is `grab` over the cube, `pointer` over a selectable region and `grabbing` while dragging.
|
|
262
270
|
|
|
263
|
-
|
|
271
|
+
### ViewCube accessibility
|
|
272
|
+
|
|
273
|
+
The cube canvas has `role="img"` and one localized accessible name (`View orientation` in English, `Orientación de vista` in Spanish). Individual regions have no accessible names. The cube is pointer-driven: the canvas is not a tab stop, does not take keyboard focus after pointer use and draws no focus ring. Keyboard operation of the cube is not provided.
|
|
264
274
|
|
|
265
275
|
### ViewCube layout and lifecycle
|
|
266
276
|
|
|
267
|
-
The cube
|
|
277
|
+
The cube is a square at the top right of the 3D view: **top 0px**, **right 0px** unless the host sets the inset below. Its side, in CSS pixels, is `min(clamp(22% of min(viewer width, viewer height), 96, 180), 40% of min(viewer width, viewer height))`, rounded to an integer. For example, a viewer whose smaller side is 300 px gets a 96 px cube, 600 px gets 132 px, 900 px or more gets the 180 px maximum, and a 200 px viewer gets 80 px (the 40% cap). A viewer without a usable size shows no cube.
|
|
278
|
+
|
|
279
|
+
Hosts can inset the cube from the right edge with the CSS custom property `--pref-viewer-view-cube-inset-right` (default `0px`). Set it on `<pref-viewer>` or on any ancestor; it inherits into the viewer:
|
|
280
|
+
|
|
281
|
+
```css
|
|
282
|
+
pref-viewer {
|
|
283
|
+
--pref-viewer-view-cube-inset-right: 24px;
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
When both overlays are enabled, the render-menu top equals the **measured side of the cube canvas** and updates when that size changes; the menu offset is measured, not a fixed value. Without the cube, the menu returns to its style-defined default top. The cube remains below the menu's layer, and viewer modals cover both. The internal `view-cube-layout` event carries `{ offset, height }` in CSS pixels: `offset` is the measured cube side (0 when there is no cube) and `height` is the scene viewport height.
|
|
268
288
|
|
|
269
|
-
Cube resources are created only while enabled in a visible 3D view. Disabling it or switching to 2D releases its overlay, listeners, observers and
|
|
289
|
+
Cube resources are created only while enabled in a visible 3D view. Disabling it or switching to 2D releases its overlay, listeners, observers, pending transition, engine and WebGL context. An active cube uses a second WebGL context next to the viewer's; it is repainted after a context restore and after a device pixel ratio change. Reactivation uses the current camera without reloading assets. Layout subscriptions connect before activation and are removed when inactive or disconnected.
|
|
270
290
|
|
|
271
291
|
Rapid selections retarget the transition from the displayed pose. Canvas pointer/wheel/key interaction, resize, projection change, camera/model replacement, locking, disabling or disposal cancels pending navigation; unlocking/reactivation does not replay it. Transitions use the existing demand-rendering scheduler and release their activity when finished without stopping unrelated model animations.
|
|
272
292
|
|
|
@@ -449,7 +469,7 @@ The component emits custom events so host applications can integrate loading ind
|
|
|
449
469
|
|
|
450
470
|
### Internal Listeners
|
|
451
471
|
|
|
452
|
-
`<pref-viewer>` listens to `pref-viewer-2d-viewport-changed` from `<pref-viewer-2d>`, `pref-viewer-3d-loaded` and `pref-viewer-3d-error` from `<pref-viewer-3d>`, and `pref-viewer-3d-render-settings-change-requested` from `<pref-viewer-menu-3d>`. Internal `pref-viewer-2d-element-click` and `pref-viewer-3d-element-click` events are intercepted and forwarded through the single public `pref-viewer-element-click` contract. `BabylonJSController` listens to `pref-viewer-3d-animation-changed` from the nearest `<pref-viewer-3d>` host. The root also conditionally subscribes to the internal, non-bubbling `view-cube-layout` event while the cube is active in 3D. It carries measured
|
|
472
|
+
`<pref-viewer>` listens to `pref-viewer-2d-viewport-changed` from `<pref-viewer-2d>`, `pref-viewer-3d-loaded` and `pref-viewer-3d-error` from `<pref-viewer-3d>`, and `pref-viewer-3d-render-settings-change-requested` from `<pref-viewer-menu-3d>`. Internal `pref-viewer-2d-element-click` and `pref-viewer-3d-element-click` events are intercepted and forwarded through the single public `pref-viewer-element-click` contract. `BabylonJSController` listens to `pref-viewer-3d-animation-changed` from the nearest `<pref-viewer-3d>` host. The root also conditionally subscribes to the internal, non-bubbling `view-cube-layout` event while the cube is active in 3D. It carries `{ offset, height }` in CSS pixels, where `offset` is the measured side of the square cube and `height` is the scene viewport height, so the render menu can sit below the cube; it is not a new public root event.
|
|
453
473
|
|
|
454
474
|
Example:
|
|
455
475
|
|
|
@@ -501,6 +521,23 @@ Render settings are persisted in `localStorage` under the `pref-viewer/render-se
|
|
|
501
521
|
|
|
502
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.
|
|
503
523
|
|
|
524
|
+
## Environment map and scene lights
|
|
525
|
+
|
|
526
|
+
`options.ibl.url` accepts two formats, chosen by the URL's extension (query and hash ignored):
|
|
527
|
+
|
|
528
|
+
| Extension | Loaded as | Notes |
|
|
529
|
+
| --- | --- | --- |
|
|
530
|
+
| `.env` | Prefiltered Babylon environment (`CubeTexture.CreateFromPrefilteredData`) | No prefiltering in the browser; a 4K environment is typically under 1 MB. |
|
|
531
|
+
| anything else | Radiance HDR (`HDRCubeTexture`) | Prefiltered on load, which costs time and memory for large files. |
|
|
532
|
+
|
|
533
|
+
Either file is downloaded once, cached in IndexedDB, and reused across reloads.
|
|
534
|
+
|
|
535
|
+
Directional and spot lights that come with the scene glTF (`KHR_lights_punctual`) cast shadows when `render.shadowsEnabled` is `true` and `ibl.shadows` is off, alongside the built-in light's. Every scene and model mesh casts unless its node sets `extras.castShadows: false`, and receives unless it sets `extras.receiveShadows: false`. A light's shadow darkness comes from its node's `extras.shadowDarkness`, from `0` (black) to `1` (no shadow), and is `0.5` when absent:
|
|
536
|
+
|
|
537
|
+
```json
|
|
538
|
+
{ "name": "Sun", "rotation": [-0.5, 0, 0, 0.866], "extras": { "shadowDarkness": 0.15 }, "extensions": { "KHR_lights_punctual": { "light": 0 } } }
|
|
539
|
+
```
|
|
540
|
+
|
|
504
541
|
## Runtime styles
|
|
505
542
|
|
|
506
543
|
Runtime styles can be passed through the `styles` attribute, the `styles` property setter, `setStyles(styles)`, or `loadConfig({ styles })`.
|
|
@@ -515,7 +552,7 @@ viewer.setStyles({
|
|
|
515
552
|
});
|
|
516
553
|
```
|
|
517
554
|
|
|
518
|
-
The ViewCube uses this same primary color for its hover and
|
|
555
|
+
The ViewCube uses this same primary color for its hover feedback and, mixed into the face fill, for its current-orientation feedback. Changing `colorPrimary` through `styles` or `config` attributes, `setStyles`, or `loadConfig({ styles })` also updates animation-opening highlight color, including an opening currently highlighted, without reloading the model or changing whether highlighting is enabled. The render menu color control stays synchronized. Persisted primary styles are applied to highlights when the viewer connects. `options.render.highlightColor` can still set an explicit highlight color; a later primary-style update replaces it.
|
|
519
556
|
|
|
520
557
|
Only `colorPrimary` is currently supported. The value updates `PrefViewerStyleVariables.colorPrimary`, is exposed on the host as `--pref-viewer-color-primary`, and is persisted in `localStorage` under `pref-viewer/styles`. Persisted styles are restored when a new `<pref-viewer>` instance is created and connected.
|
|
521
558
|
|
|
@@ -570,38 +607,24 @@ Focused regressions for this work live in `tests/babylonjs-selection-controller.
|
|
|
570
607
|
|
|
571
608
|
### Camera implementation and maintenance
|
|
572
609
|
|
|
573
|
-
- `src/babylonjs-view-cube-controller.js`: dedicated `BabylonJSViewCubeController` for
|
|
610
|
+
- `src/babylonjs-view-cube-controller.js`: dedicated `BabylonJSViewCubeController` for pointer interaction (hover, click, drag), camera reading and writing, click transitions, size, colours and cleanup. It delegates model bounds and destination-fit calculations to BabylonJSCameraFraming and the drawing to the renderer. Cube-only helpers and constants remain private; region generation remains a public static utility. Its constructor JSDoc documents the host object and callbacks.
|
|
611
|
+
- `src/babylonjs-view-cube-renderer.js`: `BabylonJSViewCubeRenderer`, the cube's own Babylon.js engine and virtual scene with its 26 region meshes, picking and painting. It owns no render loop and no interaction logic; the controller renders it from the host loop.
|
|
612
|
+
- `src/view-cube-orbit-math.js`: pure helpers for orbit angles, the 26 view directions, drag deltas and the cube size rule, without Babylon or DOM dependencies.
|
|
574
613
|
- `src/babylonjs-camera-framing.js`: stateless `BabylonJSCameraFraming` with static `getModelBounds`, `calculateCameraFit` and `isCameraSupported` utilities. Bounds use only visible, enabled geometry in the supplied model container; fit calculations preserve camera state and projection, use the shared camera margin and return a destination for the caller to apply. Default-camera automatic fitting uses these same utilities, preserving the current orientation and applying the destination immediately.
|
|
575
614
|
- `src/babylonjs-camera-zoom-controller.js`: independent `BabylonJSCameraZoomController` for model-only dynamic radius protection and authored-floor restoration. It works without cube resources.
|
|
576
615
|
- `src/babylonjs-camera-wheel-motion.js`: internal boundary for inspecting and cancelling the coupled native wheel inertia during rendering, geometry protection and camera lifecycle changes. Babylon computes the zoom; this boundary isolates version-sensitive native input state.
|
|
577
616
|
- `src/babylonjs-controller.js`: owns the scene, active camera, containers, native wheel settings and render scheduler; coordinates both controllers.
|
|
578
|
-
- `src/styles.js`: exports `PrefViewerViewCubeStyles`, imported by the cube controller. The SVG stylesheet uses multiline CSS and scoped variables for the main visual properties; no JSDoc is required for this styles constant.
|
|
579
617
|
- `src/pref-viewer-3d.js` and `src/pref-viewer.js`: bridge lazy visibility, queued config, localization and measured menu layout. The root stores the layout callback in `#handlers` and removes its listener during teardown. Shared styles place dialogs above viewer overlays.
|
|
580
618
|
|
|
581
|
-
ViewCube class members are ordered as properties, constructor, static methods, private methods and public methods/getters. New classes and new/modified methods carry JSDoc describing their parameters, return values and current lifecycle/side effects. JavaScript `if` and `for` bodies always use braces, including single-statement bodies. Focused tests live in `tests/babylonjs-camera-framing.test.js`, `tests/babylonjs-view-cube-controller.test.js`, `tests/babylonjs-camera-zoom-controller.test.js`, `tests/babylonjs-controller-wheel.test.js` and `tests/pref-viewer.test.js`. Browser checks in the existing playground remain necessary for
|
|
619
|
+
ViewCube class members are ordered as properties, constructor, static methods, private methods and public methods/getters. New classes and new/modified methods carry JSDoc describing their parameters, return values and current lifecycle/side effects. JavaScript `if` and `for` bodies always use braces, including single-statement bodies. Focused tests live in `tests/babylonjs-camera-framing.test.js`, `tests/babylonjs-view-cube-controller.test.js`, `tests/babylonjs-view-cube-renderer.test.js`, `tests/view-cube-orbit-math.test.js`, `tests/babylonjs-camera-zoom-controller.test.js`, `tests/babylonjs-controller-wheel.test.js` and `tests/pref-viewer.test.js`. Browser checks in the existing playground remain necessary for cube rendering, hover regions, dragging, focus and cursor behavior, and modal stacking, because the tests run on a null engine.
|
|
582
620
|
|
|
583
|
-
### ViewCube
|
|
621
|
+
### ViewCube rendering maintenance
|
|
584
622
|
|
|
585
|
-
The
|
|
623
|
+
The cube's visual constants (the light palette, face label font and size, edge and corner sizes, lighting) are internal to `src/babylonjs-view-cube-renderer.js`. They are not properties supported by `setStyles` or `config.styles`; only `colorPrimary` reaches the cube, through the hover and current colours. The renderer module also contains a dark palette constant; it is not exported from the package and is not part of the public API.
|
|
586
624
|
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
| `--cube-border-color` | `#78838f` |
|
|
591
|
-
| `--cube-border-width` | `1.0px` in the SVG coordinate system; also used by the hover outline |
|
|
592
|
-
| `--cube-hover-color` | Shared primary color; used by the fill and opaque outline |
|
|
593
|
-
| `--cube-hover-opacity` | `0.50` fill opacity |
|
|
594
|
-
| `--cube-active-color` | Shared primary color |
|
|
595
|
-
| `--cube-active-opacity` | `0.15` fill opacity |
|
|
596
|
-
| `--cube-text-font-family` | `Arial, sans-serif` |
|
|
597
|
-
| `--cube-text-font-size` | `9px` |
|
|
598
|
-
| `--cube-text-color` | `#29323b` |
|
|
599
|
-
| `--cube-text-font-weight` | `600` |
|
|
600
|
-
| `--cube-text-letter-spacing` | `1.0px` |
|
|
601
|
-
|
|
602
|
-
Both feedback colors default to `var(--pref-viewer-color-primary, ...)`, preserving supported runtime primary-color updates. Text size and spacing apply in the SVG coordinate system and scale with its viewport. Active-view borders remain transparent; hover borders remain fully opaque regardless of fill opacity. Geometry and input behavior remain owned by the controller.
|
|
603
|
-
|
|
604
|
-
ViewCube listener registration and hover updates are private instance methods. Surface creation, region construction, hit-region lookup, extent interpolation and SVG projection are private static helpers; per-update projection values and interpolation progress are passed explicitly. The render menu also encapsulates hue-channel calculation and lighting playback as private methods. Playback uses one callback bound to the menu instance and cancels its scheduled frame on stop or disconnection.
|
|
625
|
+
Keep these rules when changing the renderer: the cube scene stays virtual and its engine stays out of `EngineStore.Instances` while it is alive (otherwise the viewer can create resources on the cube's WebGL context); Babylon input stays detached from the cube canvas (otherwise the cursor and keyboard focus are disturbed); and the engine keeps `loseContextOnDispose` so its WebGL context is released.
|
|
626
|
+
|
|
627
|
+
ViewCube listener registration, drag handling and hover updates are private instance methods. Region construction, colour parsing and extent interpolation are private static helpers; interpolation progress is passed explicitly. The render menu also encapsulates hue-channel calculation and lighting playback as private methods. Playback uses one callback bound to the menu instance and cancels its scheduled frame on stop or disconnection.
|
|
605
628
|
|
|
606
629
|
## Package scripts
|
|
607
630
|
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ArcRotateCamera, AssetContainer, BRDFTextureTools, Camera, Color3, Color4, DefaultRenderingPipeline, DirectionalLight, Engine, FreeCamera, HDRCubeTexture, HemisphericLight, IblShadowsRenderPipeline, ImageProcessingConfiguration, LoadAssetContainerAsync, Material, Matrix, MeshBuilder, PBRMaterial, PointerEventTypes, PointLight, RenderTargetTexture, Scene, ShadowGenerator, SpotLight, SSAORenderingPipeline, Texture, Tools, UniversalCamera, Vector3, WebXRDefaultExperience, WebXRFeatureName, WebXRSessionManager, WebXRState, WhenTextureReadyAsync } from "@babylonjs/core";
|
|
1
|
+
import { ArcRotateCamera, AssetContainer, BRDFTextureTools, Camera, Color3, Color4, CubeTexture, DefaultRenderingPipeline, DirectionalLight, Engine, FreeCamera, HDRCubeTexture, HemisphericLight, IblShadowsRenderPipeline, ImageProcessingConfiguration, LoadAssetContainerAsync, Material, Matrix, MeshBuilder, PBRMaterial, PointerEventTypes, PointLight, RenderTargetTexture, Scene, ShadowGenerator, SpotLight, SSAORenderingPipeline, Texture, Tools, UniversalCamera, Vector3, WebXRDefaultExperience, WebXRFeatureName, WebXRSessionManager, WebXRState, WhenTextureReadyAsync } from "@babylonjs/core";
|
|
2
2
|
import { DracoCompression } from "@babylonjs/core/Meshes/Compression/dracoCompression.js";
|
|
3
3
|
import "@babylonjs/loaders";
|
|
4
4
|
import "@babylonjs/loaders/glTF/2.0/Extensions/KHR_draco_mesh_compression.js";
|
|
@@ -1334,7 +1334,7 @@ export default class BabylonJSController {
|
|
|
1334
1334
|
* @returns {Promise<boolean>} Returns true if the environment texture was changed, false if it was already up to date or failed to load.
|
|
1335
1335
|
* @description
|
|
1336
1336
|
* Lifecycle implemented here:
|
|
1337
|
-
* 1. If `options.ibl.cachedUrl` exists, create `HDRCubeTexture` from it.
|
|
1337
|
+
* 1. If `options.ibl.cachedUrl` exists, create `HDRCubeTexture` from it (a prefiltered `CubeTexture` when `options.ibl.url` is a `.env`).
|
|
1338
1338
|
* 2. Wait for readiness, clone it into `#hdrTexture` for reuse.
|
|
1339
1339
|
* 3. Call `options.ibl.consumeCachedUrl(true)` to revoke temporary object URLs and clear `cachedUrl`.
|
|
1340
1340
|
* 4. On following reloads, if `options.ibl.valid === true` and no `cachedUrl` is present, use `#hdrTexture.clone()`.
|
|
@@ -1348,8 +1348,13 @@ export default class BabylonJSController {
|
|
|
1348
1348
|
let hdrTexture = null;
|
|
1349
1349
|
if (this.#options.ibl?.cachedUrl) {
|
|
1350
1350
|
const hdrTextureURI = this.#options.ibl.cachedUrl;
|
|
1351
|
-
|
|
1352
|
-
|
|
1351
|
+
if (/\.env$/i.test(String(this.#options.ibl.url ?? "").split(/[?#]/)[0])) {
|
|
1352
|
+
// The cached file is a blob: URL with no extension, so the loader is told it is a .env.
|
|
1353
|
+
hdrTexture = CubeTexture.CreateFromPrefilteredData(hdrTextureURI, this.#scene, ".env");
|
|
1354
|
+
} else {
|
|
1355
|
+
const envTextureSize = BabylonJSController.config.quality.environmentTextureSize || 1024;
|
|
1356
|
+
hdrTexture = new HDRCubeTexture(hdrTextureURI, this.#scene, envTextureSize, false, false, false, true, undefined, undefined, false, true, true);
|
|
1357
|
+
}
|
|
1353
1358
|
} else if (this.#hdrTexture && this.#options.ibl?.valid === true) {
|
|
1354
1359
|
hdrTexture = this.#hdrTexture.clone();
|
|
1355
1360
|
} else {
|
|
@@ -1586,7 +1591,7 @@ export default class BabylonJSController {
|
|
|
1586
1591
|
return generator.getLight()?.name === "PrefViewerDirLight";
|
|
1587
1592
|
});
|
|
1588
1593
|
|
|
1589
|
-
this.#containers.environment?.
|
|
1594
|
+
this.#containers.environment?.assetContainer?.lights.forEach((light) => {
|
|
1590
1595
|
// Only shadows for DirectionalLight and SpotLight types
|
|
1591
1596
|
if (!(light instanceof DirectionalLight || light instanceof SpotLight)) {
|
|
1592
1597
|
return;
|
|
@@ -1595,7 +1600,9 @@ export default class BabylonJSController {
|
|
|
1595
1600
|
const shadowGenerator = new ShadowGenerator(1024, light);
|
|
1596
1601
|
shadowGenerator.useBlurExponentialShadowMap = true;
|
|
1597
1602
|
shadowGenerator.blurKernel = 16;
|
|
1598
|
-
|
|
1603
|
+
// KHR_lights_punctual parents the light to its glTF node, which carries the node's extras.
|
|
1604
|
+
const extrasShadowDarkness = light.parent?.metadata?.gltf?.extras?.shadowDarkness;
|
|
1605
|
+
shadowGenerator.darkness = typeof extrasShadowDarkness === "number" && Number.isFinite(extrasShadowDarkness) ? Math.min(Math.max(extrasShadowDarkness, 0), 1) : 0.5;
|
|
1599
1606
|
shadowGenerator.bias = 0.0005;
|
|
1600
1607
|
shadowGenerator.normalBias = 0.02;
|
|
1601
1608
|
shadowGenerator.getShadowMap().refreshRate = RenderTargetTexture.REFRESHRATE_RENDER_ONCE;
|