@preference-sl/pref-viewer 2.16.0-beta.1 → 2.16.0-beta.11
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/LICENSE.md +13 -0
- package/README.md +486 -0
- package/package.json +7 -7
- package/src/babylonjs-animation-opening.js +11 -5
- package/src/babylonjs-controller.js +455 -903
- package/src/file-storage.js +5 -126
- package/src/gltf-resolver.js +24 -58
- package/src/localization/translations.js +5 -17
- package/src/material-utils.js +72 -0
- package/src/pref-viewer-2d.js +14 -21
- package/src/pref-viewer-3d.js +160 -193
- package/src/pref-viewer-menu-3d.js +185 -268
- package/src/pref-viewer-task.js +7 -2
- package/src/pref-viewer.js +549 -333
- package/src/render-math.js +127 -0
- package/src/styles.js +163 -179
- package/Readme.md +0 -8
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure math utilities used by the lighting cycle and hardware scaling logic.
|
|
3
|
+
* No Babylon.js imports — safe to use in Node/SSR environments and in tests without mocks.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Clamps a number to the [0, 1] range.
|
|
8
|
+
* Returns 0.5 for non-finite inputs (NaN, ±Infinity) so callers get a safe mid-point fallback.
|
|
9
|
+
* @param {number} value - The value to clamp.
|
|
10
|
+
* @returns {number} A number in [0, 1].
|
|
11
|
+
*/
|
|
12
|
+
export function clamp01(value) {
|
|
13
|
+
if (!Number.isFinite(value)) {
|
|
14
|
+
return 0.5;
|
|
15
|
+
}
|
|
16
|
+
return Math.min(1, Math.max(0, value));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Linearly interpolates between two values.
|
|
21
|
+
* The interpolation amount is clamped to [0, 1] before use.
|
|
22
|
+
* @param {number} from - Start value (returned when amount ≤ 0).
|
|
23
|
+
* @param {number} to - End value (returned when amount ≥ 1).
|
|
24
|
+
* @param {number} amount - Blend factor in [0, 1].
|
|
25
|
+
* @returns {number} Interpolated value between `from` and `to`.
|
|
26
|
+
*/
|
|
27
|
+
export function lerp(from, to, amount) {
|
|
28
|
+
const t = clamp01(amount);
|
|
29
|
+
return from + (to - from) * t;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Evaluates a bell-curve (half sine arc) over [0, 1].
|
|
34
|
+
* Returns 0 at both endpoints and 1 at the midpoint (x = 0.5).
|
|
35
|
+
* Used to model the intensity rise and fall of sunlight across the day.
|
|
36
|
+
* @param {number} x - Input in [0, 1]; clamped internally.
|
|
37
|
+
* @returns {number} Bell-curve output in [0, 1].
|
|
38
|
+
*/
|
|
39
|
+
function bellCurve(x) {
|
|
40
|
+
const clamped = clamp01(x);
|
|
41
|
+
return Math.sin(clamped * Math.PI);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Returns a unit vector for the given (x, y, z) direction.
|
|
46
|
+
* Falls back to the original vector with length 1 when the input is the zero vector.
|
|
47
|
+
* @param {number} x
|
|
48
|
+
* @param {number} y
|
|
49
|
+
* @param {number} z
|
|
50
|
+
* @returns {{x: number, y: number, z: number}} Normalized direction vector.
|
|
51
|
+
*/
|
|
52
|
+
function normalizeDirection(x, y, z) {
|
|
53
|
+
const length = Math.hypot(x, y, z) || 1;
|
|
54
|
+
return {
|
|
55
|
+
x: x / length,
|
|
56
|
+
y: y / length,
|
|
57
|
+
z: z / length,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Computes the Babylon.js `hardwareScalingLevel` needed to render at the requested base
|
|
63
|
+
* resolution on a HiDPI display.
|
|
64
|
+
*
|
|
65
|
+
* Babylon's hardware scaling is the inverse of the device pixel ratio: a level of 0.5 on a
|
|
66
|
+
* 2× display renders at native resolution. This helper applies the base scaling factor (which
|
|
67
|
+
* may already downscale for performance on low-end hardware) on top of the device pixel ratio.
|
|
68
|
+
*
|
|
69
|
+
* Both inputs are validated and fall back to 1 when zero, negative, or non-finite.
|
|
70
|
+
* @param {number} [baseScaling=1] - Desired base scaling level (1 = full resolution, >1 = downscaled).
|
|
71
|
+
* @param {number} [pixelRatio=1] - Device pixel ratio (`window.devicePixelRatio`).
|
|
72
|
+
* @returns {number} Hardware scaling level to pass to `engine.setHardwareScalingLevel()`.
|
|
73
|
+
*/
|
|
74
|
+
export function getAdaptiveHardwareScalingLevel(baseScaling = 1, pixelRatio = 1) {
|
|
75
|
+
const safeBaseScaling = Number.isFinite(baseScaling) && baseScaling > 0 ? baseScaling : 1;
|
|
76
|
+
const safePixelRatio = Number.isFinite(pixelRatio) && pixelRatio > 0 ? pixelRatio : 1;
|
|
77
|
+
return safeBaseScaling / safePixelRatio;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Computes a lighting profile for a given time of day, used to drive the scene's directional
|
|
82
|
+
* lights, environment intensity, and tonemapping curve.
|
|
83
|
+
*
|
|
84
|
+
* The model follows a simplified solar arc: sunrise at 06:15 and sunset at 20:15 (fractional
|
|
85
|
+
* hours). Day factor peaks at solar noon and falls to zero outside daylight hours. Sun and moon
|
|
86
|
+
* directions are antipodal unit vectors derived from the sun phase angle.
|
|
87
|
+
* @param {number} [timeOfDay=0.5] - Normalized time in [0, 1] where 0 = midnight and 1 = next midnight.
|
|
88
|
+
* Values outside [0, 1] are clamped.
|
|
89
|
+
* @returns {{
|
|
90
|
+
* timeOfDay: number,
|
|
91
|
+
* timeHours: number,
|
|
92
|
+
* sunPhase: number,
|
|
93
|
+
* solarAzimuth: number,
|
|
94
|
+
* solarElevation: number,
|
|
95
|
+
* dayFactor: number,
|
|
96
|
+
* nightFactor: number,
|
|
97
|
+
* sunDirection: {x: number, y: number, z: number},
|
|
98
|
+
* moonDirection: {x: number, y: number, z: number}
|
|
99
|
+
* }} Lighting profile snapshot for the requested time.
|
|
100
|
+
*/
|
|
101
|
+
export function getLightingCycleProfile(timeOfDay = 0.5) {
|
|
102
|
+
const normalizedTime = clamp01(timeOfDay);
|
|
103
|
+
const timeHours = normalizedTime * 24;
|
|
104
|
+
const sunriseHour = 6.25;
|
|
105
|
+
const sunsetHour = 20.25;
|
|
106
|
+
const daylightProgress = clamp01((timeHours - sunriseHour) / (sunsetHour - sunriseHour));
|
|
107
|
+
const dayFactor = timeHours >= sunriseHour && timeHours <= sunsetHour ? Math.pow(bellCurve(daylightProgress), 0.88) : 0;
|
|
108
|
+
const nightFactor = 1 - dayFactor;
|
|
109
|
+
const solarArc = dayFactor > 0 ? Math.pow(dayFactor, 0.72) : 0;
|
|
110
|
+
const solarAzimuth = lerp(-Math.PI * 0.82, Math.PI * 0.82, daylightProgress);
|
|
111
|
+
const solarElevation = lerp(-0.18, 1.18, solarArc);
|
|
112
|
+
const sunPhase = normalizedTime * Math.PI * 2 - Math.PI / 2;
|
|
113
|
+
const sunDirection = normalizeDirection(-Math.cos(sunPhase), -Math.sin(sunPhase), -0.35);
|
|
114
|
+
const moonDirection = normalizeDirection(-sunDirection.x, -sunDirection.y, -sunDirection.z);
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
timeOfDay: normalizedTime,
|
|
118
|
+
timeHours,
|
|
119
|
+
sunPhase,
|
|
120
|
+
solarAzimuth,
|
|
121
|
+
solarElevation,
|
|
122
|
+
dayFactor,
|
|
123
|
+
nightFactor,
|
|
124
|
+
sunDirection,
|
|
125
|
+
moonDirection,
|
|
126
|
+
};
|
|
127
|
+
}
|