@woosh/meep-engine 2.165.7 → 2.167.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/build/bundle-worker-image-decoder.js +1 -1
- package/package.json +1 -1
- package/src/CORRECTNESS_HUNT_2026_07_24.md +142 -0
- package/src/core/binary/BinaryBuffer.js +1 -1
- package/src/core/binary/EncodingBinaryBuffer.d.ts.map +1 -1
- package/src/core/binary/EncodingBinaryBuffer.js +3 -1
- package/src/core/cache/Cache.d.ts.map +1 -1
- package/src/core/cache/Cache.js +0 -4
- package/src/core/cache/CacheElement.d.ts.map +1 -1
- package/src/core/cache/CacheElement.js +4 -0
- package/src/core/cache/FrequencySketch.d.ts +0 -21
- package/src/core/cache/FrequencySketch.d.ts.map +1 -1
- package/src/core/cache/FrequencySketch.js +66 -65
- package/src/core/cache/wtinylfu/CacheElementWTinylfu.d.ts +17 -0
- package/src/core/cache/wtinylfu/CacheElementWTinylfu.d.ts.map +1 -0
- package/src/core/cache/wtinylfu/CacheElementWTinylfu.js +18 -0
- package/src/core/cache/wtinylfu/CacheRegionType.d.ts +10 -0
- package/src/core/cache/wtinylfu/CacheRegionType.d.ts.map +1 -0
- package/src/core/cache/wtinylfu/CacheRegionType.js +10 -0
- package/src/core/cache/wtinylfu/CacheRegionWTinylfu.d.ts +66 -0
- package/src/core/cache/wtinylfu/CacheRegionWTinylfu.d.ts.map +1 -0
- package/src/core/cache/wtinylfu/CacheRegionWTinylfu.js +183 -0
- package/src/core/cache/wtinylfu/CacheWTinylfu.d.ts +279 -0
- package/src/core/cache/wtinylfu/CacheWTinylfu.d.ts.map +1 -0
- package/src/core/cache/wtinylfu/CacheWTinylfu.js +807 -0
- package/src/core/cache/wtinylfu/benchmark/CacheWTinylfu.bench.md +243 -0
- package/src/core/cache/wtinylfu/wtinylfuDecisions.d.ts +80 -0
- package/src/core/cache/wtinylfu/wtinylfuDecisions.d.ts.map +1 -0
- package/src/core/cache/wtinylfu/wtinylfuDecisions.js +102 -0
- package/src/core/collection/RingBuffer.d.ts.map +1 -1
- package/src/core/collection/RingBuffer.js +15 -3
- package/src/core/collection/map/HashMap.d.ts +1 -1
- package/src/core/collection/map/HashMap.d.ts.map +1 -1
- package/src/core/collection/map/HashMap.js +5 -17
- package/src/core/geom/2d/line/line2_compute_segment_point_distance_sqr.d.ts.map +1 -1
- package/src/core/geom/2d/line/line2_compute_segment_point_distance_sqr.js +5 -0
- package/src/core/geom/ConicRay.d.ts.map +1 -1
- package/src/core/geom/ConicRay.js +9 -2
- package/src/core/geom/Quaternion.d.ts.map +1 -1
- package/src/core/geom/Quaternion.js +7 -3
- package/src/core/math/build_gaussian_kernel_1d.d.ts +2 -2
- package/src/core/math/build_gaussian_kernel_1d.d.ts.map +1 -1
- package/src/core/math/build_gaussian_kernel_1d.js +4 -2
- package/src/core/math/build_gaussian_kernel_2d.d.ts +2 -2
- package/src/core/math/build_gaussian_kernel_2d.d.ts.map +1 -1
- package/src/core/math/build_gaussian_kernel_2d.js +4 -2
- package/src/core/math/gaussian.d.ts +2 -2
- package/src/core/math/gaussian.js +2 -2
- package/src/core/math/spline/spline3_bezier_bounds.d.ts.map +1 -1
- package/src/core/math/spline/spline3_bezier_bounds.js +10 -3
- package/src/core/math/spline/spline3_bezier_to_hermite.d.ts +8 -7
- package/src/core/math/spline/spline3_bezier_to_hermite.d.ts.map +1 -1
- package/src/core/math/spline/spline3_bezier_to_hermite.js +13 -12
- package/src/core/math/spline/spline3_hermite_bounds.d.ts.map +1 -1
- package/src/core/math/spline/spline3_hermite_bounds.js +10 -3
- package/src/core/math/spline/spline3_hermite_bounds_t.d.ts.map +1 -1
- package/src/core/math/spline/spline3_hermite_bounds_t.js +115 -109
- package/src/core/math/spline/spline3_hermite_to_bezier.d.ts +2 -0
- package/src/core/math/spline/spline3_hermite_to_bezier.d.ts.map +1 -1
- package/src/core/math/spline/spline3_hermite_to_bezier.js +2 -0
- package/src/core/math/statistics/computeStatisticalMean.js +1 -1
- package/src/core/math/statistics/gaussian_amplitude.d.ts.map +1 -1
- package/src/core/math/statistics/gaussian_amplitude.js +3 -1
- package/src/engine/animation/clip/ecd_bind_animation_curve.d.ts.map +1 -1
- package/src/engine/animation/clip/ecd_bind_animation_curve.js +10 -1
- package/src/engine/animation/clip/hemisphere_align_quaternion_values.d.ts +20 -0
- package/src/engine/animation/clip/hemisphere_align_quaternion_values.d.ts.map +1 -0
- package/src/engine/animation/clip/hemisphere_align_quaternion_values.js +37 -0
- package/src/engine/animation/keyed2/AnimationTrackPlayback.d.ts.map +1 -1
- package/src/engine/animation/keyed2/AnimationTrackPlayback.js +5 -1
- package/src/engine/ecs/EntityComponentDataset.d.ts.map +1 -1
- package/src/engine/ecs/EntityComponentDataset.js +5 -21
- package/src/engine/ecs/fow/FogOfWar.d.ts +22 -0
- package/src/engine/ecs/fow/FogOfWar.d.ts.map +1 -1
- package/src/engine/ecs/fow/FogOfWar.js +202 -54
- package/src/engine/ecs/fow/FogOfWarEdgeMode.d.ts +16 -0
- package/src/engine/ecs/fow/FogOfWarEdgeMode.d.ts.map +1 -0
- package/src/engine/ecs/fow/FogOfWarEdgeMode.js +39 -0
- package/src/engine/ecs/fow/FogOfWarSystem.d.ts.map +1 -1
- package/src/engine/ecs/fow/FogOfWarSystem.js +1 -0
- package/src/engine/ecs/fow/serialization/FogOfWarSerializationAdapter.d.ts.map +1 -1
- package/src/engine/ecs/fow/serialization/FogOfWarSerializationAdapter.js +3 -0
- package/src/engine/ecs/fow/shader/FogOfWarRenderer.d.ts +7 -0
- package/src/engine/ecs/fow/shader/FogOfWarRenderer.d.ts.map +1 -1
- package/src/engine/ecs/fow/shader/FogOfWarRenderer.js +155 -145
- package/src/engine/ecs/fow/shader/screenSpaceFogOfWarShader.d.ts.map +1 -1
- package/src/engine/ecs/fow/shader/screenSpaceFogOfWarShader.js +33 -8
- package/src/engine/ecs/storage/binary/collection/BinaryCollectionDeSerializer.d.ts.map +1 -1
- package/src/engine/ecs/storage/binary/collection/BinaryCollectionDeSerializer.js +3 -1
- package/src/engine/graphics/GraphicsEngine.d.ts +5 -1
- package/src/engine/graphics/GraphicsEngine.d.ts.map +1 -1
- package/src/engine/graphics/GraphicsEngine.js +14 -3
- package/src/engine/graphics/composit/CompositLayer.d.ts.map +1 -1
- package/src/engine/graphics/composit/CompositLayer.js +258 -255
- package/src/engine/graphics/composit/LayerCompositer.d.ts +12 -0
- package/src/engine/graphics/composit/LayerCompositer.d.ts.map +1 -1
- package/src/engine/graphics/composit/LayerCompositer.js +19 -10
- package/src/engine/graphics/ecs/highlight/plugin/OutlineRenderPlugin.d.ts +1 -1
- package/src/engine/graphics/ecs/highlight/plugin/OutlineRenderPlugin.d.ts.map +1 -1
- package/src/engine/graphics/ecs/highlight/plugin/OutlineRenderPlugin.js +10 -4
- package/src/engine/graphics/ecs/highlight/renderer/OutlineRenderer.d.ts +6 -0
- package/src/engine/graphics/ecs/highlight/renderer/OutlineRenderer.d.ts.map +1 -1
- package/src/engine/graphics/ecs/highlight/renderer/OutlineRenderer.js +21 -0
- package/src/engine/graphics/ecs/path/ribbon/RibbonPathBuilder.d.ts.map +1 -1
- package/src/engine/graphics/ecs/path/ribbon/RibbonPathBuilder.js +5 -23
- package/src/engine/graphics/ecs/path/tube/build/estimatePathViaIterativeIntegral.d.ts.map +1 -1
- package/src/engine/graphics/ecs/path/tube/build/estimatePathViaIterativeIntegral.js +6 -4
- package/src/engine/graphics/ecs/water/WaterSystem.d.ts.map +1 -1
- package/src/engine/graphics/ecs/water/WaterSystem.js +9 -3
- package/src/engine/graphics/particles/ecs/ParticleEmitterSystem.d.ts +12 -0
- package/src/engine/graphics/particles/ecs/ParticleEmitterSystem.d.ts.map +1 -1
- package/src/engine/graphics/particles/ecs/ParticleEmitterSystem.js +46 -9
- package/src/engine/graphics/particles/particular/engine/ParticularEngine.d.ts +5 -0
- package/src/engine/graphics/particles/particular/engine/ParticularEngine.d.ts.map +1 -1
- package/src/engine/graphics/particles/particular/engine/ParticularEngine.js +8 -0
- package/src/engine/graphics/particles/particular/engine/shader/MaterialRecord.d.ts +7 -0
- package/src/engine/graphics/particles/particular/engine/shader/MaterialRecord.d.ts.map +1 -1
- package/src/engine/graphics/particles/particular/engine/shader/MaterialRecord.js +8 -0
- package/src/engine/graphics/particles/particular/engine/shader/ShaderManager.d.ts +10 -2
- package/src/engine/graphics/particles/particular/engine/shader/ShaderManager.d.ts.map +1 -1
- package/src/engine/graphics/particles/particular/engine/shader/ShaderManager.js +42 -10
- package/src/engine/graphics/render/buffer/FrameBuffer.d.ts.map +1 -1
- package/src/engine/graphics/render/buffer/FrameBuffer.js +5 -2
- package/src/engine/graphics/render/buffer/simple-fx/ao/AmbientOcclusionPostProcessEffect.d.ts +13 -1
- package/src/engine/graphics/render/buffer/simple-fx/ao/AmbientOcclusionPostProcessEffect.d.ts.map +1 -1
- package/src/engine/graphics/render/buffer/simple-fx/ao/AmbientOcclusionPostProcessEffect.js +40 -7
- package/src/engine/graphics/render/buffer/simple-fx/taa/TemporalSupersamplingRenderPlugin.d.ts.map +1 -1
- package/src/engine/graphics/render/buffer/simple-fx/taa/TemporalSupersamplingRenderPlugin.js +10 -4
- package/src/engine/graphics/render/forward_plus/LightManager.d.ts.map +1 -1
- package/src/engine/graphics/render/forward_plus/LightManager.js +1235 -1232
- package/src/engine/graphics/render/forward_plus/plugin/ForwardPlusRenderingPlugin.d.ts +5 -0
- package/src/engine/graphics/render/forward_plus/plugin/ForwardPlusRenderingPlugin.d.ts.map +1 -1
- package/src/engine/graphics/render/forward_plus/plugin/ForwardPlusRenderingPlugin.js +11 -10
- package/src/engine/graphics/trail/tube/TubeX.d.ts.map +1 -1
- package/src/engine/graphics/trail/tube/TubeX.js +557 -555
- package/src/engine/graphics/trail/x/RibbonXPlugin.d.ts +12 -1
- package/src/engine/graphics/trail/x/RibbonXPlugin.d.ts.map +1 -1
- package/src/engine/graphics/trail/x/RibbonXPlugin.js +15 -8
- package/src/engine/input/ecs/systems/InputControllerSystem.d.ts.map +1 -1
- package/src/engine/input/ecs/systems/InputControllerSystem.js +9 -6
- package/src/engine/navigation/ecs/components/Path.d.ts +5 -2
- package/src/engine/navigation/ecs/components/Path.d.ts.map +1 -1
- package/src/engine/navigation/ecs/components/Path.js +10 -4
- package/src/engine/navigation/ecs/path_following/PathFollowingSystem.js +1 -1
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/engine/physics/fluid/ecs/FluidSystem.d.ts +3 -3
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
import { assert } from "../assert.js";
|
|
1
2
|
import { gaussian } from "./gaussian.js";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
|
-
*
|
|
5
|
+
* Build a normalized 1-dimensional gaussian kernel, taps sum to 1.
|
|
5
6
|
* @param {Float32Array} kernel
|
|
6
7
|
* @param {number} sample_count
|
|
7
|
-
* @param {number} sigma
|
|
8
|
+
* @param {number} sigma standard deviation, must be greater than 0. A sigma of 0 makes every tap `NaN`, as the centre tap evaluates `exp(-0/0)`
|
|
8
9
|
*/
|
|
9
10
|
export function build_gaussian_kernel_1d(kernel, sample_count, sigma) {
|
|
11
|
+
assert.greaterThan(sigma, 0, 'sigma');
|
|
10
12
|
|
|
11
13
|
const half_width = (sample_count - 1) * 0.5;
|
|
12
14
|
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* @param {number[]|Float32Array} result
|
|
4
4
|
* @param {number} samplesX
|
|
5
5
|
* @param {number} samplesY
|
|
6
|
-
* @param {number} sigma_x
|
|
7
|
-
* @param {number} sigma_y
|
|
6
|
+
* @param {number} sigma_x standard deviation along X, must be greater than 0. A sigma of 0 makes every tap `NaN`, as the centre tap evaluates `exp(-0/0)`
|
|
7
|
+
* @param {number} sigma_y standard deviation along Y, must be greater than 0
|
|
8
8
|
*/
|
|
9
9
|
export function build_gaussian_kernel_2d(result: number[] | Float32Array, samplesX: number, samplesY: number, sigma_x: number, sigma_y: number): void;
|
|
10
10
|
//# sourceMappingURL=build_gaussian_kernel_2d.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build_gaussian_kernel_2d.d.ts","sourceRoot":"","sources":["../../../../src/core/math/build_gaussian_kernel_2d.js"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,iDANW,MAAM,EAAE,GAAC,YAAY,YACrB,MAAM,YACN,MAAM,WACN,MAAM,WACN,MAAM,
|
|
1
|
+
{"version":3,"file":"build_gaussian_kernel_2d.d.ts","sourceRoot":"","sources":["../../../../src/core/math/build_gaussian_kernel_2d.js"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,iDANW,MAAM,EAAE,GAAC,YAAY,YACrB,MAAM,YACN,MAAM,WACN,MAAM,WACN,MAAM,QA+ChB"}
|
|
@@ -6,8 +6,8 @@ import { gaussian } from "./gaussian.js";
|
|
|
6
6
|
* @param {number[]|Float32Array} result
|
|
7
7
|
* @param {number} samplesX
|
|
8
8
|
* @param {number} samplesY
|
|
9
|
-
* @param {number} sigma_x
|
|
10
|
-
* @param {number} sigma_y
|
|
9
|
+
* @param {number} sigma_x standard deviation along X, must be greater than 0. A sigma of 0 makes every tap `NaN`, as the centre tap evaluates `exp(-0/0)`
|
|
10
|
+
* @param {number} sigma_y standard deviation along Y, must be greater than 0
|
|
11
11
|
*/
|
|
12
12
|
export function build_gaussian_kernel_2d(
|
|
13
13
|
result,
|
|
@@ -16,6 +16,8 @@ export function build_gaussian_kernel_2d(
|
|
|
16
16
|
) {
|
|
17
17
|
assert.isNonNegativeInteger(samplesX, 'samplesX');
|
|
18
18
|
assert.isNonNegativeInteger(samplesY, 'samplesY');
|
|
19
|
+
assert.greaterThan(sigma_x, 0, 'sigma_x');
|
|
20
|
+
assert.greaterThan(sigma_y, 0, 'sigma_y');
|
|
19
21
|
|
|
20
22
|
const half_samples_x = (samplesX - 1) * 0.5;
|
|
21
23
|
const half_samples_y = (samplesY - 1) * 0.5;
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* Un-normalized gaussian: `exp(−distance² / (2·sigma²))`.
|
|
3
3
|
* This is not the standard gaussian — it lacks the normalization factor;
|
|
4
4
|
* the standard gaussian would be weighted by `1 / √(2π·sigma²)`.
|
|
5
|
-
* @param {number} sigma Standard deviation. Controls the "width" of the bell curve: larger sigma → wider curve, slower falloff with distance.
|
|
5
|
+
* @param {number} sigma Standard deviation. Controls the "width" of the bell curve: larger sigma → wider curve, slower falloff with distance. Must be greater than 0; at 0 the exponent is a division by zero and the result is `NaN` for `distance === 0`.
|
|
6
6
|
* @param {number} distance Distance from the mean (the point at which to evaluate the curve). At 0 the result is 1; it decays toward 0 as |distance| grows.
|
|
7
|
-
* @returns {number} Ranges from 0 to 1
|
|
7
|
+
* @returns {number} Ranges from 0 to 1, inclusive of 1 at distance 0. Non-zero in exact arithmetic, but `Math.exp` underflows to exactly 0 once `distance/sigma` is large enough (around 27 standard deviations), so callers must not assume a non-zero result.
|
|
8
8
|
*/
|
|
9
9
|
export function gaussian(sigma: number, distance: number): number;
|
|
10
10
|
//# sourceMappingURL=gaussian.d.ts.map
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* Un-normalized gaussian: `exp(−distance² / (2·sigma²))`.
|
|
3
3
|
* This is not the standard gaussian — it lacks the normalization factor;
|
|
4
4
|
* the standard gaussian would be weighted by `1 / √(2π·sigma²)`.
|
|
5
|
-
* @param {number} sigma Standard deviation. Controls the "width" of the bell curve: larger sigma → wider curve, slower falloff with distance.
|
|
5
|
+
* @param {number} sigma Standard deviation. Controls the "width" of the bell curve: larger sigma → wider curve, slower falloff with distance. Must be greater than 0; at 0 the exponent is a division by zero and the result is `NaN` for `distance === 0`.
|
|
6
6
|
* @param {number} distance Distance from the mean (the point at which to evaluate the curve). At 0 the result is 1; it decays toward 0 as |distance| grows.
|
|
7
|
-
* @returns {number} Ranges from 0 to 1
|
|
7
|
+
* @returns {number} Ranges from 0 to 1, inclusive of 1 at distance 0. Non-zero in exact arithmetic, but `Math.exp` underflows to exactly 0 once `distance/sigma` is large enough (around 27 standard deviations), so callers must not assume a non-zero result.
|
|
8
8
|
*/
|
|
9
9
|
export function gaussian(sigma, distance) {
|
|
10
10
|
const d2 = distance * distance;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spline3_bezier_bounds.d.ts","sourceRoot":"","sources":["../../../../../src/core/math/spline/spline3_bezier_bounds.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"spline3_bezier_bounds.d.ts","sourceRoot":"","sources":["../../../../../src/core/math/spline/spline3_bezier_bounds.js"],"names":[],"mappings":"AAMA;;;;;;;;;;;;GAYG;AACH,8CARW,MAAM,EAAE,GAAC,YAAY,iBACrB,MAAM,iBACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,QA6EhB"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { assert } from "../../assert.js";
|
|
2
2
|
import { max2 } from "../max2.js";
|
|
3
|
+
import { max3 } from "../max3.js";
|
|
3
4
|
import { min2 } from "../min2.js";
|
|
4
5
|
import { spline3_bezier } from "./spline3_bezier.js";
|
|
5
6
|
|
|
@@ -27,9 +28,14 @@ export function spline3_bezier_bounds(result, result_offset, result_stride, p0,
|
|
|
27
28
|
let min = min2(p0, p3);
|
|
28
29
|
let max = max2(p0, p3);
|
|
29
30
|
|
|
30
|
-
|
|
31
|
+
// `a`, `b` and `c` all scale linearly with the curve's coordinates, so the degeneracy test has to
|
|
32
|
+
// be relative to them. An absolute threshold silently treats an entire small-coordinate curve as
|
|
33
|
+
// degenerate and reports the endpoints as the bounds, missing interior extrema.
|
|
34
|
+
const epsilon = max3(Math.abs(a), Math.abs(b), Math.abs(c)) * 1e-12;
|
|
31
35
|
|
|
32
|
-
|
|
36
|
+
if (Math.abs(a) <= epsilon) {
|
|
37
|
+
|
|
38
|
+
if (Math.abs(b) > epsilon) {
|
|
33
39
|
const t = -c / b;
|
|
34
40
|
|
|
35
41
|
if (0 < t && t < 1) {
|
|
@@ -49,10 +55,11 @@ export function spline3_bezier_bounds(result, result_offset, result_stride, p0,
|
|
|
49
55
|
} else {
|
|
50
56
|
|
|
51
57
|
const b2ac = b * b - 4 * c * a;
|
|
52
|
-
const sqrtb2ac = Math.sqrt(b2ac);
|
|
53
58
|
|
|
54
59
|
if (b2ac >= 0) {
|
|
55
60
|
|
|
61
|
+
const sqrtb2ac = Math.sqrt(b2ac);
|
|
62
|
+
|
|
56
63
|
const t1 = (-b + sqrtb2ac) / (2 * a);
|
|
57
64
|
|
|
58
65
|
if (0 < t1 && t1 < 1) {
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* One-dimensional cubic curve conversion from bezier to Hermite
|
|
3
|
+
* The result is `[p0, p1, m0, m1]` where P are positions and M are tangents, matching the argument
|
|
4
|
+
* order taken by {@link spline3_hermite} and the layout written by {@link spline3_hermite_subdivide}.
|
|
5
|
+
* The result can therefore be fed straight back into {@link spline3_hermite_to_bezier}.
|
|
5
6
|
* @param {Float32Array|number[]} result where to put results
|
|
6
7
|
* @param {number} result_offset offset to start writing at in result array
|
|
7
8
|
* @param {number} result_stride how far to step between each written value. Necessary for N-dimensional curves where we want to interleave multiple curves together, such as for color or quaternions
|
|
8
|
-
* @param {number} p0
|
|
9
|
-
* @param {number} p1
|
|
10
|
-
* @param {number} p2
|
|
11
|
-
* @param {number} p3
|
|
9
|
+
* @param {number} p0 first bezier control point
|
|
10
|
+
* @param {number} p1 second bezier control point
|
|
11
|
+
* @param {number} p2 third bezier control point
|
|
12
|
+
* @param {number} p3 fourth bezier control point
|
|
12
13
|
* @see spline3_hermite_to_bezier
|
|
13
14
|
*/
|
|
14
15
|
export function spline3_bezier_to_hermite(result: Float32Array | number[], result_offset: number, result_stride: number, p0: number, p1: number, p2: number, p3: number): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spline3_bezier_to_hermite.d.ts","sourceRoot":"","sources":["../../../../../src/core/math/spline/spline3_bezier_to_hermite.js"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"spline3_bezier_to_hermite.d.ts","sourceRoot":"","sources":["../../../../../src/core/math/spline/spline3_bezier_to_hermite.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,kDATW,YAAY,GAAC,MAAM,EAAE,iBACrB,MAAM,iBACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,QAsBhB"}
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* One-dimensional cubic curve conversion from bezier to Hermite
|
|
3
|
+
* The result is `[p0, p1, m0, m1]` where P are positions and M are tangents, matching the argument
|
|
4
|
+
* order taken by {@link spline3_hermite} and the layout written by {@link spline3_hermite_subdivide}.
|
|
5
|
+
* The result can therefore be fed straight back into {@link spline3_hermite_to_bezier}.
|
|
5
6
|
* @param {Float32Array|number[]} result where to put results
|
|
6
7
|
* @param {number} result_offset offset to start writing at in result array
|
|
7
8
|
* @param {number} result_stride how far to step between each written value. Necessary for N-dimensional curves where we want to interleave multiple curves together, such as for color or quaternions
|
|
8
|
-
* @param {number} p0
|
|
9
|
-
* @param {number} p1
|
|
10
|
-
* @param {number} p2
|
|
11
|
-
* @param {number} p3
|
|
9
|
+
* @param {number} p0 first bezier control point
|
|
10
|
+
* @param {number} p1 second bezier control point
|
|
11
|
+
* @param {number} p2 third bezier control point
|
|
12
|
+
* @param {number} p3 fourth bezier control point
|
|
12
13
|
* @see spline3_hermite_to_bezier
|
|
13
14
|
*/
|
|
14
15
|
export function spline3_bezier_to_hermite(
|
|
@@ -22,12 +23,12 @@ export function spline3_bezier_to_hermite(
|
|
|
22
23
|
|
|
23
24
|
const TENSION_FACTOR = 3;
|
|
24
25
|
|
|
25
|
-
const
|
|
26
|
-
const
|
|
26
|
+
const m0 = (p1 - p0) * TENSION_FACTOR;
|
|
27
|
+
const m1 = (p3 - p2) * TENSION_FACTOR;
|
|
27
28
|
|
|
28
29
|
result[result_offset + 0 * result_stride] = p0;
|
|
29
|
-
result[result_offset + 1 * result_stride] =
|
|
30
|
-
result[result_offset + 2 * result_stride] =
|
|
31
|
-
result[result_offset + 3 * result_stride] =
|
|
30
|
+
result[result_offset + 1 * result_stride] = p3;
|
|
31
|
+
result[result_offset + 2 * result_stride] = m0;
|
|
32
|
+
result[result_offset + 3 * result_stride] = m1;
|
|
32
33
|
|
|
33
34
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spline3_hermite_bounds.d.ts","sourceRoot":"","sources":["../../../../../src/core/math/spline/spline3_hermite_bounds.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"spline3_hermite_bounds.d.ts","sourceRoot":"","sources":["../../../../../src/core/math/spline/spline3_hermite_bounds.js"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;GAcG;AACH,+CAXW,MAAM,EAAE,GAAC,YAAY,iBACrB,MAAM,iBACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,QA2FhB"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { assert } from "../../assert.js";
|
|
2
2
|
import { max2 } from "../max2.js";
|
|
3
|
+
import { max3 } from "../max3.js";
|
|
3
4
|
import { min2 } from "../min2.js";
|
|
4
5
|
import { spline3_hermite } from "./spline3_hermite.js";
|
|
5
6
|
|
|
@@ -40,9 +41,14 @@ export function spline3_hermite_bounds(
|
|
|
40
41
|
let min = min2(p0, p1);
|
|
41
42
|
let max = max2(p0, p1);
|
|
42
43
|
|
|
43
|
-
|
|
44
|
+
// `a`, `b` and `c` all scale linearly with the curve's coordinates, so the degeneracy test has to
|
|
45
|
+
// be relative to them. An absolute threshold silently treats an entire small-coordinate curve as
|
|
46
|
+
// degenerate and reports the endpoints as the bounds, missing interior extrema.
|
|
47
|
+
const epsilon = max3(Math.abs(a), Math.abs(b), Math.abs(c)) * 1e-12;
|
|
44
48
|
|
|
45
|
-
|
|
49
|
+
if (Math.abs(a) <= epsilon) {
|
|
50
|
+
|
|
51
|
+
if (Math.abs(b) > epsilon) {
|
|
46
52
|
const t = -c / b;
|
|
47
53
|
|
|
48
54
|
if (0 < t && t < 1) {
|
|
@@ -62,10 +68,11 @@ export function spline3_hermite_bounds(
|
|
|
62
68
|
} else {
|
|
63
69
|
|
|
64
70
|
const b2ac = b * b - 4 * c * a;
|
|
65
|
-
const sqrtb2ac = Math.sqrt(b2ac);
|
|
66
71
|
|
|
67
72
|
if (b2ac >= 0) {
|
|
68
73
|
|
|
74
|
+
const sqrtb2ac = Math.sqrt(b2ac);
|
|
75
|
+
|
|
69
76
|
const t1 = (-b + sqrtb2ac) / (2 * a);
|
|
70
77
|
|
|
71
78
|
if (0 < t1 && t1 < 1) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spline3_hermite_bounds_t.d.ts","sourceRoot":"","sources":["../../../../../src/core/math/spline/spline3_hermite_bounds_t.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"spline3_hermite_bounds_t.d.ts","sourceRoot":"","sources":["../../../../../src/core/math/spline/spline3_hermite_bounds_t.js"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,iDAXW,MAAM,EAAE,GAAC,YAAY,GAAC,YAAY,iBAClC,MAAM,iBACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,QA8FhB"}
|
|
@@ -1,109 +1,115 @@
|
|
|
1
|
-
import { assert } from "../../assert.js";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
*
|
|
7
|
-
* `
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* @param {number}
|
|
16
|
-
* @param {number}
|
|
17
|
-
* @param {number}
|
|
18
|
-
* @param {number}
|
|
19
|
-
* @param {number}
|
|
20
|
-
* @param {number}
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* @
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
assert.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
//
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
1
|
+
import { assert } from "../../assert.js";
|
|
2
|
+
import { max3 } from "../max3.js";
|
|
3
|
+
import { spline3_hermite } from "./spline3_hermite.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Compute the parameter values `t` at which a cubic Hermite spline reaches its
|
|
7
|
+
* minimum and maximum on `[0, 1]`. `t_at_min` is written to
|
|
8
|
+
* `result[result_offset]`, `t_at_max` to `result[result_offset + result_stride]`.
|
|
9
|
+
* Both values lie in `[0, 1]`.
|
|
10
|
+
*
|
|
11
|
+
* Companion to {@link spline3_hermite_bounds}, which writes the values; this
|
|
12
|
+
* one writes the parameters at which those values are reached. Either function
|
|
13
|
+
* does its own critical-point search — call whichever you actually need.
|
|
14
|
+
*
|
|
15
|
+
* @param {number[]|Float32Array|Float64Array} result
|
|
16
|
+
* @param {number} result_offset
|
|
17
|
+
* @param {number} result_stride
|
|
18
|
+
* @param {number} p0
|
|
19
|
+
* @param {number} p1
|
|
20
|
+
* @param {number} m0
|
|
21
|
+
* @param {number} m1
|
|
22
|
+
*
|
|
23
|
+
* @author Alex Goldring
|
|
24
|
+
* @copyright Company Named Limited (c) 2026
|
|
25
|
+
*/
|
|
26
|
+
export function spline3_hermite_bounds_t(
|
|
27
|
+
result,
|
|
28
|
+
result_offset,
|
|
29
|
+
result_stride,
|
|
30
|
+
p0, p1, m0, m1
|
|
31
|
+
) {
|
|
32
|
+
assert.greaterThan(result_stride, 0, 'result_stride must be greater than 0');
|
|
33
|
+
assert.isInteger(result_stride, 'result_stride');
|
|
34
|
+
|
|
35
|
+
// Derivative of the Hermite polynomial:
|
|
36
|
+
// 3 t² (m0 + m1 + 2 p0 - 2 p1) - 2 t (2 m0 + m1 + 3 p0 - 3 p1) + m0
|
|
37
|
+
const a = 3 * (m0 + m1 + 2 * p0 - 2 * p1);
|
|
38
|
+
const b = -2 * (2 * m0 + m1 + 3 * p0 - 3 * p1);
|
|
39
|
+
const c = m0;
|
|
40
|
+
|
|
41
|
+
let min, max, t_at_min, t_at_max;
|
|
42
|
+
if (p0 <= p1) {
|
|
43
|
+
min = p0; t_at_min = 0;
|
|
44
|
+
max = p1; t_at_max = 1;
|
|
45
|
+
} else {
|
|
46
|
+
min = p1; t_at_min = 1;
|
|
47
|
+
max = p0; t_at_max = 0;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// `a`, `b` and `c` all scale linearly with the curve's coordinates, so the degeneracy test has to
|
|
51
|
+
// be relative to them. An absolute threshold silently treats an entire small-coordinate curve as
|
|
52
|
+
// degenerate and reports the endpoints as the extrema, missing interior ones.
|
|
53
|
+
const epsilon = max3(Math.abs(a), Math.abs(b), Math.abs(c)) * 1e-12;
|
|
54
|
+
|
|
55
|
+
if (Math.abs(a) <= epsilon) {
|
|
56
|
+
|
|
57
|
+
if (Math.abs(b) > epsilon) {
|
|
58
|
+
const t = -c / b;
|
|
59
|
+
|
|
60
|
+
if (0 < t && t < 1) {
|
|
61
|
+
const value = spline3_hermite(t, p0, p1, m0, m1);
|
|
62
|
+
|
|
63
|
+
if (value < min) {
|
|
64
|
+
min = value;
|
|
65
|
+
t_at_min = t;
|
|
66
|
+
}
|
|
67
|
+
if (value > max) {
|
|
68
|
+
max = value;
|
|
69
|
+
t_at_max = t;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
} else {
|
|
75
|
+
|
|
76
|
+
const b2ac = b * b - 4 * c * a;
|
|
77
|
+
|
|
78
|
+
if (b2ac >= 0) {
|
|
79
|
+
const sqrtb2ac = Math.sqrt(b2ac);
|
|
80
|
+
|
|
81
|
+
const t1 = (-b + sqrtb2ac) / (2 * a);
|
|
82
|
+
|
|
83
|
+
if (0 < t1 && t1 < 1) {
|
|
84
|
+
const value = spline3_hermite(t1, p0, p1, m0, m1);
|
|
85
|
+
|
|
86
|
+
if (value < min) {
|
|
87
|
+
min = value;
|
|
88
|
+
t_at_min = t1;
|
|
89
|
+
}
|
|
90
|
+
if (value > max) {
|
|
91
|
+
max = value;
|
|
92
|
+
t_at_max = t1;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const t2 = (-b - sqrtb2ac) / (2 * a);
|
|
97
|
+
|
|
98
|
+
if (0 < t2 && t2 < 1) {
|
|
99
|
+
const value = spline3_hermite(t2, p0, p1, m0, m1);
|
|
100
|
+
|
|
101
|
+
if (value < min) {
|
|
102
|
+
min = value;
|
|
103
|
+
t_at_min = t2;
|
|
104
|
+
}
|
|
105
|
+
if (value > max) {
|
|
106
|
+
max = value;
|
|
107
|
+
t_at_max = t2;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
result[result_offset] = t_at_min;
|
|
114
|
+
result[result_offset + result_stride] = t_at_max;
|
|
115
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* One-dimensional cubic curve conversion from Hermite to bezier
|
|
3
|
+
* The result is the 4 bezier control points in order. {@link spline3_bezier_to_hermite} inverts this,
|
|
4
|
+
* and writes its Hermite as `[p0, p1, m0, m1]`, so its output can be fed straight back in here.
|
|
3
5
|
* @param {Float32Array|number[]} result where to put results
|
|
4
6
|
* @param {number} result_offset offset to start writing at in result array
|
|
5
7
|
* @param {number} result_stride how far to step between each written value. Necessary for N-dimensional curves where we want to interleave multiple curves together, such as for color or quaternions
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spline3_hermite_to_bezier.d.ts","sourceRoot":"","sources":["../../../../../src/core/math/spline/spline3_hermite_to_bezier.js"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"spline3_hermite_to_bezier.d.ts","sourceRoot":"","sources":["../../../../../src/core/math/spline/spline3_hermite_to_bezier.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,kDATW,YAAY,GAAC,MAAM,EAAE,iBACrB,MAAM,iBACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,QAsBhB"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* One-dimensional cubic curve conversion from Hermite to bezier
|
|
3
|
+
* The result is the 4 bezier control points in order. {@link spline3_bezier_to_hermite} inverts this,
|
|
4
|
+
* and writes its Hermite as `[p0, p1, m0, m1]`, so its output can be fed straight back in here.
|
|
3
5
|
* @param {Float32Array|number[]} result where to put results
|
|
4
6
|
* @param {number} result_offset offset to start writing at in result array
|
|
5
7
|
* @param {number} result_stride how far to step between each written value. Necessary for N-dimensional curves where we want to interleave multiple curves together, such as for color or quaternions
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gaussian_amplitude.d.ts","sourceRoot":"","sources":["../../../../../src/core/math/statistics/gaussian_amplitude.js"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,6CAJW,MAAM,sBACN,MAAM,GACJ,MAAM,
|
|
1
|
+
{"version":3,"file":"gaussian_amplitude.d.ts","sourceRoot":"","sources":["../../../../../src/core/math/statistics/gaussian_amplitude.js"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,6CAJW,MAAM,sBACN,MAAM,GACJ,MAAM,CAQlB"}
|
|
@@ -9,5 +9,7 @@ import { gaussian } from "../gaussian.js";
|
|
|
9
9
|
export function gaussian_amplitude(variance, distance_from_mean) {
|
|
10
10
|
// Adapted from https://github.com/Kitware/VTK/blob/af928016f4041ad8a6a193d032355b909721fc95/Common/Core/vtkMath.cxx#L339
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
// gaussian() takes a standard deviation and squares it internally, so pass sqrt(variance) to get
|
|
13
|
+
// the exponent -distance^2 / (2 * variance) that the 1/sqrt(2*PI*variance) normalization expects.
|
|
14
|
+
return 1.0 / Math.sqrt(2.0 * Math.PI * variance) * gaussian(Math.sqrt(variance), distance_from_mean);
|
|
13
15
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ecd_bind_animation_curve.d.ts","sourceRoot":"","sources":["../../../../../src/engine/animation/clip/ecd_bind_animation_curve.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ecd_bind_animation_curve.d.ts","sourceRoot":"","sources":["../../../../../src/engine/animation/clip/ecd_bind_animation_curve.js"],"names":[],"mappings":"AA6GA;;;;GAIG;AACH,2DAFW,mBAAmB,wBAgC7B;8BA9I6B,oBAAoB;qCACb,2BAA2B"}
|
|
@@ -7,6 +7,7 @@ import { AnimationTrack } from "./AnimationTrack.js";
|
|
|
7
7
|
import { AnimationTrackBinding } from "./AnimationTrackBinding.js";
|
|
8
8
|
import { bind_property_writer } from "./bind_property_writer.js";
|
|
9
9
|
import { curve_from_track_data } from "./curve_from_track_data.js";
|
|
10
|
+
import { hemisphere_align_quaternion_values } from "./hemisphere_align_quaternion_values.js";
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
/**
|
|
@@ -44,7 +45,7 @@ function track_to_interpolation(track) {
|
|
|
44
45
|
*/
|
|
45
46
|
function convert_three_track_to_curves(track) {
|
|
46
47
|
|
|
47
|
-
|
|
48
|
+
let values = track.values;
|
|
48
49
|
const times = track.times;
|
|
49
50
|
|
|
50
51
|
const key_count = times.length;
|
|
@@ -58,6 +59,14 @@ function convert_three_track_to_curves(track) {
|
|
|
58
59
|
// figure out interpolation type
|
|
59
60
|
const interpolation = track_to_interpolation(track);
|
|
60
61
|
|
|
62
|
+
// A quaternion track is interpolated below as four independent per-component curves; without hemisphere
|
|
63
|
+
// alignment a pair of adjacent keys with a negative dot product interpolates the long way around. Negate
|
|
64
|
+
// keys into a common hemisphere first so the component nlerp takes the short arc. (Discrete needs no
|
|
65
|
+
// interpolation; CubicTangents packs tangents per key and is handled separately / not yet aligned.)
|
|
66
|
+
if (interpolation === AnimationInterpolationKind.Linear && track.ValueTypeName === 'quaternion') {
|
|
67
|
+
values = hemisphere_align_quaternion_values(values, key_count);
|
|
68
|
+
}
|
|
69
|
+
|
|
61
70
|
const values_per_key = values.length / key_count;
|
|
62
71
|
|
|
63
72
|
const component_count = interpolation === AnimationInterpolationKind.CubicTangents ? values_per_key / 3 : values_per_key;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Return a copy of a flat quaternion keyframe-value array (`[x0,y0,z0,w0, x1,y1,z1,w1, ...]`) in which every
|
|
3
|
+
* key has been negated as needed so that consecutive keys lie in the same hemisphere (their dot product is
|
|
4
|
+
* non-negative).
|
|
5
|
+
*
|
|
6
|
+
* A quaternion and its negation represent the same rotation, so this does not change the pose at any key. It
|
|
7
|
+
* does change what happens BETWEEN keys: the animation clip pipeline interpolates a quaternion track as four
|
|
8
|
+
* independent per-component curves (component-wise normalized-lerp), and without hemisphere alignment a pair of
|
|
9
|
+
* adjacent keys whose dot product is negative interpolates the long way around — spinning nearly 360 degrees and
|
|
10
|
+
* dipping through a near-degenerate quaternion at the midpoint. Aligning the keys first makes the component nlerp
|
|
11
|
+
* take the short arc, matching what three.js does at interpolation time via Quaternion.slerpFlat's sign flip.
|
|
12
|
+
*
|
|
13
|
+
* The input array is not mutated.
|
|
14
|
+
*
|
|
15
|
+
* @param {number[]|Float32Array|Float64Array} values flat quaternion components, 4 per key
|
|
16
|
+
* @param {number} key_count number of keyframes
|
|
17
|
+
* @returns {number[]|Float32Array|Float64Array} a copy with hemisphere-aligned keys
|
|
18
|
+
*/
|
|
19
|
+
export function hemisphere_align_quaternion_values(values: number[] | Float32Array | Float64Array, key_count: number): number[] | Float32Array | Float64Array;
|
|
20
|
+
//# sourceMappingURL=hemisphere_align_quaternion_values.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hemisphere_align_quaternion_values.d.ts","sourceRoot":"","sources":["../../../../../src/engine/animation/clip/hemisphere_align_quaternion_values.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,2DAJW,MAAM,EAAE,GAAC,YAAY,GAAC,YAAY,aAClC,MAAM,GACJ,MAAM,EAAE,GAAC,YAAY,GAAC,YAAY,CAoB9C"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Return a copy of a flat quaternion keyframe-value array (`[x0,y0,z0,w0, x1,y1,z1,w1, ...]`) in which every
|
|
3
|
+
* key has been negated as needed so that consecutive keys lie in the same hemisphere (their dot product is
|
|
4
|
+
* non-negative).
|
|
5
|
+
*
|
|
6
|
+
* A quaternion and its negation represent the same rotation, so this does not change the pose at any key. It
|
|
7
|
+
* does change what happens BETWEEN keys: the animation clip pipeline interpolates a quaternion track as four
|
|
8
|
+
* independent per-component curves (component-wise normalized-lerp), and without hemisphere alignment a pair of
|
|
9
|
+
* adjacent keys whose dot product is negative interpolates the long way around — spinning nearly 360 degrees and
|
|
10
|
+
* dipping through a near-degenerate quaternion at the midpoint. Aligning the keys first makes the component nlerp
|
|
11
|
+
* take the short arc, matching what three.js does at interpolation time via Quaternion.slerpFlat's sign flip.
|
|
12
|
+
*
|
|
13
|
+
* The input array is not mutated.
|
|
14
|
+
*
|
|
15
|
+
* @param {number[]|Float32Array|Float64Array} values flat quaternion components, 4 per key
|
|
16
|
+
* @param {number} key_count number of keyframes
|
|
17
|
+
* @returns {number[]|Float32Array|Float64Array} a copy with hemisphere-aligned keys
|
|
18
|
+
*/
|
|
19
|
+
export function hemisphere_align_quaternion_values(values, key_count) {
|
|
20
|
+
const out = values.slice();
|
|
21
|
+
|
|
22
|
+
for (let i = 1; i < key_count; i++) {
|
|
23
|
+
const p = (i - 1) * 4;
|
|
24
|
+
const c = i * 4;
|
|
25
|
+
|
|
26
|
+
const dot = out[p] * out[c] + out[p + 1] * out[c + 1] + out[p + 2] * out[c + 2] + out[p + 3] * out[c + 3];
|
|
27
|
+
|
|
28
|
+
if (dot < 0) {
|
|
29
|
+
out[c] = -out[c];
|
|
30
|
+
out[c + 1] = -out[c + 1];
|
|
31
|
+
out[c + 2] = -out[c + 2];
|
|
32
|
+
out[c + 3] = -out[c + 3];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return out;
|
|
37
|
+
}
|