@woosh/meep-engine 3.63.3 → 3.64.1
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/CHANGELOG.md +51 -0
- package/package.json +1 -1
- package/src/core/color/xyz/m3_chromatic_adaptation_bradford.d.ts +14 -0
- package/src/core/color/xyz/m3_chromatic_adaptation_bradford.d.ts.map +1 -0
- package/src/core/color/xyz/m3_chromatic_adaptation_bradford.js +51 -0
- package/src/core/math/linalg/eigen/matrix_symmetric_3x3_eigen.d.ts +2 -1
- package/src/core/math/linalg/eigen/matrix_symmetric_3x3_eigen.d.ts.map +1 -1
- package/src/core/math/linalg/eigen/matrix_symmetric_3x3_eigen.js +51 -70
- package/src/core/math/linalg/eigen/matrix_symmetric_4x4_eigen.d.ts.map +1 -1
- package/src/core/math/linalg/eigen/matrix_symmetric_4x4_eigen.js +8 -64
- package/src/core/math/linalg/eigen/matrix_symmetric_jacobi_rotate_in_place.d.ts +17 -0
- package/src/core/math/linalg/eigen/matrix_symmetric_jacobi_rotate_in_place.d.ts.map +1 -0
- package/src/core/math/linalg/eigen/matrix_symmetric_jacobi_rotate_in_place.js +64 -0
- package/src/core/math/linalg/solve_box_constrained_qp.d.ts +30 -0
- package/src/core/math/linalg/solve_box_constrained_qp.d.ts.map +1 -0
- package/src/core/math/linalg/solve_box_constrained_qp.js +205 -0
- package/src/engine/graphics/texture/sampler/exr_to_sampler2d.d.ts +27 -0
- package/src/engine/graphics/texture/sampler/exr_to_sampler2d.d.ts.map +1 -0
- package/src/engine/graphics/texture/sampler/exr_to_sampler2d.js +91 -0
- package/src/engine/graphics/texture/sampler/sampler2d_to_exr.d.ts +23 -0
- package/src/engine/graphics/texture/sampler/sampler2d_to_exr.d.ts.map +1 -0
- package/src/engine/graphics/texture/sampler/sampler2d_to_exr.js +64 -0
- package/src/engine/physics/constraint/soft_spring_coefficients.d.ts +24 -0
- package/src/engine/physics/constraint/soft_spring_coefficients.d.ts.map +1 -0
- package/src/engine/physics/constraint/soft_spring_coefficients.js +38 -0
- package/src/engine/physics/constraint/solve_constraints.d.ts.map +1 -1
- package/src/engine/physics/constraint/solve_constraints.js +16 -8
- package/src/engine/physics/ecs/PhysicsSystem.d.ts +54 -0
- package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
- package/src/engine/physics/ecs/PhysicsSystem.js +192 -7
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/engine/physics/inertia/world_inverse_inertia.d.ts +3 -5
- package/src/engine/physics/inertia/world_inverse_inertia.d.ts.map +1 -1
- package/src/engine/physics/inertia/world_inverse_inertia.js +3 -5
- package/src/engine/physics/vehicle/RaycastVehicle.d.ts +183 -12
- package/src/engine/physics/vehicle/RaycastVehicle.d.ts.map +1 -1
- package/src/engine/physics/vehicle/RaycastVehicle.js +1046 -121
- package/src/format/image/exr/ExrCompression.d.ts +22 -0
- package/src/format/image/exr/ExrCompression.d.ts.map +1 -0
- package/src/format/image/exr/ExrCompression.js +27 -0
- package/src/format/image/exr/ExrImage.d.ts +32 -0
- package/src/format/image/exr/ExrImage.d.ts.map +1 -0
- package/src/format/image/exr/ExrImage.js +32 -0
- package/src/format/image/exr/ExrPixelType.d.ts +13 -0
- package/src/format/image/exr/ExrPixelType.d.ts.map +1 -0
- package/src/format/image/exr/ExrPixelType.js +18 -0
- package/src/format/image/exr/exr_compare_names.d.ts +16 -0
- package/src/format/image/exr/exr_compare_names.d.ts.map +1 -0
- package/src/format/image/exr/exr_compare_names.js +25 -0
- package/src/format/image/exr/exr_constants.d.ts +49 -0
- package/src/format/image/exr/exr_constants.d.ts.map +1 -0
- package/src/format/image/exr/exr_constants.js +56 -0
- package/src/format/image/exr/exr_read.d.ts +32 -0
- package/src/format/image/exr/exr_read.d.ts.map +1 -0
- package/src/format/image/exr/exr_read.js +531 -0
- package/src/format/image/exr/exr_sample_bits.d.ts +16 -0
- package/src/format/image/exr/exr_sample_bits.d.ts.map +1 -0
- package/src/format/image/exr/exr_sample_bits.js +21 -0
- package/src/format/image/exr/exr_scanlines_per_chunk.d.ts +17 -0
- package/src/format/image/exr/exr_scanlines_per_chunk.d.ts.map +1 -0
- package/src/format/image/exr/exr_scanlines_per_chunk.js +31 -0
- package/src/format/image/exr/exr_write.d.ts +27 -0
- package/src/format/image/exr/exr_write.d.ts.map +1 -0
- package/src/format/image/exr/exr_write.js +378 -0
- package/src/shade/playground/probe_clipmap/index.html +5 -0
- package/src/shade/playground/probe_clipmap/main.d.ts.map +1 -1
- package/src/shade/playground/probe_clipmap/main.js +34 -1
- package/src/shade/playground/tonemap_sdr/README.md +11 -8
- package/src/shade/playground/tonemap_sdr/ToneMapCompare.js +2 -2
- package/src/shade/renderer/Renderer.d.ts +5 -6
- package/src/shade/renderer/Renderer.d.ts.map +1 -1
- package/src/shade/renderer/Renderer.js +15 -88
- package/src/shade/renderer/animation/chunk_animation_curve_evaluate_keys.d.ts +14 -0
- package/src/shade/renderer/animation/chunk_animation_curve_evaluate_keys.d.ts.map +1 -0
- package/src/shade/renderer/animation/chunk_animation_curve_evaluate_keys.js +62 -0
- package/src/shade/renderer/deferred/tonemap/ColorGrade.d.ts +158 -0
- package/src/shade/renderer/deferred/tonemap/ColorGrade.d.ts.map +1 -0
- package/src/shade/renderer/deferred/tonemap/ColorGrade.js +337 -0
- package/src/shade/renderer/deferred/tonemap/SAMPLER_TONEMAP_LUT.d.ts +9 -0
- package/src/shade/renderer/deferred/tonemap/SAMPLER_TONEMAP_LUT.d.ts.map +1 -0
- package/src/shade/renderer/deferred/tonemap/SAMPLER_TONEMAP_LUT.js +15 -0
- package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_ACES.d.ts +6 -0
- package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_ACES.d.ts.map +1 -0
- package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_ACES.js +84 -0
- package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_GT7.d.ts +10 -0
- package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_GT7.d.ts.map +1 -0
- package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_GT7.js +25 -0
- package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_NONE.d.ts +9 -0
- package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_NONE.d.ts.map +1 -0
- package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_NONE.js +20 -0
- package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_PBR_NEUTRAL.d.ts +14 -0
- package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_PBR_NEUTRAL.d.ts.map +1 -0
- package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_PBR_NEUTRAL.js +30 -0
- package/src/shade/renderer/deferred/tonemap/ToneMapOperator.d.ts +54 -0
- package/src/shade/renderer/deferred/tonemap/ToneMapOperator.d.ts.map +1 -0
- package/src/shade/renderer/deferred/tonemap/ToneMapOperator.js +63 -0
- package/src/shade/renderer/deferred/tonemap/ToneMapper.d.ts +106 -0
- package/src/shade/renderer/deferred/tonemap/ToneMapper.d.ts.map +1 -0
- package/src/shade/renderer/deferred/tonemap/ToneMapper.js +474 -0
- package/src/shade/renderer/deferred/tonemap/TonemapAces2Tables.d.ts +5 -13
- package/src/shade/renderer/deferred/tonemap/TonemapAces2Tables.d.ts.map +1 -1
- package/src/shade/renderer/deferred/tonemap/TonemapAces2Tables.js +5 -44
- package/src/shade/renderer/deferred/tonemap/TonemapDisplaySettings.d.ts +7 -25
- package/src/shade/renderer/deferred/tonemap/TonemapDisplaySettings.d.ts.map +1 -1
- package/src/shade/renderer/deferred/tonemap/TonemapDisplaySettings.js +11 -51
- package/src/shade/renderer/deferred/tonemap/m3_white_balance_rec709.d.ts +20 -0
- package/src/shade/renderer/deferred/tonemap/m3_white_balance_rec709.d.ts.map +1 -0
- package/src/shade/renderer/deferred/tonemap/m3_white_balance_rec709.js +103 -0
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_lut.d.ts +9 -0
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_lut.d.ts.map +1 -0
- package/src/shade/renderer/deferred/tonemap/{shader_tonemap_HDR_none.js → shader_tonemap_HDR_lut.js} +22 -18
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_lut.d.ts +9 -0
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_lut.d.ts.map +1 -0
- package/src/shade/renderer/deferred/tonemap/{shader_tonemap_LDR_aces.js → shader_tonemap_LDR_lut.js} +24 -24
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_lut_bake.d.ts +23 -0
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_lut_bake.d.ts.map +1 -0
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_lut_bake.js +92 -0
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_lut_sdr_from_hdr.d.ts +15 -0
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_lut_sdr_from_hdr.d.ts.map +1 -0
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_lut_sdr_from_hdr.js +73 -0
- package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +3 -3
- package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +1 -1
- package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +6 -6
- package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +1 -1
- package/src/shade/renderer/fluid/query/GPUFluidQueries.d.ts +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts +3 -15
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.js +4 -17
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts +3 -3
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.js +15 -13
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.d.ts +7 -3
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.js +28 -17
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_project.d.ts +18 -18
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_project.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_project.js +44 -48
- package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
- package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
- package/src/shade/renderer/shader/chunk/color/conversion/chunk_CRM_REC709_AP1.d.ts +22 -0
- package/src/shade/renderer/shader/chunk/color/conversion/chunk_CRM_REC709_AP1.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/color/conversion/chunk_CRM_REC709_AP1.js +62 -0
- package/src/shade/renderer/shader/chunk/color/grade/chunk_color_grade.d.ts +13 -0
- package/src/shade/renderer/shader/chunk/color/grade/chunk_color_grade.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/color/grade/chunk_color_grade.js +140 -0
- package/src/shade/renderer/shader/chunk/color/oklab/chunk_oklab_compute_max_saturation.d.ts +11 -0
- package/src/shade/renderer/shader/chunk/color/oklab/chunk_oklab_compute_max_saturation.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/color/oklab/chunk_oklab_compute_max_saturation.js +65 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/chunk_bt2390_eetf.d.ts +14 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/chunk_bt2390_eetf.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/chunk_bt2390_eetf.js +38 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_lut.d.ts +16 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_lut.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_lut.js +41 -0
- package/src/shade/renderer/shader/chunk/filter/chunk_multiscale_mean.d.ts +8 -0
- package/src/shade/renderer/shader/chunk/filter/chunk_multiscale_mean.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/filter/chunk_multiscale_mean.js +21 -3
- package/src/shade/renderer/water/query/GPUWaterQueries.d.ts +1 -1
- package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +8 -8
- package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
- package/src/shade/wgsl/emulator/WGSLLanguageCore.js +2 -0
- package/src/shade/renderer/ShadeToneMappingMode.d.ts +0 -15
- package/src/shade/renderer/ShadeToneMappingMode.d.ts.map +0 -1
- package/src/shade/renderer/ShadeToneMappingMode.js +0 -41
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR.d.ts +0 -9
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR.d.ts.map +0 -1
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR.js +0 -79
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_aces.d.ts +0 -17
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_aces.d.ts.map +0 -1
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_aces.js +0 -101
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_none.d.ts +0 -9
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_none.d.ts.map +0 -1
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_pbr_neutral.d.ts +0 -10
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_pbr_neutral.d.ts.map +0 -1
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_pbr_neutral.js +0 -80
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR.d.ts +0 -9
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR.d.ts.map +0 -1
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR.js +0 -80
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_aces.d.ts +0 -10
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_aces.d.ts.map +0 -1
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_none.d.ts +0 -9
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_none.d.ts.map +0 -1
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_none.js +0 -71
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_pbr_neutral.d.ts +0 -10
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_pbr_neutral.d.ts.map +0 -1
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_pbr_neutral.js +0 -76
- package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_hdr_bt2390.d.ts +0 -3
- package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_hdr_bt2390.d.ts.map +0 -1
- package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_hdr_bt2390.js +0 -44
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { lu_factor_linear_system } from "./lu_factor_linear_system.js";
|
|
2
|
+
import { lu_solve_linear_system } from "./lu_solve_linear_system.js";
|
|
3
|
+
|
|
4
|
+
/** Solved for, anywhere between its bounds. */
|
|
5
|
+
const FREE = 0;
|
|
6
|
+
/** Held at its lower bound. */
|
|
7
|
+
const AT_LOWER = 1;
|
|
8
|
+
/** Held at its upper bound. */
|
|
9
|
+
const AT_UPPER = 2;
|
|
10
|
+
|
|
11
|
+
// Working storage, grown to the largest system solved so far.
|
|
12
|
+
let scratch_matrix = new Float64Array(64);
|
|
13
|
+
let scratch_target = new Float64Array(8);
|
|
14
|
+
let scratch_free = new Uint32Array(8);
|
|
15
|
+
let scratch_pivot = new Uint32Array(8);
|
|
16
|
+
let scratch_state = new Uint8Array(8);
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Solve the bound-constrained quadratic program
|
|
20
|
+
*
|
|
21
|
+
* minimise ½·xᵀ·A·x − bᵀ·x subject to lo ≤ x ≤ hi
|
|
22
|
+
*
|
|
23
|
+
* for a symmetric positive-definite `A`; equivalently the box LCP: `x` within `[lo, hi]` where
|
|
24
|
+
* `w = A·x − b` is zero for every `x_i` strictly between its bounds, non-negative where `x_i = lo_i`
|
|
25
|
+
* and non-positive where `x_i = hi_i`. The solution is unique.
|
|
26
|
+
*
|
|
27
|
+
* Primal active-set method (Nocedal & Wright, *Numerical Optimization*, 2nd ed., §16.5). It starts
|
|
28
|
+
* from the point of the box nearest the origin, with every variable free. Each pass solves for the
|
|
29
|
+
* free variables with the held ones at their bounds, and steps toward that solution as far as the box
|
|
30
|
+
* allows; a variable that cuts the step short is held at the bound it reached. A full step is the
|
|
31
|
+
* minimum over the variables currently free: then the held variable whose `w` has the wrong sign by
|
|
32
|
+
* the most is freed, or, when none has, `x` is the solution. The objective falls from each such
|
|
33
|
+
* minimum to the next, so no set of held variables repeats and the search ends; it also ends where
|
|
34
|
+
* rounding stops the objective falling. When no bound is reached it is one factorisation of `A`.
|
|
35
|
+
*
|
|
36
|
+
* @param {ArrayLike<number>} A n×n, column-major (`A[j·n + i]` is row `i`, column `j`); being symmetric,
|
|
37
|
+
* row-major reads the same. Not modified.
|
|
38
|
+
* @param {ArrayLike<number>} b length n
|
|
39
|
+
* @param {ArrayLike<number>} lo lower bounds, length n; `-Infinity` where there is none
|
|
40
|
+
* @param {ArrayLike<number>} hi upper bounds, length n, none below its `lo`; `Infinity` where there is none
|
|
41
|
+
* @param {Float64Array|number[]} x receives the solution, length n
|
|
42
|
+
* @param {number} n
|
|
43
|
+
* @returns {boolean} true when solved; false when `A` did not factor as positive definite, `x` then
|
|
44
|
+
* holding the last point reached, within the bounds
|
|
45
|
+
*/
|
|
46
|
+
export function solve_box_constrained_qp(A, b, lo, hi, x, n) {
|
|
47
|
+
if (scratch_state.length < n) {
|
|
48
|
+
scratch_matrix = new Float64Array(n * n);
|
|
49
|
+
scratch_target = new Float64Array(n);
|
|
50
|
+
scratch_free = new Uint32Array(n);
|
|
51
|
+
scratch_pivot = new Uint32Array(n);
|
|
52
|
+
scratch_state = new Uint8Array(n);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const state = scratch_state;
|
|
56
|
+
|
|
57
|
+
let diagonal_max = 0;
|
|
58
|
+
|
|
59
|
+
for (let i = 0; i < n; i++) {
|
|
60
|
+
const lower = lo[i];
|
|
61
|
+
const upper = hi[i];
|
|
62
|
+
|
|
63
|
+
x[i] = lower > 0 ? lower : (upper < 0 ? upper : 0);
|
|
64
|
+
state[i] = FREE;
|
|
65
|
+
|
|
66
|
+
const d = A[i * n + i];
|
|
67
|
+
|
|
68
|
+
if (d > diagonal_max) {
|
|
69
|
+
diagonal_max = d;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (n === 0) {
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (!(diagonal_max < Infinity) || diagonal_max <= 0) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// lu_factor_linear_system refuses a pivot under an absolute 1e-12; with the largest diagonal scaled
|
|
82
|
+
// to one, that is relative to A.
|
|
83
|
+
const scale = 1 / diagonal_max;
|
|
84
|
+
|
|
85
|
+
const matrix = scratch_matrix;
|
|
86
|
+
const target = scratch_target;
|
|
87
|
+
const free = scratch_free;
|
|
88
|
+
const pivot = scratch_pivot;
|
|
89
|
+
|
|
90
|
+
let last_minimum = Infinity;
|
|
91
|
+
|
|
92
|
+
for (; ;) {
|
|
93
|
+
let free_count = 0;
|
|
94
|
+
|
|
95
|
+
for (let i = 0; i < n; i++) {
|
|
96
|
+
if (state[i] === FREE) {
|
|
97
|
+
free[free_count++] = i;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (free_count > 0) {
|
|
102
|
+
// A_FF·x_F = b_F − A_FH·x_H, with the held variables at their bounds.
|
|
103
|
+
for (let r = 0; r < free_count; r++) {
|
|
104
|
+
const i = free[r];
|
|
105
|
+
|
|
106
|
+
let rhs = b[i];
|
|
107
|
+
|
|
108
|
+
for (let j = 0; j < n; j++) {
|
|
109
|
+
if (state[j] !== FREE) {
|
|
110
|
+
rhs -= A[j * n + i] * x[j];
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
target[r] = rhs * scale;
|
|
115
|
+
|
|
116
|
+
for (let c = 0; c < free_count; c++) {
|
|
117
|
+
matrix[c * free_count + r] = A[free[c] * n + i] * scale;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (!lu_factor_linear_system(matrix, pivot, free_count)) {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
lu_solve_linear_system(matrix, pivot, target, free_count);
|
|
126
|
+
|
|
127
|
+
// The longest step toward the solution that stays inside the box.
|
|
128
|
+
let step = 1;
|
|
129
|
+
let blocking = -1;
|
|
130
|
+
let blocking_state = FREE;
|
|
131
|
+
|
|
132
|
+
for (let r = 0; r < free_count; r++) {
|
|
133
|
+
const i = free[r];
|
|
134
|
+
const t = target[r];
|
|
135
|
+
const xi = x[i];
|
|
136
|
+
|
|
137
|
+
if (t < lo[i]) {
|
|
138
|
+
const s = (xi - lo[i]) / (xi - t);
|
|
139
|
+
|
|
140
|
+
if (s < step) {
|
|
141
|
+
step = s;
|
|
142
|
+
blocking = i;
|
|
143
|
+
blocking_state = AT_LOWER;
|
|
144
|
+
}
|
|
145
|
+
} else if (t > hi[i]) {
|
|
146
|
+
const s = (hi[i] - xi) / (t - xi);
|
|
147
|
+
|
|
148
|
+
if (s < step) {
|
|
149
|
+
step = s;
|
|
150
|
+
blocking = i;
|
|
151
|
+
blocking_state = AT_UPPER;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (blocking !== -1) {
|
|
157
|
+
for (let r = 0; r < free_count; r++) {
|
|
158
|
+
const i = free[r];
|
|
159
|
+
x[i] += step * (target[r] - x[i]);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
x[blocking] = blocking_state === AT_LOWER ? lo[blocking] : hi[blocking];
|
|
163
|
+
state[blocking] = blocking_state;
|
|
164
|
+
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
for (let r = 0; r < free_count; r++) {
|
|
169
|
+
x[free[r]] = target[r];
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// x is the minimum over the free variables. Free the held variable whose multiplier
|
|
174
|
+
// w_i = (A·x − b)_i has the wrong sign by the most.
|
|
175
|
+
let objective = 0;
|
|
176
|
+
let release = -1;
|
|
177
|
+
let worst = 0;
|
|
178
|
+
|
|
179
|
+
for (let i = 0; i < n; i++) {
|
|
180
|
+
let ax = 0;
|
|
181
|
+
|
|
182
|
+
for (let j = 0; j < n; j++) {
|
|
183
|
+
ax += A[j * n + i] * x[j];
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
objective += x[i] * (0.5 * ax - b[i]);
|
|
187
|
+
|
|
188
|
+
const w = ax - b[i];
|
|
189
|
+
const s = state[i];
|
|
190
|
+
const violation = s === AT_LOWER ? -w : (s === AT_UPPER ? w : 0);
|
|
191
|
+
|
|
192
|
+
if (violation > worst) {
|
|
193
|
+
worst = violation;
|
|
194
|
+
release = i;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (release === -1 || !(objective < last_minimum)) {
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
last_minimum = objective;
|
|
203
|
+
state[release] = FREE;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decode an OpenEXR file into an RGBA sampler.
|
|
3
|
+
*
|
|
4
|
+
* R, G, B and A come from the file's channels of those names, and a luminance image — Y, with A if it
|
|
5
|
+
* has one — reads as grey. A channel the file lacks reads as 0, or as 1 for alpha; channels of other
|
|
6
|
+
* names are left out.
|
|
7
|
+
*
|
|
8
|
+
* The sampler's storage holds every sample it reads exactly: half float when every one of those channels
|
|
9
|
+
* is HALF, 32-bit unsigned integer when every one is UINT, and float when HALF and FLOAT are mixed.
|
|
10
|
+
* Unsigned integers mixed with either float type are refused, since no storage holds both exactly.
|
|
11
|
+
* Samples are copied as numbers, so every value comes through unchanged but a NaN may come back with
|
|
12
|
+
* another payload.
|
|
13
|
+
*
|
|
14
|
+
* {@link sampler2d_to_exr} names channels the way this reads them, so a four-channel sampler makes the
|
|
15
|
+
* round trip unchanged and one of fewer channels comes back as the RGBA it stands for.
|
|
16
|
+
*
|
|
17
|
+
* @param {ArrayBuffer} bytes the whole file; keep unchanged until the promise settles
|
|
18
|
+
* @returns {Promise<Sampler2D>} four channels
|
|
19
|
+
* @throws {Error} when the file has none of R, G, B and Y, or mixes unsigned integers with floats among
|
|
20
|
+
* the channels read, and wherever {@link exr_read} throws
|
|
21
|
+
*
|
|
22
|
+
* @author Alex Goldring
|
|
23
|
+
* @copyright Company Named Limited (c) 2026
|
|
24
|
+
*/
|
|
25
|
+
export function exr_to_sampler2d(bytes: ArrayBuffer): Promise<Sampler2D>;
|
|
26
|
+
import { Sampler2D } from "./Sampler2D.js";
|
|
27
|
+
//# sourceMappingURL=exr_to_sampler2d.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exr_to_sampler2d.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/texture/sampler/exr_to_sampler2d.js"],"names":[],"mappings":"AAaA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wCARW,WAAW,GACT,QAAQ,SAAS,CAAC,CA4D9B;0BAzFyB,gBAAgB"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { exr_read } from "../../../../format/image/exr/exr_read.js";
|
|
2
|
+
import { Sampler2D } from "./Sampler2D.js";
|
|
3
|
+
import { sampler2d_copy_channel_data } from "./sampler2d_copy_channel_data.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* What each RGBA channel reads as when the file lacks it: no colour, full alpha. OpenEXR's own RGBA
|
|
7
|
+
* interface fills missing channels the same way.
|
|
8
|
+
*
|
|
9
|
+
* @readonly
|
|
10
|
+
* @type {number[]}
|
|
11
|
+
*/
|
|
12
|
+
const MISSING_CHANNEL_VALUE = [0, 0, 0, 1];
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Decode an OpenEXR file into an RGBA sampler.
|
|
16
|
+
*
|
|
17
|
+
* R, G, B and A come from the file's channels of those names, and a luminance image — Y, with A if it
|
|
18
|
+
* has one — reads as grey. A channel the file lacks reads as 0, or as 1 for alpha; channels of other
|
|
19
|
+
* names are left out.
|
|
20
|
+
*
|
|
21
|
+
* The sampler's storage holds every sample it reads exactly: half float when every one of those channels
|
|
22
|
+
* is HALF, 32-bit unsigned integer when every one is UINT, and float when HALF and FLOAT are mixed.
|
|
23
|
+
* Unsigned integers mixed with either float type are refused, since no storage holds both exactly.
|
|
24
|
+
* Samples are copied as numbers, so every value comes through unchanged but a NaN may come back with
|
|
25
|
+
* another payload.
|
|
26
|
+
*
|
|
27
|
+
* {@link sampler2d_to_exr} names channels the way this reads them, so a four-channel sampler makes the
|
|
28
|
+
* round trip unchanged and one of fewer channels comes back as the RGBA it stands for.
|
|
29
|
+
*
|
|
30
|
+
* @param {ArrayBuffer} bytes the whole file; keep unchanged until the promise settles
|
|
31
|
+
* @returns {Promise<Sampler2D>} four channels
|
|
32
|
+
* @throws {Error} when the file has none of R, G, B and Y, or mixes unsigned integers with floats among
|
|
33
|
+
* the channels read, and wherever {@link exr_read} throws
|
|
34
|
+
*
|
|
35
|
+
* @author Alex Goldring
|
|
36
|
+
* @copyright Company Named Limited (c) 2026
|
|
37
|
+
*/
|
|
38
|
+
export async function exr_to_sampler2d(bytes) {
|
|
39
|
+
const { width, height, channels } = await exr_read(bytes);
|
|
40
|
+
|
|
41
|
+
const find = (name) => channels.find(channel => channel.name === name);
|
|
42
|
+
|
|
43
|
+
const alpha = find("A");
|
|
44
|
+
|
|
45
|
+
let sources = [find("R"), find("G"), find("B"), alpha];
|
|
46
|
+
|
|
47
|
+
if (sources[0] === undefined && sources[1] === undefined && sources[2] === undefined) {
|
|
48
|
+
const luminance = find("Y");
|
|
49
|
+
|
|
50
|
+
if (luminance === undefined) {
|
|
51
|
+
throw new Error(
|
|
52
|
+
`EXR: no R, G, B or Y channel to read as colour; the file has`
|
|
53
|
+
+ ` ${channels.map(channel => channel.name).join(", ")}`
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
sources = [luminance, luminance, luminance, alpha];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const read = sources.filter(source => source !== undefined);
|
|
61
|
+
|
|
62
|
+
let result;
|
|
63
|
+
|
|
64
|
+
if (read.every(source => source.data instanceof Float16Array)) {
|
|
65
|
+
result = Sampler2D.float16(4, width, height);
|
|
66
|
+
} else if (read.every(source => source.data instanceof Uint32Array)) {
|
|
67
|
+
result = Sampler2D.uint32(4, width, height);
|
|
68
|
+
} else if (read.some(source => source.data instanceof Uint32Array)) {
|
|
69
|
+
const types = [...new Set(read)]
|
|
70
|
+
.map(source => `${source.name} (${source.data instanceof Uint32Array ? "UINT" : source.data instanceof Float16Array ? "HALF" : "FLOAT"})`);
|
|
71
|
+
|
|
72
|
+
throw new Error(
|
|
73
|
+
`EXR: the channels read as colour, ${types.join(", ")}, mix unsigned integers with floats,`
|
|
74
|
+
+ ` which no sampler storage holds both of exactly`
|
|
75
|
+
);
|
|
76
|
+
} else {
|
|
77
|
+
result = Sampler2D.float32(4, width, height);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
for (let c = 0; c < 4; c++) {
|
|
81
|
+
const source = sources[c];
|
|
82
|
+
|
|
83
|
+
if (source === undefined) {
|
|
84
|
+
result.channelFill(c, MISSING_CHANNEL_VALUE[c]);
|
|
85
|
+
} else {
|
|
86
|
+
sampler2d_copy_channel_data(new Sampler2D(source.data, 1, width, height), 0, result, c);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Encode a sampler as an OpenEXR file.
|
|
3
|
+
*
|
|
4
|
+
* Channels are named the way OpenEXR names them: one channel is a luminance image, Y; two are Y and A;
|
|
5
|
+
* three are R, G and B; four are R, G, B and A. {@link exr_to_sampler2d} reads each of those back as RGBA.
|
|
6
|
+
*
|
|
7
|
+
* The sampler's storage is the pixel type: a `Float16Array` is written as HALF, a `Float32Array` as FLOAT,
|
|
8
|
+
* a `Uint32Array` as UINT. Other storage is refused rather than converted, because what its numbers mean
|
|
9
|
+
* — normalised, sRGB-encoded — is not this function's to guess; convert first, for instance with
|
|
10
|
+
* `sampler2d_srgb_u8_to_linear_f16` or `sampler2d_to_f16`. Samples are copied as numbers, so every value
|
|
11
|
+
* is written unchanged but a NaN may be written with another payload.
|
|
12
|
+
*
|
|
13
|
+
* @param {Sampler2D} sampler 1 to 4 channels
|
|
14
|
+
* @param {ExrCompression} compression see {@link exr_write}
|
|
15
|
+
* @returns {Promise<ArrayBuffer>} the whole file
|
|
16
|
+
* @throws {Error} for any other channel count, and wherever {@link exr_write} throws
|
|
17
|
+
*
|
|
18
|
+
* @author Alex Goldring
|
|
19
|
+
* @copyright Company Named Limited (c) 2026
|
|
20
|
+
*/
|
|
21
|
+
export function sampler2d_to_exr(sampler: Sampler2D, compression: ExrCompression): Promise<ArrayBuffer>;
|
|
22
|
+
import { Sampler2D } from "./Sampler2D.js";
|
|
23
|
+
//# sourceMappingURL=sampler2d_to_exr.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sampler2d_to_exr.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/texture/sampler/sampler2d_to_exr.js"],"names":[],"mappings":"AAmBA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,0CARW,SAAS,gCAEP,QAAQ,WAAW,CAAC,CA8BhC;0BA9DyB,gBAAgB"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { exr_write } from "../../../../format/image/exr/exr_write.js";
|
|
2
|
+
import { Sampler2D } from "./Sampler2D.js";
|
|
3
|
+
import { sampler2d_copy_channel_data } from "./sampler2d_copy_channel_data.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Channel names by item size, the way OpenEXR names them: luminance, luminance and alpha, colour, colour
|
|
7
|
+
* and alpha.
|
|
8
|
+
*
|
|
9
|
+
* @readonly
|
|
10
|
+
* @type {(string[]|undefined)[]}
|
|
11
|
+
*/
|
|
12
|
+
const CHANNEL_NAMES = [
|
|
13
|
+
undefined,
|
|
14
|
+
["Y"],
|
|
15
|
+
["Y", "A"],
|
|
16
|
+
["R", "G", "B"],
|
|
17
|
+
["R", "G", "B", "A"],
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Encode a sampler as an OpenEXR file.
|
|
22
|
+
*
|
|
23
|
+
* Channels are named the way OpenEXR names them: one channel is a luminance image, Y; two are Y and A;
|
|
24
|
+
* three are R, G and B; four are R, G, B and A. {@link exr_to_sampler2d} reads each of those back as RGBA.
|
|
25
|
+
*
|
|
26
|
+
* The sampler's storage is the pixel type: a `Float16Array` is written as HALF, a `Float32Array` as FLOAT,
|
|
27
|
+
* a `Uint32Array` as UINT. Other storage is refused rather than converted, because what its numbers mean
|
|
28
|
+
* — normalised, sRGB-encoded — is not this function's to guess; convert first, for instance with
|
|
29
|
+
* `sampler2d_srgb_u8_to_linear_f16` or `sampler2d_to_f16`. Samples are copied as numbers, so every value
|
|
30
|
+
* is written unchanged but a NaN may be written with another payload.
|
|
31
|
+
*
|
|
32
|
+
* @param {Sampler2D} sampler 1 to 4 channels
|
|
33
|
+
* @param {ExrCompression} compression see {@link exr_write}
|
|
34
|
+
* @returns {Promise<ArrayBuffer>} the whole file
|
|
35
|
+
* @throws {Error} for any other channel count, and wherever {@link exr_write} throws
|
|
36
|
+
*
|
|
37
|
+
* @author Alex Goldring
|
|
38
|
+
* @copyright Company Named Limited (c) 2026
|
|
39
|
+
*/
|
|
40
|
+
export async function sampler2d_to_exr(sampler, compression) {
|
|
41
|
+
const width = sampler.width;
|
|
42
|
+
const height = sampler.height;
|
|
43
|
+
const item_size = sampler.itemSize;
|
|
44
|
+
|
|
45
|
+
const names = CHANNEL_NAMES[item_size];
|
|
46
|
+
|
|
47
|
+
if (names === undefined) {
|
|
48
|
+
throw new Error(`EXR: a sampler of ${item_size} channels has no OpenEXR naming; 1 to 4 channels do`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const storage = sampler.data.constructor;
|
|
52
|
+
|
|
53
|
+
const channels = new Array(item_size);
|
|
54
|
+
|
|
55
|
+
for (let c = 0; c < item_size; c++) {
|
|
56
|
+
const plane = new Sampler2D(new storage(width * height), 1, width, height);
|
|
57
|
+
|
|
58
|
+
sampler2d_copy_channel_data(sampler, c, plane, 0);
|
|
59
|
+
|
|
60
|
+
channels[c] = { name: names[c], data: plane.data };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return exr_write({ width, height, channels }, compression);
|
|
64
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coefficients of a spring-damper solved as a soft velocity constraint over a step `h` (Catto, "Soft
|
|
3
|
+
* Constraints", GDC 2011). For a row with Jacobian `J`, position `C` (zero at the spring's rest) and
|
|
4
|
+
* impulse `λ`, the constraint
|
|
5
|
+
*
|
|
6
|
+
* J·v⁺ + β·C + γ·λ = 0, β = k / (c + h·k), γ = 1 / (h·(c + h·k))
|
|
7
|
+
*
|
|
8
|
+
* is backward Euler for the spring force `−k·C − c·J·v`: its impulse is `λ = −h·(k·C⁺ + c·J·v⁺)`, with
|
|
9
|
+
* `C⁺ = C + h·J·v⁺` the position the step ends at. It is stable for every `k, c ≥ 0` and `h > 0`.
|
|
10
|
+
* `γ` is the row's compliance, added to its effective-mass denominator; `β` turns `C` into the
|
|
11
|
+
* velocity the spring restores at.
|
|
12
|
+
*
|
|
13
|
+
* Reads `[k, c, h]` from `params` and writes `[γ, β]` to `out`. The numbers travel in arrays because a
|
|
14
|
+
* number handed to a call V8 does not inline is boxed into a new heap object.
|
|
15
|
+
*
|
|
16
|
+
* @param {Float64Array|number[]} out receives `γ` at `out_offset` and `β` after it
|
|
17
|
+
* @param {number} out_offset
|
|
18
|
+
* @param {Float64Array|number[]} params stiffness `k` (N/m, or N·m/rad for an angular row), damping `c`
|
|
19
|
+
* (N·s/m, or N·m·s/rad) and step `h` (seconds), from `params_offset`
|
|
20
|
+
* @param {number} params_offset
|
|
21
|
+
* @returns {boolean} false, writing nothing, when the spring is inert: no stiffness and no damping
|
|
22
|
+
*/
|
|
23
|
+
export function soft_spring_coefficients(out: Float64Array | number[], out_offset: number, params: Float64Array | number[], params_offset: number): boolean;
|
|
24
|
+
//# sourceMappingURL=soft_spring_coefficients.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"soft_spring_coefficients.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/constraint/soft_spring_coefficients.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,8CAPW,YAAY,GAAC,MAAM,EAAE,cACrB,MAAM,UACN,YAAY,GAAC,MAAM,EAAE,iBAErB,MAAM,GACJ,OAAO,CAiBnB"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coefficients of a spring-damper solved as a soft velocity constraint over a step `h` (Catto, "Soft
|
|
3
|
+
* Constraints", GDC 2011). For a row with Jacobian `J`, position `C` (zero at the spring's rest) and
|
|
4
|
+
* impulse `λ`, the constraint
|
|
5
|
+
*
|
|
6
|
+
* J·v⁺ + β·C + γ·λ = 0, β = k / (c + h·k), γ = 1 / (h·(c + h·k))
|
|
7
|
+
*
|
|
8
|
+
* is backward Euler for the spring force `−k·C − c·J·v`: its impulse is `λ = −h·(k·C⁺ + c·J·v⁺)`, with
|
|
9
|
+
* `C⁺ = C + h·J·v⁺` the position the step ends at. It is stable for every `k, c ≥ 0` and `h > 0`.
|
|
10
|
+
* `γ` is the row's compliance, added to its effective-mass denominator; `β` turns `C` into the
|
|
11
|
+
* velocity the spring restores at.
|
|
12
|
+
*
|
|
13
|
+
* Reads `[k, c, h]` from `params` and writes `[γ, β]` to `out`. The numbers travel in arrays because a
|
|
14
|
+
* number handed to a call V8 does not inline is boxed into a new heap object.
|
|
15
|
+
*
|
|
16
|
+
* @param {Float64Array|number[]} out receives `γ` at `out_offset` and `β` after it
|
|
17
|
+
* @param {number} out_offset
|
|
18
|
+
* @param {Float64Array|number[]} params stiffness `k` (N/m, or N·m/rad for an angular row), damping `c`
|
|
19
|
+
* (N·s/m, or N·m·s/rad) and step `h` (seconds), from `params_offset`
|
|
20
|
+
* @param {number} params_offset
|
|
21
|
+
* @returns {boolean} false, writing nothing, when the spring is inert: no stiffness and no damping
|
|
22
|
+
*/
|
|
23
|
+
export function soft_spring_coefficients(out, out_offset, params, params_offset) {
|
|
24
|
+
const stiffness = params[params_offset];
|
|
25
|
+
const damping = params[params_offset + 1];
|
|
26
|
+
const h = params[params_offset + 2];
|
|
27
|
+
|
|
28
|
+
const denom = damping + h * stiffness;
|
|
29
|
+
|
|
30
|
+
if (denom <= 0) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
out[out_offset] = 1 / (h * denom);
|
|
35
|
+
out[out_offset + 1] = stiffness / denom;
|
|
36
|
+
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"solve_constraints.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/constraint/solve_constraints.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"solve_constraints.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/constraint/solve_constraints.js"],"names":[],"mappings":"AA86BA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qCAXW,OAAO,iCAEP,MAAM,SAEN,MAAM,YAGN,OAAO,QAgCjB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qCAJW,OAAO,mCAEP,OAAO,QAgBjB"}
|
|
@@ -27,6 +27,7 @@ import { JOINT_WORLD } from "../ecs/Joint.js";
|
|
|
27
27
|
import { SleepState } from "../ecs/SleepState.js";
|
|
28
28
|
import { angular_effective_mass_array, world_inverse_inertia_apply_array } from "../inertia/world_inverse_inertia.js";
|
|
29
29
|
import { DofMode } from "./DofMode.js";
|
|
30
|
+
import { soft_spring_coefficients } from "./soft_spring_coefficients.js";
|
|
30
31
|
|
|
31
32
|
/**
|
|
32
33
|
* # 6-DOF constraint (joint) solver
|
|
@@ -150,6 +151,10 @@ const scratch_rel = new Float64Array(8);
|
|
|
150
151
|
const scratch_ang_err = new Float64Array(3);
|
|
151
152
|
/** One row's effective-mass denominator, body A's part at 0 and body B's at 1. */
|
|
152
153
|
const scratch_keff = new Float64Array(2);
|
|
154
|
+
/** A SPRING row's stiffness, damping and substep, for {@link soft_spring_coefficients}. */
|
|
155
|
+
const scratch_spring_params = new Float64Array(3);
|
|
156
|
+
/** A SPRING row's compliance `γ` at 0 and bias rate `β` at 1, from {@link soft_spring_coefficients}. */
|
|
157
|
+
const scratch_spring = new Float64Array(2);
|
|
153
158
|
|
|
154
159
|
// The numbers {@link fill_row} is given for one DOF, at these offsets in `scratch_dof`. They are computed
|
|
155
160
|
// per row, and a computed number handed to a call that is not inlined (fill_row is past V8's inlining
|
|
@@ -459,8 +464,8 @@ function invert_sym3(K, out) {
|
|
|
459
464
|
*
|
|
460
465
|
* A spring drives the DOF position toward zero with stiffness `k` (N/m or
|
|
461
466
|
* N·m/rad) and damping `c`, as a *regularised* row rather than a hard one. The
|
|
462
|
-
* implicit-Euler soft constraint (Catto, "Soft Constraints"
|
|
463
|
-
* `h`, with `denom = c + h·k`:
|
|
467
|
+
* implicit-Euler soft constraint (Catto, "Soft Constraints";
|
|
468
|
+
* {@link soft_spring_coefficients}) gives, per substep `h`, with `denom = c + h·k`:
|
|
464
469
|
* `γ = 1 / (h·denom)` the compliance / regularisation (inverse mass),
|
|
465
470
|
* `bias = (k/denom)·C` the restoring velocity, and a softened effective
|
|
466
471
|
* `effMass = 1/(K + γ)` mass — so the row solves
|
|
@@ -554,14 +559,17 @@ function fill_row(joint, dofIndex, dof, spook_locked, spook_spec, dt_sub, out, o
|
|
|
554
559
|
}
|
|
555
560
|
if (mode === DofMode.SPRING) {
|
|
556
561
|
if (keff === 0) { imp[dofIndex] = 0; return false; }
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
if (
|
|
561
|
-
|
|
562
|
+
scratch_spring_params[0] = joint.dofStiffness[dofIndex];
|
|
563
|
+
scratch_spring_params[1] = joint.dofDamping[dofIndex];
|
|
564
|
+
scratch_spring_params[2] = dt_sub;
|
|
565
|
+
if (!soft_spring_coefficients(scratch_spring, 0, scratch_spring_params, 0)) {
|
|
566
|
+
imp[dofIndex] = 0; // inert (no k, no c)
|
|
567
|
+
return false;
|
|
568
|
+
}
|
|
569
|
+
const gamma = scratch_spring[0];
|
|
562
570
|
out[o + ROW_EFF] = 1 / (keff + gamma);
|
|
563
571
|
// restoring velocity toward pos = 0
|
|
564
|
-
out[o + ROW_BIAS] = out[o + ROW_RELAX_BIAS] =
|
|
572
|
+
out[o + ROW_BIAS] = out[o + ROW_RELAX_BIAS] = scratch_spring[1] * pos;
|
|
565
573
|
out[o + ROW_CLAMP_LO] = -Infinity;
|
|
566
574
|
out[o + ROW_CLAMP_HI] = Infinity;
|
|
567
575
|
out[o + ROW_GAMMA] = gamma;
|
|
@@ -704,6 +704,60 @@ export class PhysicsSystem extends System<any> {
|
|
|
704
704
|
* @param {Vector3|ArrayLike<number>} force indexed as [x, y, z]
|
|
705
705
|
*/
|
|
706
706
|
applyForce(rigidBody: RigidBody, force: Vector3 | ArrayLike<number>): void;
|
|
707
|
+
/**
|
|
708
|
+
* The mean velocity a body will have across the next {@link fixedUpdate}`(dt)` under what already
|
|
709
|
+
* acts on it: gravity, its damping, and the force and torque accumulated so far, with no contact or
|
|
710
|
+
* joint. Its displacement over that step is this times `dt`.
|
|
711
|
+
*
|
|
712
|
+
* The accumulated force and torque are spent before the substeps, as is an impulse applied before
|
|
713
|
+
* the step ({@link applyImpulseAt}): the mean keeps {@link predictStepMeanVelocityShare} of the
|
|
714
|
+
* velocity change each makes, all of it on a body nothing damps. Gravity enters at each of the `N`
|
|
715
|
+
* {@link substeps}: it adds `gravity·gravityScale·dt` to an undamped body's end velocity, but only
|
|
716
|
+
* `(N + 1)/(2N)` of that to its mean. A damping above 0 decays the velocity at each substep by
|
|
717
|
+
* `k = 1/(1 + damping·dt/N)`, so the mean keeps `(1/N)·Σᵢ kⁱ` of the velocity the substeps start
|
|
718
|
+
* from and `(1/N²)·Σᵢ Σⱼ₌₁…ᵢ kʲ` of the step's gravity, `i = 1…N`; the angular velocity decays the
|
|
719
|
+
* same way at the angular damping. A controller that works out its impulses from where the coming
|
|
720
|
+
* step will carry the body predicts that motion with this.
|
|
721
|
+
*
|
|
722
|
+
* A body that is not Dynamic is predicted to keep its velocity, as a kinematic body moving at the
|
|
723
|
+
* velocity it carries does. A KinematicPosition body given a target for the step
|
|
724
|
+
* ({@link setTargetPose}) takes the velocity that reaches the target instead, and a Static body does
|
|
725
|
+
* not move.
|
|
726
|
+
*
|
|
727
|
+
* @param {Float64Array|number[]} linear receives the mean linear velocity, indexed as [x, y, z]
|
|
728
|
+
* @param {Float64Array|number[]} angular receives the mean angular velocity, indexed as [x, y, z]
|
|
729
|
+
* @param {RigidBody} rigidBody
|
|
730
|
+
* @param {Transform64} transform the body's world transform
|
|
731
|
+
* @param {number} dt seconds, the step the next fixedUpdate takes
|
|
732
|
+
*/
|
|
733
|
+
predictStepMeanVelocity(linear: Float64Array | number[], angular: Float64Array | number[], rigidBody: RigidBody, transform: Transform64, dt: number): void;
|
|
734
|
+
/**
|
|
735
|
+
* How much of a change to a body's velocity, made before the next {@link fixedUpdate}`(dt)`, its mean
|
|
736
|
+
* velocity across that step keeps, with no contact or joint: `out[0]` of a change to its linear
|
|
737
|
+
* velocity, `out[1]` of one to its angular velocity. An impulse applied before the step
|
|
738
|
+
* ({@link applyImpulseAt}) moves the {@link predictStepMeanVelocity} by these times the velocity
|
|
739
|
+
* change it makes. A controller that solves for impulses against that motion takes their effect on
|
|
740
|
+
* it from these.
|
|
741
|
+
*
|
|
742
|
+
* A damping above 0 decays the velocity at each of the `N` {@link substeps} by
|
|
743
|
+
* `k = 1/(1 + damping·dt/N)`, so the mean keeps `(1/N)·Σᵢ₌₁…ₙ kⁱ` of a change: 1 for a body nothing
|
|
744
|
+
* damps, less the more it is damped and the longer the step. A body that is not Dynamic: 1 and 1,
|
|
745
|
+
* nothing damps it — as {@link predictStepMeanVelocity} predicts it to keep its velocity, with the
|
|
746
|
+
* same exceptions.
|
|
747
|
+
*
|
|
748
|
+
* @param {Float64Array|number[]} out receives the linear share at [0] and the angular share at [1]
|
|
749
|
+
* @param {RigidBody} rigidBody
|
|
750
|
+
* @param {number} dt seconds, the step the next fixedUpdate takes
|
|
751
|
+
*/
|
|
752
|
+
predictStepMeanVelocityShare(out: Float64Array | number[], rigidBody: RigidBody, dt: number): void;
|
|
753
|
+
/**
|
|
754
|
+
* The number of substeps {@link fixedUpdate} divides a step into: {@link substeps}, truncated, and 1
|
|
755
|
+
* for anything below 2 — a count of 0, negative or fractional would make the substep `dt / N`
|
|
756
|
+
* infinite and the loop bound meaningless.
|
|
757
|
+
* @private
|
|
758
|
+
* @returns {number}
|
|
759
|
+
*/
|
|
760
|
+
private __substep_count;
|
|
707
761
|
/**
|
|
708
762
|
* Replace the linear velocity. Wakes the body if asleep.
|
|
709
763
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PhysicsSystem.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/ecs/PhysicsSystem.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"PhysicsSystem.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/ecs/PhysicsSystem.js"],"names":[],"mappings":"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"}
|