@woosh/meep-engine 3.44.0 → 3.45.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-terrain.js +1 -1
- package/package.json +1 -1
- package/src/core/collection/array/array_sort_insertion_ascending.d.ts +19 -0
- package/src/core/collection/array/array_sort_insertion_ascending.d.ts.map +1 -0
- package/src/core/collection/array/array_sort_insertion_ascending.js +31 -0
- package/src/core/geom/3d/aabb/aabb3_array_round_outward_f32.d.ts +27 -0
- package/src/core/geom/3d/aabb/aabb3_array_round_outward_f32.d.ts.map +1 -0
- package/src/core/geom/3d/aabb/aabb3_array_round_outward_f32.js +39 -0
- package/src/core/geom/3d/aabb/aabb3_from_v3_array.d.ts.map +1 -1
- package/src/core/geom/3d/aabb/aabb3_from_v3_array.js +4 -1
- package/src/core/geom/3d/aabb/aabb3_transform_oriented.d.ts +2 -2
- package/src/core/geom/3d/aabb/aabb3_transform_oriented.d.ts.map +1 -1
- package/src/core/geom/3d/aabb/aabb3_transform_oriented.js +1 -1
- package/src/core/geom/3d/pose/pose3_apply_inverse_point_array.d.ts +21 -0
- package/src/core/geom/3d/pose/pose3_apply_inverse_point_array.d.ts.map +1 -0
- package/src/core/geom/3d/pose/pose3_apply_inverse_point_array.js +36 -0
- package/src/core/geom/3d/pose/pose3_apply_point_array.d.ts +25 -0
- package/src/core/geom/3d/pose/pose3_apply_point_array.d.ts.map +1 -0
- package/src/core/geom/3d/pose/pose3_apply_point_array.js +40 -0
- package/src/core/geom/3d/pose/pose3_compose_array.d.ts +28 -0
- package/src/core/geom/3d/pose/pose3_compose_array.d.ts.map +1 -0
- package/src/core/geom/3d/pose/pose3_compose_array.js +41 -0
- package/src/core/geom/3d/pose/pose3_to_local_array.d.ts +29 -0
- package/src/core/geom/3d/pose/pose3_to_local_array.d.ts.map +1 -0
- package/src/core/geom/3d/pose/pose3_to_local_array.js +42 -0
- package/src/core/geom/3d/quaternion/quat3_clamp_angle_array.d.ts +28 -0
- package/src/core/geom/3d/quaternion/quat3_clamp_angle_array.d.ts.map +1 -0
- package/src/core/geom/3d/quaternion/quat3_clamp_angle_array.js +66 -0
- package/src/core/geom/3d/quaternion/quat3_multiply_conjugate_left_array.d.ts +22 -0
- package/src/core/geom/3d/quaternion/quat3_multiply_conjugate_left_array.d.ts.map +1 -0
- package/src/core/geom/3d/quaternion/quat3_multiply_conjugate_left_array.js +30 -0
- package/src/core/geom/3d/quaternion/quat3_multiply_conjugate_right_array.d.ts +23 -0
- package/src/core/geom/3d/quaternion/quat3_multiply_conjugate_right_array.d.ts.map +1 -0
- package/src/core/geom/3d/quaternion/quat3_multiply_conjugate_right_array.js +31 -0
- package/src/core/geom/3d/triangle/tri3_compute_normal_area_weighted_array.d.ts +26 -0
- package/src/core/geom/3d/triangle/tri3_compute_normal_area_weighted_array.d.ts.map +1 -0
- package/src/core/geom/3d/triangle/tri3_compute_normal_area_weighted_array.js +46 -0
- package/src/core/geom/vec3/v3_distance_array.d.ts +11 -0
- package/src/core/geom/vec3/v3_distance_array.d.ts.map +1 -0
- package/src/core/geom/vec3/v3_distance_array.js +19 -0
- package/src/core/geom/vec3/v3_normalize_array_checked.d.ts +23 -0
- package/src/core/geom/vec3/v3_normalize_array_checked.d.ts.map +1 -0
- package/src/core/geom/vec3/v3_normalize_array_checked.js +49 -0
- package/src/core/geom/vec3/v3_reject_array.d.ts +15 -0
- package/src/core/geom/vec3/v3_reject_array.d.ts.map +1 -0
- package/src/core/geom/vec3/v3_reject_array.js +32 -0
- package/src/core/graph/csr/csr_build_incidence.d.ts +26 -0
- package/src/core/graph/csr/csr_build_incidence.d.ts.map +1 -0
- package/src/core/graph/csr/csr_build_incidence.js +71 -0
- package/src/core/graph/csr/csr_graph_color_greedy.d.ts +25 -0
- package/src/core/graph/csr/csr_graph_color_greedy.d.ts.map +1 -0
- package/src/core/graph/csr/csr_graph_color_greedy.js +83 -0
- package/src/core/graph/csr/csr_graph_validate_coloring.d.ts +15 -0
- package/src/core/graph/csr/csr_graph_validate_coloring.d.ts.map +1 -0
- package/src/core/graph/csr/csr_graph_validate_coloring.js +33 -0
- package/src/core/math/linalg/matrix_symmetric_3x3_solve_ldlt.d.ts +26 -0
- package/src/core/math/linalg/matrix_symmetric_3x3_solve_ldlt.d.ts.map +1 -0
- package/src/core/math/linalg/matrix_symmetric_3x3_solve_ldlt.js +71 -0
- package/src/core/math/max2_exact.d.ts +15 -0
- package/src/core/math/max2_exact.d.ts.map +1 -0
- package/src/core/math/max2_exact.js +30 -0
- package/src/core/math/min2_exact.d.ts +20 -0
- package/src/core/math/min2_exact.d.ts.map +1 -0
- package/src/core/math/min2_exact.js +35 -0
- package/src/engine/ecs/ik/IKGoalSystem.d.ts.map +1 -1
- package/src/engine/ecs/ik/IKGoalSystem.js +3 -19
- package/src/engine/ecs/parent/parent_entity_model_of.d.ts +17 -0
- package/src/engine/ecs/parent/parent_entity_model_of.d.ts.map +1 -0
- package/src/engine/ecs/parent/parent_entity_model_of.js +26 -0
- package/src/engine/ecs/transform/t64_read_pose_array.d.ts +15 -0
- package/src/engine/ecs/transform/t64_read_pose_array.d.ts.map +1 -0
- package/src/engine/ecs/transform/t64_read_pose_array.js +24 -0
- package/src/engine/graphics/geometry/geometry_construct_triangle_normal_area_weighted.d.ts +2 -0
- package/src/engine/graphics/geometry/geometry_construct_triangle_normal_area_weighted.d.ts.map +1 -1
- package/src/engine/graphics/geometry/geometry_construct_triangle_normal_area_weighted.js +10 -21
- package/src/engine/graphics3/AnimationGraphSystem.d.ts +5 -0
- package/src/engine/graphics3/AnimationGraphSystem.d.ts.map +1 -1
- package/src/engine/graphics3/AnimationGraphSystem.js +48 -2
- package/src/engine/graphics3/AnimationSystem.d.ts +5 -0
- package/src/engine/graphics3/AnimationSystem.d.ts.map +1 -1
- package/src/engine/graphics3/AnimationSystem.js +47 -2
- package/src/engine/graphics3/register_clips.d.ts +29 -0
- package/src/engine/graphics3/register_clips.d.ts.map +1 -1
- package/src/engine/graphics3/register_clips.js +52 -0
- package/src/engine/physics/broadphase/compute_fat_world_aabb.d.ts +9 -0
- package/src/engine/physics/broadphase/compute_fat_world_aabb.d.ts.map +1 -1
- package/src/engine/physics/broadphase/compute_fat_world_aabb.js +3 -1
- package/src/engine/physics/cloth/PLAN.md +10 -8
- package/src/engine/physics/cloth/build/cloth_bind_in_frame.d.ts +22 -0
- package/src/engine/physics/cloth/build/cloth_bind_in_frame.d.ts.map +1 -1
- package/src/engine/physics/cloth/build/cloth_bind_in_frame.js +51 -19
- package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts.map +1 -1
- package/src/engine/physics/cloth/build/cloth_proxy_from_joints.js +16 -2
- package/src/engine/physics/cloth/build/cloth_proxy_from_mesh.d.ts.map +1 -1
- package/src/engine/physics/cloth/build/cloth_proxy_from_mesh.js +19 -24
- package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts +7 -0
- package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts.map +1 -1
- package/src/engine/physics/cloth/collider/ClothColliderIndex.js +85 -67
- package/src/engine/physics/cloth/collider/cloth_collider_bounds.d.ts.map +1 -1
- package/src/engine/physics/cloth/collider/cloth_collider_bounds.js +19 -101
- package/src/engine/physics/cloth/collider/cloth_collider_pack.d.ts +2 -5
- package/src/engine/physics/cloth/collider/cloth_collider_pack.d.ts.map +1 -1
- package/src/engine/physics/cloth/collider/cloth_collider_pack.js +7 -15
- package/src/engine/physics/cloth/collider/cloth_collider_sdf.d.ts.map +1 -1
- package/src/engine/physics/cloth/collider/cloth_collider_sdf.js +16 -61
- package/src/engine/physics/cloth/ecs/ClothColliderFlags.d.ts +0 -1
- package/src/engine/physics/cloth/ecs/ClothColliderFlags.js +6 -19
- package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts +1 -2
- package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothColliderSystem.js +3 -12
- package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothWorld.js +40 -130
- package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_build_rows.js +17 -58
- package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_dynamics_map.js +3 -3
- package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_gather_colliders.js +44 -104
- package/src/engine/physics/cloth/ecs/cloth_geodesic.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_geodesic.js +6 -13
- package/src/engine/physics/cloth/ecs/cloth_holds.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_holds.js +15 -40
- package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.js +45 -79
- package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_seed_subtree.js +7 -27
- package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_write_back.js +30 -62
- package/src/engine/physics/cloth/playground/cloth_playground_build.d.ts.map +1 -1
- package/src/engine/physics/cloth/playground/cloth_playground_build.js +2 -3
- package/src/engine/physics/cloth/playground/collide_main.js +2 -28
- package/src/engine/physics/cloth/playground/garment_main.js +4 -19
- package/src/engine/physics/cloth/playground/main.js +6 -48
- package/src/engine/physics/cloth/playground/rig_main.js +947 -955
- package/src/engine/physics/cloth/playground/wind_main.js +8 -7
- package/src/engine/physics/cloth/solver/ClothState.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/ClothState.js +16 -76
- package/src/engine/physics/cloth/solver/cloth_color_particles.d.ts +10 -8
- package/src/engine/physics/cloth/solver/cloth_color_particles.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/cloth_color_particles.js +30 -102
- package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/cloth_contact_find.js +3 -2
- package/src/engine/physics/cloth/solver/cloth_hold_line.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/cloth_hold_line.js +2 -14
- package/src/engine/physics/cloth/solver/cloth_kinetic_energy.d.ts +21 -0
- package/src/engine/physics/cloth/solver/cloth_kinetic_energy.d.ts.map +1 -0
- package/src/engine/physics/cloth/solver/cloth_kinetic_energy.js +45 -0
- package/src/engine/physics/cloth/solver/cloth_particle_coupling.d.ts +32 -0
- package/src/engine/physics/cloth/solver/cloth_particle_coupling.d.ts.map +1 -0
- package/src/engine/physics/cloth/solver/cloth_particle_coupling.js +133 -0
- package/src/engine/physics/cloth/solver/cloth_particle_of_source.d.ts +16 -0
- package/src/engine/physics/cloth/solver/cloth_particle_of_source.d.ts.map +1 -0
- package/src/engine/physics/cloth/solver/cloth_particle_of_source.js +19 -0
- package/src/engine/physics/cloth/solver/cloth_self_find.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/cloth_self_find.js +6 -55
- package/src/engine/physics/cloth/solver/cloth_solve_vertex.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/cloth_solve_vertex.js +30 -65
- package/src/engine/physics/cloth/solver/cloth_step.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/cloth_step.js +6 -28
- package/src/engine/physics/cloth/solver/cloth_step_instance.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/cloth_step_instance.js +2 -3
- package/src/engine/physics/cloth/solver/cloth_stretch_residual.d.ts +21 -0
- package/src/engine/physics/cloth/solver/cloth_stretch_residual.d.ts.map +1 -0
- package/src/engine/physics/cloth/solver/cloth_stretch_residual.js +54 -0
- package/src/engine/physics/cloth/solver/cloth_vertex_accumulator.d.ts +15 -0
- package/src/engine/physics/cloth/solver/cloth_vertex_accumulator.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/cloth_vertex_accumulator.js +28 -0
- package/src/engine/physics/cloth/solver/cloth_worst_tether_ratio.d.ts +30 -0
- package/src/engine/physics/cloth/solver/cloth_worst_tether_ratio.d.ts.map +1 -0
- package/src/engine/physics/cloth/solver/cloth_worst_tether_ratio.js +56 -0
- package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.js +3 -17
- package/src/engine/physics/cloth/wind/ClothFluidWind.d.ts +2 -1
- package/src/engine/physics/cloth/wind/ClothFluidWind.d.ts.map +1 -1
- package/src/engine/physics/cloth/wind/ClothFluidWind.js +7 -25
- package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts +3 -1
- package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts.map +1 -1
- package/src/engine/physics/cloth/wind/cloth_sample_air.js +40 -62
- package/src/engine/physics/ecs/ContactProbeSystem.d.ts.map +1 -1
- package/src/engine/physics/ecs/ContactProbeSystem.js +2 -18
- package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
- package/src/engine/physics/ecs/PhysicsSystem.js +9 -50
- package/src/engine/physics/fluid/ecs/fluid_sample_domain_bounds.d.ts +24 -0
- package/src/engine/physics/fluid/ecs/fluid_sample_domain_bounds.d.ts.map +1 -0
- package/src/engine/physics/fluid/ecs/fluid_sample_domain_bounds.js +42 -0
- package/src/engine/physics/fluid/ecs/fluid_sample_velocity_world_mps.d.ts +25 -0
- package/src/engine/physics/fluid/ecs/fluid_sample_velocity_world_mps.d.ts.map +1 -0
- package/src/engine/physics/fluid/ecs/fluid_sample_velocity_world_mps.js +40 -0
- package/src/engine/physics/inverse_kinematics/frame_fabrik/frame_fabrik_solve.d.ts.map +1 -1
- package/src/engine/physics/inverse_kinematics/frame_fabrik/frame_fabrik_solve.js +40 -90
- package/src/engine/physics/narrowphase/capsule_contacts.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/capsule_contacts.js +3 -5
- package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.js +2 -14
- package/src/engine/physics/narrowphase/hull_sphere_contact.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/hull_sphere_contact.js +2 -5
- package/src/engine/physics/narrowphase/narrowphase_step.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/narrowphase_step.js +13 -32
- package/src/engine/physics/narrowphase/sphere_box_contact.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/sphere_box_contact.js +2 -5
- package/src/format/texture/basis/transcode/etc1s_to_astc.d.ts.map +1 -1
- package/src/format/texture/basis/transcode/etc1s_to_astc.js +2 -1
- package/src/shade/playground/image_decode_bench/main.js +2 -1
- package/src/shade/playground/skinned_blas_refit/diff_traced_against_rasterized.d.ts.map +1 -1
- package/src/shade/playground/skinned_blas_refit/diff_traced_against_rasterized.js +2 -1
- package/src/shade/playground/skinned_mesh_soup/verify_clone_vertices.d.ts.map +1 -1
- package/src/shade/playground/skinned_mesh_soup/verify_clone_vertices.js +2 -1
- package/src/shade/playground/ssr_variance/statistics.d.ts.map +1 -1
- package/src/shade/playground/ssr_variance/statistics.js +2 -1
- package/src/shade/playground/texture_encode/main.d.ts.map +1 -1
- package/src/shade/playground/texture_encode/main.js +2 -1
- package/src/shade/playground/volumetrics_froxel/measure.d.ts.map +1 -1
- package/src/shade/playground/volumetrics_froxel/measure.js +2 -1
- package/src/shade/renderer/buffer/table/gpu_database_check_links.d.ts.map +1 -1
- package/src/shade/renderer/buffer/table/gpu_database_check_links.js +2 -1
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_group_step.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_group_step.js +3 -2
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_leaf_frontier.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_leaf_frontier.js +2 -1
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_partition_into_groups.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_partition_into_groups.js +2 -1
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_run_round.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_run_round.js +2 -1
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_try_repack.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_try_repack.js +3 -2
- package/src/shade/renderer/geometry/virtual/build/partition/vgeo_graph_components.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/partition/vgeo_graph_components.js +2 -1
- package/src/shade/renderer/geometry/virtual/build/partition/vgeo_split_face_set_packed.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/partition/vgeo_split_face_set_packed.js +2 -1
- package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.js +3 -2
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_extract.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_extract.js +3 -2
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { assert } from "../../../../core/assert.js";
|
|
2
|
+
import { csr_build_incidence } from "../../../../core/graph/csr/csr_build_incidence.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The particle graph a cloth's rows imply: an edge between every two particles
|
|
6
|
+
* that share a row, as a sorted CSR adjacency.
|
|
7
|
+
*
|
|
8
|
+
* A stretch row couples its two endpoints; a bend stencil couples all six pairs
|
|
9
|
+
* of its four particles, since every one of them appears in the same row. Two
|
|
10
|
+
* build-time consumers want exactly this set — the colouring, where an edge is
|
|
11
|
+
* a pair that must not be updated at once (`cloth_color_particles.js`), and the
|
|
12
|
+
* self-collision exclusions, where it is a pair a row already governs
|
|
13
|
+
* (`cloth_self_find.js`) — and this is the one place it is built.
|
|
14
|
+
*
|
|
15
|
+
* The set is deduplicated, because a garment adds every hinge's shared edge
|
|
16
|
+
* once as a stretch row and again as a bend pair, so duplicates are the common
|
|
17
|
+
* case; and a row that names one particle twice couples nothing. Each particle's
|
|
18
|
+
* partners come out ascending, which is the contract the exclusion scans read.
|
|
19
|
+
*
|
|
20
|
+
* Build-time only: it allocates its result and a scratch the size of the
|
|
21
|
+
* half-edge list.
|
|
22
|
+
*
|
|
23
|
+
* @param {number} particle_count
|
|
24
|
+
* @param {Int32Array|number[]} stretch_particle particle index pairs, 2 per row
|
|
25
|
+
* @param {number} stretch_count
|
|
26
|
+
* @param {Int32Array|number[]} bend_particle particle index quads, 4 per row
|
|
27
|
+
* @param {number} bend_count
|
|
28
|
+
* @returns {{offset: Int32Array, partner: Int32Array}} `partner[offset[i] .. offset[i + 1])` are the
|
|
29
|
+
* particles sharing a row with `i`, ascending, without `i` itself
|
|
30
|
+
*/
|
|
31
|
+
export function cloth_particle_coupling(
|
|
32
|
+
particle_count,
|
|
33
|
+
stretch_particle, stretch_count,
|
|
34
|
+
bend_particle, bend_count
|
|
35
|
+
) {
|
|
36
|
+
assert.isNonNegativeInteger(particle_count, 'particle_count');
|
|
37
|
+
assert.isNonNegativeInteger(stretch_count, 'stretch_count');
|
|
38
|
+
assert.isNonNegativeInteger(bend_count, 'bend_count');
|
|
39
|
+
|
|
40
|
+
// Both directions of every coupled pair, duplicates and all.
|
|
41
|
+
const capacity = stretch_count * 2 + bend_count * 12;
|
|
42
|
+
|
|
43
|
+
const from = new Int32Array(capacity);
|
|
44
|
+
const to = new Int32Array(capacity);
|
|
45
|
+
|
|
46
|
+
let half_edge_count = 0;
|
|
47
|
+
|
|
48
|
+
for (let row = 0; row < stretch_count; row++) {
|
|
49
|
+
const a = stretch_particle[row * 2];
|
|
50
|
+
const b = stretch_particle[row * 2 + 1];
|
|
51
|
+
|
|
52
|
+
assert.ok(a >= 0 && a < particle_count, `stretch row ${row} particle 0 (=${a}) out of range`);
|
|
53
|
+
assert.ok(b >= 0 && b < particle_count, `stretch row ${row} particle 1 (=${b}) out of range`);
|
|
54
|
+
|
|
55
|
+
if (a !== b) {
|
|
56
|
+
from[half_edge_count] = a;
|
|
57
|
+
to[half_edge_count++] = b;
|
|
58
|
+
from[half_edge_count] = b;
|
|
59
|
+
to[half_edge_count++] = a;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
for (let row = 0; row < bend_count; row++) {
|
|
64
|
+
const base = row * 4;
|
|
65
|
+
|
|
66
|
+
for (let i = 0; i < 4; i++) {
|
|
67
|
+
const a = bend_particle[base + i];
|
|
68
|
+
|
|
69
|
+
assert.ok(a >= 0 && a < particle_count, `bend row ${row} particle ${i} (=${a}) out of range`);
|
|
70
|
+
|
|
71
|
+
for (let j = i + 1; j < 4; j++) {
|
|
72
|
+
const b = bend_particle[base + j];
|
|
73
|
+
|
|
74
|
+
if (a !== b) {
|
|
75
|
+
from[half_edge_count] = a;
|
|
76
|
+
to[half_edge_count++] = b;
|
|
77
|
+
from[half_edge_count] = b;
|
|
78
|
+
to[half_edge_count++] = a;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const offset = new Int32Array(particle_count + 1);
|
|
85
|
+
const partner = new Int32Array(half_edge_count);
|
|
86
|
+
|
|
87
|
+
csr_build_incidence(offset, partner, from, half_edge_count, particle_count);
|
|
88
|
+
|
|
89
|
+
// half-edge index to the particle at its far end
|
|
90
|
+
for (let k = 0; k < half_edge_count; k++) {
|
|
91
|
+
partner[k] = to[partner[k]];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Sort each particle's partners and drop the repeats, compacting in place.
|
|
95
|
+
// The write cursor never passes the read cursor, so an entry is always read
|
|
96
|
+
// before anything is written over it.
|
|
97
|
+
let written = 0;
|
|
98
|
+
|
|
99
|
+
for (let particle = 0; particle < particle_count; particle++) {
|
|
100
|
+
const start = offset[particle];
|
|
101
|
+
const end = offset[particle + 1];
|
|
102
|
+
|
|
103
|
+
offset[particle] = written;
|
|
104
|
+
|
|
105
|
+
const row_start = written;
|
|
106
|
+
|
|
107
|
+
for (let k = start; k < end; k++) {
|
|
108
|
+
const value = partner[k];
|
|
109
|
+
|
|
110
|
+
// insertion into the sorted run `[row_start, written)`, skipping a value already there
|
|
111
|
+
let j = written - 1;
|
|
112
|
+
|
|
113
|
+
while (j >= row_start && partner[j] > value) {
|
|
114
|
+
j--;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (j >= row_start && partner[j] === value) {
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
for (let m = written; m > j + 1; m--) {
|
|
122
|
+
partner[m] = partner[m - 1];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
partner[j + 1] = value;
|
|
126
|
+
written++;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
offset[particle_count] = written;
|
|
131
|
+
|
|
132
|
+
return { offset, partner: partner.slice(0, written) };
|
|
133
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Invert {@link ClothState#source_of_particle}: for every source vertex, the
|
|
3
|
+
* particle it became.
|
|
4
|
+
*
|
|
5
|
+
* `ClothState.from` permutes particles into colour order, so anything built
|
|
6
|
+
* against the source mesh — a triangle list, a joint layout, a node table —
|
|
7
|
+
* names the wrong particles until it is read through this map.
|
|
8
|
+
*
|
|
9
|
+
* @param {Int32Array} out particle of every source vertex, `particle_count` entries
|
|
10
|
+
* @param {Int32Array} source_of_particle source vertex of every particle, a permutation
|
|
11
|
+
* of `[0, particle_count)`
|
|
12
|
+
* @param {number} particle_count
|
|
13
|
+
* @returns {void}
|
|
14
|
+
*/
|
|
15
|
+
export function cloth_particle_of_source(out: Int32Array, source_of_particle: Int32Array, particle_count: number): void;
|
|
16
|
+
//# sourceMappingURL=cloth_particle_of_source.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloth_particle_of_source.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/solver/cloth_particle_of_source.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,8CANW,UAAU,sBACV,UAAU,kBAEV,MAAM,GACJ,IAAI,CAMhB"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Invert {@link ClothState#source_of_particle}: for every source vertex, the
|
|
3
|
+
* particle it became.
|
|
4
|
+
*
|
|
5
|
+
* `ClothState.from` permutes particles into colour order, so anything built
|
|
6
|
+
* against the source mesh — a triangle list, a joint layout, a node table —
|
|
7
|
+
* names the wrong particles until it is read through this map.
|
|
8
|
+
*
|
|
9
|
+
* @param {Int32Array} out particle of every source vertex, `particle_count` entries
|
|
10
|
+
* @param {Int32Array} source_of_particle source vertex of every particle, a permutation
|
|
11
|
+
* of `[0, particle_count)`
|
|
12
|
+
* @param {number} particle_count
|
|
13
|
+
* @returns {void}
|
|
14
|
+
*/
|
|
15
|
+
export function cloth_particle_of_source(out, source_of_particle, particle_count) {
|
|
16
|
+
for (let particle = 0; particle < particle_count; particle++) {
|
|
17
|
+
out[source_of_particle[particle]] = particle;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloth_self_find.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/solver/cloth_self_find.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cloth_self_find.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/solver/cloth_self_find.js"],"names":[],"mappings":"AA6DA;;;;;GAKG;AACH,0DAFa;IAAC,MAAM,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,UAAU,CAAA;CAAC,CAQrD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,4EANW;IAAC,MAAM,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,UAAU,CAAA;CAAC,UACzC,MAAM,GAGJ,MAAM,CAgHlB;AAED;;;;;;GAMG;AACH,+DAHW;IAAC,MAAM,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,UAAU,CAAA;CAAC,GACvC,MAAM,CAyJlB;AAxXD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH;;;;;;;;;;;;;;;;;GAiBG;AACH,4CAFU,MAAM,CAE+B"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PointHashGrid3 } from "../../../../core/geom/3d/hash-grid/PointHashGrid3.js";
|
|
2
|
+
import { cloth_particle_coupling } from "./cloth_particle_coupling.js";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* # Finding the self-collision pairs, once per step
|
|
@@ -65,61 +66,11 @@ export const CLOTH_SELF_PAIRS_PER_PARTICLE = 8;
|
|
|
65
66
|
* @returns {{offset: Int32Array, partner: Int32Array}} CSR, sorted within each particle
|
|
66
67
|
*/
|
|
67
68
|
export function cloth_self_exclusions(state) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
for (let i = 0; i < particle_count; i++) {
|
|
74
|
-
sets[i] = new Set();
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* @param {number} a
|
|
79
|
-
* @param {number} b
|
|
80
|
-
*/
|
|
81
|
-
const link = (a, b) => {
|
|
82
|
-
if (a === b) {
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
sets[a].add(b);
|
|
87
|
-
sets[b].add(a);
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
for (let row = 0; row < state.stretch_count; row++) {
|
|
91
|
-
link(state.stretch_particle[row * 2], state.stretch_particle[row * 2 + 1]);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
for (let row = 0; row < state.bend_count; row++) {
|
|
95
|
-
const base = row * 4;
|
|
96
|
-
|
|
97
|
-
for (let a = 0; a < 4; a++) {
|
|
98
|
-
for (let b = a + 1; b < 4; b++) {
|
|
99
|
-
link(state.bend_particle[base + a], state.bend_particle[base + b]);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const offset = new Int32Array(particle_count + 1);
|
|
105
|
-
|
|
106
|
-
let total = 0;
|
|
107
|
-
|
|
108
|
-
for (let i = 0; i < particle_count; i++) {
|
|
109
|
-
total += sets[i].size;
|
|
110
|
-
|
|
111
|
-
offset[i + 1] = total;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const partner = new Int32Array(total);
|
|
115
|
-
|
|
116
|
-
for (let i = 0; i < particle_count; i++) {
|
|
117
|
-
const sorted = Array.from(sets[i]).sort((a, b) => a - b);
|
|
118
|
-
|
|
119
|
-
partner.set(sorted, offset[i]);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return { offset, partner };
|
|
69
|
+
return cloth_particle_coupling(
|
|
70
|
+
state.particle_count,
|
|
71
|
+
state.stretch_particle, state.stretch_count,
|
|
72
|
+
state.bend_particle, state.bend_count
|
|
73
|
+
);
|
|
123
74
|
}
|
|
124
75
|
|
|
125
76
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloth_solve_vertex.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/solver/cloth_solve_vertex.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cloth_solve_vertex.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/solver/cloth_solve_vertex.js"],"names":[],"mappings":"AAmFA;;;;;;;;;;;;;GAaG;AACH,gEANW,MAAM,qBACN,MAAM,mBACN,YAAY,GAAC,YAAY,GAAC,IAAI,QA0FxC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { assert } from "../../../../core/assert.js";
|
|
2
|
+
import { matrix_symmetric_3x3_solve_ldlt } from "../../../../core/math/linalg/matrix_symmetric_3x3_solve_ldlt.js";
|
|
2
3
|
import { cloth_backstop_accumulate } from "./constraint/cloth_backstop_row.js";
|
|
3
4
|
import { cloth_bend_accumulate } from "./constraint/cloth_bend_row.js";
|
|
4
5
|
import { cloth_contact_accumulate } from "./constraint/cloth_contact_row.js";
|
|
@@ -7,16 +8,11 @@ import { cloth_self_accumulate } from "./constraint/cloth_self_row.js";
|
|
|
7
8
|
import { cloth_stretch_accumulate } from "./constraint/cloth_stretch_row.js";
|
|
8
9
|
import {
|
|
9
10
|
CVA_F_X,
|
|
10
|
-
CVA_F_Y,
|
|
11
|
-
CVA_F_Z,
|
|
12
11
|
CVA_H_XX,
|
|
13
|
-
CVA_H_XY,
|
|
14
|
-
CVA_H_XZ,
|
|
15
|
-
CVA_H_YY,
|
|
16
12
|
CVA_H_YZ,
|
|
17
|
-
CVA_H_ZZ,
|
|
18
13
|
CVA_TRUST,
|
|
19
|
-
CVA_STRIDE
|
|
14
|
+
CVA_STRIDE,
|
|
15
|
+
cloth_vertex_accumulator_seed
|
|
20
16
|
} from "./cloth_vertex_accumulator.js";
|
|
21
17
|
|
|
22
18
|
/**
|
|
@@ -78,6 +74,13 @@ import {
|
|
|
78
74
|
*/
|
|
79
75
|
const ACCUMULATOR = new Float64Array(CVA_STRIDE);
|
|
80
76
|
|
|
77
|
+
/**
|
|
78
|
+
* The Newton step `H⁻¹f`, scratch for the same call.
|
|
79
|
+
* @type {Float64Array}
|
|
80
|
+
* @private
|
|
81
|
+
*/
|
|
82
|
+
const DELTA = new Float64Array(3);
|
|
83
|
+
|
|
81
84
|
/**
|
|
82
85
|
* Update one particle in place.
|
|
83
86
|
*
|
|
@@ -104,24 +107,9 @@ export function cloth_solve_vertex(state, particle, inverse_h_squared, collider_
|
|
|
104
107
|
|
|
105
108
|
const p = particle * 3;
|
|
106
109
|
|
|
107
|
-
// m/h², the inertial term's weight. Positive and finite whenever the
|
|
108
|
-
// particle has a mass at all, which is what makes `H` positive definite
|
|
109
|
-
// rather than merely semidefinite.
|
|
110
|
-
const mass_over_h_squared = inverse_h_squared / inverse_mass;
|
|
111
|
-
|
|
112
110
|
const accumulator = ACCUMULATOR;
|
|
113
111
|
|
|
114
|
-
accumulator
|
|
115
|
-
accumulator[CVA_F_Y] = -mass_over_h_squared * (position[p + 1] - inertial[p + 1]);
|
|
116
|
-
accumulator[CVA_F_Z] = -mass_over_h_squared * (position[p + 2] - inertial[p + 2]);
|
|
117
|
-
|
|
118
|
-
accumulator[CVA_H_XX] = mass_over_h_squared;
|
|
119
|
-
accumulator[CVA_H_YY] = mass_over_h_squared;
|
|
120
|
-
accumulator[CVA_H_ZZ] = mass_over_h_squared;
|
|
121
|
-
accumulator[CVA_H_XY] = 0;
|
|
122
|
-
accumulator[CVA_H_XZ] = 0;
|
|
123
|
-
accumulator[CVA_H_YZ] = 0;
|
|
124
|
-
accumulator[CVA_TRUST] = Infinity;
|
|
112
|
+
cloth_vertex_accumulator_seed(accumulator, position, inertial, p, inverse_h_squared / inverse_mass);
|
|
125
113
|
|
|
126
114
|
cloth_stretch_accumulate(accumulator, state, particle);
|
|
127
115
|
cloth_bend_accumulate(accumulator, state, particle);
|
|
@@ -136,53 +124,30 @@ export function cloth_solve_vertex(state, particle, inverse_h_squared, collider_
|
|
|
136
124
|
cloth_self_accumulate(accumulator, state, particle);
|
|
137
125
|
}
|
|
138
126
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
//
|
|
147
|
-
//
|
|
148
|
-
//
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
// factorisation never forms those products, so its pivots stay positive
|
|
153
|
-
// where the determinant does not, and their product is the determinant to
|
|
154
|
-
// full precision.
|
|
155
|
-
const pivot_x = a;
|
|
156
|
-
const lower_yx = b / pivot_x;
|
|
157
|
-
const lower_zx = c / pivot_x;
|
|
158
|
-
|
|
159
|
-
const pivot_y = d - lower_yx * b;
|
|
160
|
-
const lower_zy = (e - lower_zx * b) / pivot_y;
|
|
161
|
-
|
|
162
|
-
const pivot_z = f - lower_zx * c - lower_zy * lower_zy * pivot_y;
|
|
163
|
-
|
|
164
|
-
// The pivots of an SPD matrix are its `H` restricted to nested subspaces,
|
|
165
|
-
// so all three positive *is* positive definiteness — the same claim §5.3
|
|
166
|
-
// makes, checked where it is actually used. The message is built only when the check fails: as
|
|
167
|
-
// an argument it was a string of four numbers per vertex per iteration.
|
|
168
|
-
if (!(pivot_x > 0 && pivot_y > 0 && pivot_z > 0)) {
|
|
127
|
+
// LDLᵀ, not a cofactor inverse: a vertex with one very stiff row and a
|
|
128
|
+
// small mass term assembles an `H` with a condition number in the billions,
|
|
129
|
+
// whose cofactor determinant comes out negative though every eigenvalue is
|
|
130
|
+
// positive (the core function carries the argument). The `H` slots are laid
|
|
131
|
+
// out `[xx, yy, zz, xy, xz, yz]`, which is the packing it reads.
|
|
132
|
+
//
|
|
133
|
+
// Its pivot check — all three positive *is* positive definiteness — is the
|
|
134
|
+
// same claim §5.3 makes, checked where it is actually used. A shipped build
|
|
135
|
+
// strips the assert and leaves the particle where it is rather than moving
|
|
136
|
+
// it by a solve of an indefinite system.
|
|
137
|
+
if (!matrix_symmetric_3x3_solve_ldlt(DELTA, 0, accumulator, CVA_H_XX, accumulator, CVA_F_X)) {
|
|
138
|
+
// The message is built only when the check fails: as an argument it
|
|
139
|
+
// was a string of numbers per vertex per iteration.
|
|
169
140
|
assert.ok(
|
|
170
141
|
false,
|
|
171
|
-
`cloth vertex ${particle}: H is not positive definite (
|
|
142
|
+
`cloth vertex ${particle}: H is not positive definite (H ${accumulator.subarray(CVA_H_XX, CVA_H_YZ + 1).join(', ')}) — the SPD-by-construction argument of §5.3 has been broken`
|
|
172
143
|
);
|
|
173
|
-
}
|
|
174
144
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
const force_z = accumulator[CVA_F_Z];
|
|
178
|
-
|
|
179
|
-
// Forward substitution through L, scale by D, back substitution through Lᵀ.
|
|
180
|
-
const forward_y = force_y - lower_yx * force_x;
|
|
181
|
-
const forward_z = force_z - lower_zx * force_x - lower_zy * forward_y;
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
182
147
|
|
|
183
|
-
const
|
|
184
|
-
const delta_y =
|
|
185
|
-
const
|
|
148
|
+
const delta_x = DELTA[0];
|
|
149
|
+
const delta_y = DELTA[1];
|
|
150
|
+
const delta_z = DELTA[2];
|
|
186
151
|
|
|
187
152
|
// Trust region. `H⁻¹f` is a descent direction — that is what positive
|
|
188
153
|
// definiteness buys — but a *full* Newton step is only a descent *step*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloth_step.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/solver/cloth_step.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cloth_step.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/solver/cloth_step.js"],"names":[],"mappings":"AAkCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgIG;AAEH;;;;;;;;;;;;;;;;;;GAkBG;AACH,kDAfW,MAAM,kBACN,MAAM,kBAEN,MAAM,kBACN,MAAM,YACN,MAAM,cACN,MAAM,mBACN,YAAY,GAAC,YAAY,GAAC,IAAI,mBAE9B,MAAM,WACN;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAC,aAC3G,YAAY,GAAC,IAAI,QAkI3B"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { assert } from "../../../../core/assert.js";
|
|
2
|
+
import { array_compute_max } from "../../../../core/collection/array/array_compute_max.js";
|
|
3
|
+
import { clamp01 } from "../../../../core/math/clamp01.js";
|
|
2
4
|
import { cloth_collider_pose_at } from "../collider/cloth_collider_sdf.js";
|
|
3
5
|
import { CLOTH_HOLD_LINE_WORDS, cloth_hold_line_fit, cloth_hold_line_turn } from "./cloth_hold_line.js";
|
|
4
6
|
import { cloth_solve_vertex } from "./cloth_solve_vertex.js";
|
|
@@ -408,17 +410,9 @@ function cloth_held_velocity(state, p, inverse_h) {
|
|
|
408
410
|
* @private
|
|
409
411
|
*/
|
|
410
412
|
function max_inverse_mass(state) {
|
|
411
|
-
const
|
|
412
|
-
|
|
413
|
-
let worst = 0;
|
|
414
|
-
|
|
415
|
-
for (let i = 0; i < state.particle_count; i++) {
|
|
416
|
-
if (mass_inverse[i] > worst) {
|
|
417
|
-
worst = mass_inverse[i];
|
|
418
|
-
}
|
|
419
|
-
}
|
|
413
|
+
const worst = array_compute_max(state.mass_inverse, 0, state.particle_count);
|
|
420
414
|
|
|
421
|
-
// Every particle pinned: nothing can move, so the stiffness is unused and
|
|
415
|
+
// Every particle pinned, or no particles at all: nothing can move, so the stiffness is unused and
|
|
422
416
|
// any finite value is as good as another.
|
|
423
417
|
return worst > 0 ? worst : 1;
|
|
424
418
|
}
|
|
@@ -622,15 +616,7 @@ function cloth_integrate(state, inverse_h, acceleration_x, acceleration_y, accel
|
|
|
622
616
|
(next_y - velocity[p + 1]) * acceleration_y +
|
|
623
617
|
(next_z - velocity[p + 2]) * acceleration_z;
|
|
624
618
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
if (blend < 0) {
|
|
628
|
-
blend = 0;
|
|
629
|
-
} else if (blend > 1) {
|
|
630
|
-
blend = 1;
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
inertia_blend[i] = blend;
|
|
619
|
+
inertia_blend[i] = clamp01(realised * inverse_h * inverse_acceleration_squared);
|
|
634
620
|
|
|
635
621
|
velocity[p] = next_x;
|
|
636
622
|
velocity[p + 1] = next_y;
|
|
@@ -694,15 +680,7 @@ function cloth_integrate_varying(state, inverse_h, external) {
|
|
|
694
680
|
// {@link cloth_integrate} uses — the two differ in the last bit, and
|
|
695
681
|
// a cloth whose external acceleration happens to be exactly gravity
|
|
696
682
|
// should follow the same trajectory whichever loop stepped it.
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
if (blend < 0) {
|
|
700
|
-
blend = 0;
|
|
701
|
-
} else if (blend > 1) {
|
|
702
|
-
blend = 1;
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
inertia_blend[i] = blend;
|
|
683
|
+
inertia_blend[i] = clamp01(realised * inverse_h * (1 / acceleration_squared));
|
|
706
684
|
} else {
|
|
707
685
|
// No direction to project onto, so nothing to seed. The uniform
|
|
708
686
|
// path reaches this for the whole cloth at once; here it is a
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloth_step_instance.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/solver/cloth_step_instance.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cloth_step_instance.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/solver/cloth_step_instance.js"],"names":[],"mappings":"AA6IA;;;;;;;;;GASG;AACH,wEANW;IAAC,MAAM,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,UAAU,CAAA;CAAC,GAAC,IAAI,UAE9C,YAAY,UACZ,MAAM,GACJ,IAAI,CA6DhB;;;;6BAtJS,MAAM;;;;;;;;;;;;;;;;;;AA2EhB;;;GAGG;AACH,sCAFU,MAAM,CAE0B"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { vector_scale_offset } from "../../../../core/geom/vec/vector_scale_offset.js";
|
|
1
2
|
import { cloth_contact_find } from "./cloth_contact_find.js";
|
|
2
3
|
import { cloth_self_find } from "./cloth_self_find.js";
|
|
3
4
|
import { cloth_step } from "./cloth_step.js";
|
|
@@ -229,9 +230,7 @@ function damp(state, retention) {
|
|
|
229
230
|
|
|
230
231
|
const velocity = state.velocity;
|
|
231
232
|
|
|
232
|
-
|
|
233
|
-
velocity[i] *= retention;
|
|
234
|
-
}
|
|
233
|
+
vector_scale_offset(velocity, 0, velocity, 0, velocity.length, retention);
|
|
235
234
|
}
|
|
236
235
|
|
|
237
236
|
/**
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The worst relative error over a cloth's stretch rows, `max |C|/L₀` with
|
|
3
|
+
* `C = ‖x_a − x_b‖ − L₀` — §7 P2's rubber number. Zero when every row sits at
|
|
4
|
+
* its rest length; `0.1` when the worst one is ten percent off, long or short.
|
|
5
|
+
*
|
|
6
|
+
* A row of zero rest length has no relative error to speak of and is skipped,
|
|
7
|
+
* so a cloth with no rows, or only such rows, reads zero. A row with a NaN end
|
|
8
|
+
* reads NaN and so does the answer, whatever the other rows say: the callers
|
|
9
|
+
* gate on `Number.isFinite`, and a broken state must not read as converged.
|
|
10
|
+
*
|
|
11
|
+
* A diagnostic for specs, measurements and the playgrounds; nothing in the
|
|
12
|
+
* step reads it.
|
|
13
|
+
*
|
|
14
|
+
* @param {ClothState} state
|
|
15
|
+
* @returns {number} dimensionless
|
|
16
|
+
*
|
|
17
|
+
* @author Alex Goldring
|
|
18
|
+
* @copyright Company Named Limited (c) 2026
|
|
19
|
+
*/
|
|
20
|
+
export function cloth_stretch_residual(state: ClothState): number;
|
|
21
|
+
//# sourceMappingURL=cloth_stretch_residual.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloth_stretch_residual.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/solver/cloth_stretch_residual.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;GAkBG;AACH,2DALa,MAAM,CAoClB"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { v3_length } from "../../../../core/geom/vec3/v3_length.js";
|
|
2
|
+
import { max2_exact } from "../../../../core/math/max2_exact.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The worst relative error over a cloth's stretch rows, `max |C|/L₀` with
|
|
6
|
+
* `C = ‖x_a − x_b‖ − L₀` — §7 P2's rubber number. Zero when every row sits at
|
|
7
|
+
* its rest length; `0.1` when the worst one is ten percent off, long or short.
|
|
8
|
+
*
|
|
9
|
+
* A row of zero rest length has no relative error to speak of and is skipped,
|
|
10
|
+
* so a cloth with no rows, or only such rows, reads zero. A row with a NaN end
|
|
11
|
+
* reads NaN and so does the answer, whatever the other rows say: the callers
|
|
12
|
+
* gate on `Number.isFinite`, and a broken state must not read as converged.
|
|
13
|
+
*
|
|
14
|
+
* A diagnostic for specs, measurements and the playgrounds; nothing in the
|
|
15
|
+
* step reads it.
|
|
16
|
+
*
|
|
17
|
+
* @param {ClothState} state
|
|
18
|
+
* @returns {number} dimensionless
|
|
19
|
+
*
|
|
20
|
+
* @author Alex Goldring
|
|
21
|
+
* @copyright Company Named Limited (c) 2026
|
|
22
|
+
*/
|
|
23
|
+
export function cloth_stretch_residual(state) {
|
|
24
|
+
const stretch_count = state.stretch_count;
|
|
25
|
+
|
|
26
|
+
const stretch_particle = state.stretch_particle;
|
|
27
|
+
const stretch_rest = state.stretch_rest;
|
|
28
|
+
const position = state.position;
|
|
29
|
+
|
|
30
|
+
let worst = 0;
|
|
31
|
+
|
|
32
|
+
for (let row = 0; row < stretch_count; row++) {
|
|
33
|
+
const rest = stretch_rest[row];
|
|
34
|
+
|
|
35
|
+
if (!(rest > 0)) {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const a = stretch_particle[row * 2] * 3;
|
|
40
|
+
const b = stretch_particle[row * 2 + 1] * 3;
|
|
41
|
+
|
|
42
|
+
const length = v3_length(
|
|
43
|
+
position[a] - position[b],
|
|
44
|
+
position[a + 1] - position[b + 1],
|
|
45
|
+
position[a + 2] - position[b + 2]
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
const residual = Math.abs(length - rest) / rest;
|
|
49
|
+
|
|
50
|
+
worst = max2_exact(worst, residual);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return worst;
|
|
54
|
+
}
|
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Seed an accumulator with the inertial term alone, before any row adds to it:
|
|
3
|
+
* the force `−(m/h²)(x − y)`, the Hessian `(m/h²)·I`, and no trust bound yet.
|
|
4
|
+
*
|
|
5
|
+
* `m/h²` is positive and finite whenever the particle has a mass at all, which
|
|
6
|
+
* is what makes the assembled `H` positive definite rather than merely
|
|
7
|
+
* semidefinite.
|
|
8
|
+
*
|
|
9
|
+
* @param {Float64Array} accumulator {@link CVA_STRIDE} slots, overwritten
|
|
10
|
+
* @param {Float32Array} position particle positions, 3 per particle
|
|
11
|
+
* @param {Float32Array} inertial predicted positions `y`, 3 per particle
|
|
12
|
+
* @param {number} p the particle's first component index, `particle · 3`
|
|
13
|
+
* @param {number} mass_over_h_squared `m/h²`
|
|
14
|
+
*/
|
|
15
|
+
export function cloth_vertex_accumulator_seed(accumulator: Float64Array, position: Float32Array, inertial: Float32Array, p: number, mass_over_h_squared: number): void;
|
|
1
16
|
/**
|
|
2
17
|
* # The per-vertex `(f, H)` accumulator
|
|
3
18
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloth_vertex_accumulator.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/solver/cloth_vertex_accumulator.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cloth_vertex_accumulator.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/solver/cloth_vertex_accumulator.js"],"names":[],"mappings":"AAyDA;;;;;;;;;;;;;GAaG;AACH,2DANW,YAAY,YACZ,YAAY,YACZ,YAAY,KACZ,MAAM,uBACN,MAAM,QAchB;AAnFD;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,gBAAgB;AAChB,wBAAyB;AACzB,gBAAgB;AAChB,wBAAyB;AACzB,gBAAgB;AAChB,wBAAyB;AACzB,yBAAyB;AACzB,yBAA0B;AAC1B,yBAAyB;AACzB,yBAA0B;AAC1B,yBAAyB;AACzB,yBAA0B;AAC1B,mCAAmC;AACnC,yBAA0B;AAC1B,mCAAmC;AACnC,yBAA0B;AAC1B,mCAAmC;AACnC,yBAA0B;AAE1B;;;;;;;;;;GAUG;AACH,0BAA2B;AAE3B,gCAAgC;AAChC,4BAA6B"}
|
|
@@ -54,3 +54,31 @@ export const CVA_TRUST = 9;
|
|
|
54
54
|
|
|
55
55
|
/** Slots in one accumulator. */
|
|
56
56
|
export const CVA_STRIDE = 10;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Seed an accumulator with the inertial term alone, before any row adds to it:
|
|
60
|
+
* the force `−(m/h²)(x − y)`, the Hessian `(m/h²)·I`, and no trust bound yet.
|
|
61
|
+
*
|
|
62
|
+
* `m/h²` is positive and finite whenever the particle has a mass at all, which
|
|
63
|
+
* is what makes the assembled `H` positive definite rather than merely
|
|
64
|
+
* semidefinite.
|
|
65
|
+
*
|
|
66
|
+
* @param {Float64Array} accumulator {@link CVA_STRIDE} slots, overwritten
|
|
67
|
+
* @param {Float32Array} position particle positions, 3 per particle
|
|
68
|
+
* @param {Float32Array} inertial predicted positions `y`, 3 per particle
|
|
69
|
+
* @param {number} p the particle's first component index, `particle · 3`
|
|
70
|
+
* @param {number} mass_over_h_squared `m/h²`
|
|
71
|
+
*/
|
|
72
|
+
export function cloth_vertex_accumulator_seed(accumulator, position, inertial, p, mass_over_h_squared) {
|
|
73
|
+
accumulator[CVA_F_X] = -mass_over_h_squared * (position[p] - inertial[p]);
|
|
74
|
+
accumulator[CVA_F_Y] = -mass_over_h_squared * (position[p + 1] - inertial[p + 1]);
|
|
75
|
+
accumulator[CVA_F_Z] = -mass_over_h_squared * (position[p + 2] - inertial[p + 2]);
|
|
76
|
+
|
|
77
|
+
accumulator[CVA_H_XX] = mass_over_h_squared;
|
|
78
|
+
accumulator[CVA_H_YY] = mass_over_h_squared;
|
|
79
|
+
accumulator[CVA_H_ZZ] = mass_over_h_squared;
|
|
80
|
+
accumulator[CVA_H_XY] = 0;
|
|
81
|
+
accumulator[CVA_H_XZ] = 0;
|
|
82
|
+
accumulator[CVA_H_YZ] = 0;
|
|
83
|
+
accumulator[CVA_TRUST] = Infinity;
|
|
84
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How far the cloth has stretched away from its root, as the worst ratio over
|
|
3
|
+
* nodes of straight-line distance from node 0 to the fabric between them:
|
|
4
|
+
* `max ‖x_node − x_0‖ / d_geo(node)` over nodes `1 .. node_count − 1` — §7 P2's
|
|
5
|
+
* measure. At most 1 for a cloth that has not over-stretched anywhere, since no
|
|
6
|
+
* straight line is longer than the fabric it spans; `1.05` is a node five
|
|
7
|
+
* percent further out than the cloth reaches.
|
|
8
|
+
*
|
|
9
|
+
* Everything is measured from node 0, the root of the seeder's tree, which is
|
|
10
|
+
* where the rigs this was written for are held. A cloth held in several places
|
|
11
|
+
* wants each node measured from its own hold instead, and this is not that
|
|
12
|
+
* measure.
|
|
13
|
+
*
|
|
14
|
+
* A node at a NaN position reads NaN and so does the answer, whatever the other
|
|
15
|
+
* nodes say, so a broken state cannot pass for a well-behaved one.
|
|
16
|
+
*
|
|
17
|
+
* Takes the arrays rather than a `ClothInstance` so the solver side does not
|
|
18
|
+
* depend on the ECS one.
|
|
19
|
+
*
|
|
20
|
+
* @param {Float32Array|Float64Array} position 3 per particle
|
|
21
|
+
* @param {Int32Array|Uint32Array|number[]} particle_of_node particle index per node
|
|
22
|
+
* @param {Float32Array|Float64Array|number[]} geodesic fabric distance from node 0 per node, metres
|
|
23
|
+
* @param {number} node_count
|
|
24
|
+
* @returns {number} dimensionless; 0 for a cloth of fewer than two nodes
|
|
25
|
+
*
|
|
26
|
+
* @author Alex Goldring
|
|
27
|
+
* @copyright Company Named Limited (c) 2026
|
|
28
|
+
*/
|
|
29
|
+
export function cloth_worst_tether_ratio(position: Float32Array | Float64Array, particle_of_node: Int32Array | Uint32Array | number[], geodesic: Float32Array | Float64Array | number[], node_count: number): number;
|
|
30
|
+
//# sourceMappingURL=cloth_worst_tether_ratio.d.ts.map
|