@woosh/meep-engine 3.43.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/editor/prototypeEditorShell.d.ts.map +1 -1
- package/editor/prototypeEditorShell.js +4 -2
- 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/Clock.d.ts +15 -0
- package/src/engine/Clock.d.ts.map +1 -1
- package/src/engine/Clock.js +29 -5
- package/src/engine/Engine.d.ts.map +1 -1
- package/src/engine/Engine.js +11 -19
- 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/ecs/mesh-v2/MeshSkin.d.ts +57 -0
- package/src/engine/graphics/ecs/mesh-v2/MeshSkin.d.ts.map +1 -0
- package/src/engine/graphics/ecs/mesh-v2/MeshSkin.js +84 -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 +28 -13
- package/src/engine/graphics3/AnimationGraphSystem.d.ts.map +1 -1
- package/src/engine/graphics3/AnimationGraphSystem.js +107 -64
- package/src/engine/graphics3/AnimationSystem.d.ts +29 -15
- package/src/engine/graphics3/AnimationSystem.d.ts.map +1 -1
- package/src/engine/graphics3/AnimationSystem.js +112 -61
- package/src/engine/graphics3/MeshSkinSystem.d.ts +56 -0
- package/src/engine/graphics3/MeshSkinSystem.d.ts.map +1 -0
- package/src/engine/graphics3/MeshSkinSystem.js +317 -0
- package/src/engine/graphics3/MeshSystem.d.ts +15 -35
- package/src/engine/graphics3/MeshSystem.d.ts.map +1 -1
- package/src/engine/graphics3/MeshSystem.js +21 -298
- package/src/engine/graphics3/RowChains.d.ts +76 -0
- package/src/engine/graphics3/RowChains.d.ts.map +1 -0
- package/src/engine/graphics3/RowChains.js +347 -0
- package/src/engine/graphics3/ShadedGeometrySystem.d.ts +6 -0
- package/src/engine/graphics3/ShadedGeometrySystem.d.ts.map +1 -1
- package/src/engine/graphics3/ShadedGeometrySystem.js +329 -309
- package/src/engine/graphics3/animation/AnimationClips.d.ts +56 -0
- package/src/engine/graphics3/animation/AnimationClips.d.ts.map +1 -0
- package/src/engine/graphics3/animation/AnimationClips.js +79 -0
- package/src/engine/graphics3/animation/ClipListPlayer.d.ts +13 -14
- package/src/engine/graphics3/animation/ClipListPlayer.d.ts.map +1 -1
- package/src/engine/graphics3/animation/ClipListPlayer.js +262 -263
- package/src/engine/graphics3/animation/write_clip_playback.d.ts +3 -3
- package/src/engine/graphics3/animation/write_clip_playback.js +4 -4
- package/src/engine/graphics3/pose/query_entity_node_world_pose.d.ts +5 -0
- package/src/engine/graphics3/pose/query_entity_node_world_pose.d.ts.map +1 -1
- package/src/engine/graphics3/pose/query_entity_node_world_pose.js +80 -75
- package/src/engine/graphics3/prefab/PrefabInstance.d.ts +4 -24
- package/src/engine/graphics3/prefab/PrefabInstance.d.ts.map +1 -1
- package/src/engine/graphics3/prefab/PrefabInstance.js +60 -80
- package/src/engine/graphics3/prefab/prefab_instantiate.d.ts +16 -3
- package/src/engine/graphics3/prefab/prefab_instantiate.d.ts.map +1 -1
- package/src/engine/graphics3/prefab/prefab_instantiate.js +49 -12
- package/src/engine/graphics3/prefab/prefab_place.d.ts +31 -17
- package/src/engine/graphics3/prefab/prefab_place.d.ts.map +1 -1
- package/src/engine/graphics3/prefab/prefab_place.js +175 -130
- package/src/engine/graphics3/register_clips.d.ts +93 -0
- package/src/engine/graphics3/register_clips.d.ts.map +1 -0
- package/src/engine/graphics3/register_clips.js +166 -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/MEASUREMENTS.md +795 -0
- package/src/engine/physics/cloth/PLAN.md +349 -17
- package/src/engine/physics/cloth/build/ClothProxy.d.ts +113 -61
- package/src/engine/physics/cloth/build/ClothProxy.d.ts.map +1 -1
- package/src/engine/physics/cloth/build/ClothProxy.js +142 -77
- package/src/engine/physics/cloth/build/cloth_bind_in_frame.d.ts +44 -0
- package/src/engine/physics/cloth/build/cloth_bind_in_frame.d.ts.map +1 -0
- package/src/engine/physics/cloth/build/cloth_bind_in_frame.js +107 -0
- package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts +43 -30
- 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 +371 -284
- package/src/engine/physics/cloth/build/cloth_proxy_from_mesh.d.ts +62 -0
- package/src/engine/physics/cloth/build/cloth_proxy_from_mesh.d.ts.map +1 -0
- package/src/engine/physics/cloth/build/cloth_proxy_from_mesh.js +275 -0
- 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 +1 -1
- package/src/engine/physics/cloth/collider/cloth_collider_sdf.d.ts.map +1 -1
- package/src/engine/physics/cloth/collider/cloth_collider_sdf.js +17 -62
- package/src/engine/physics/cloth/ecs/Cloth.d.ts +17 -9
- package/src/engine/physics/cloth/ecs/Cloth.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/Cloth.js +220 -212
- 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/ClothDynamicsFlags.js +6 -0
- package/src/engine/physics/cloth/ecs/ClothHold.d.ts +91 -0
- package/src/engine/physics/cloth/ecs/ClothHold.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/ClothHold.js +103 -0
- package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +254 -48
- package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothInstance.js +277 -47
- package/src/engine/physics/cloth/ecs/ClothPin.d.ts +73 -0
- package/src/engine/physics/cloth/ecs/ClothPin.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/ClothPin.js +92 -0
- package/src/engine/physics/cloth/ecs/ClothPinSerializationAdapter.d.ts +36 -0
- package/src/engine/physics/cloth/ecs/ClothPinSerializationAdapter.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/ClothPinSerializationAdapter.js +61 -0
- package/src/engine/physics/cloth/ecs/ClothRig.d.ts +23 -17
- package/src/engine/physics/cloth/ecs/ClothRig.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothRig.js +29 -27
- package/src/engine/physics/cloth/ecs/ClothSystem.d.ts +12 -14
- package/src/engine/physics/cloth/ecs/ClothSystem.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothSystem.js +20 -15
- package/src/engine/physics/cloth/ecs/ClothWorld.d.ts +57 -36
- package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothWorld.js +754 -207
- package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts +12 -13
- package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/WorkerClothSystem.js +20 -14
- package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts +63 -11
- package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_build_rows.js +297 -101
- package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts +9 -7
- package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_dynamics_map.js +12 -10
- package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts +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 +60 -120
- package/src/engine/physics/cloth/ecs/cloth_geodesic.d.ts +37 -0
- package/src/engine/physics/cloth/ecs/cloth_geodesic.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/cloth_geodesic.js +135 -0
- package/src/engine/physics/cloth/ecs/cloth_holds.d.ts +97 -0
- package/src/engine/physics/cloth/ecs/cloth_holds.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/cloth_holds.js +583 -0
- package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.d.ts +2 -2
- package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.js +168 -51
- package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts +17 -22
- package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_seed_rig.js +55 -117
- package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts +21 -6
- package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_seed_subtree.js +51 -42
- package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts +5 -0
- package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_write_back.js +62 -50
- package/src/engine/physics/cloth/ecs/cloth_write_back_rig.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_write_back_rig.js +65 -58
- 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 +3 -29
- package/src/engine/physics/cloth/playground/garment_build.d.ts.map +1 -1
- package/src/engine/physics/cloth/playground/garment_build.js +17 -5
- package/src/engine/physics/cloth/playground/garment_main.js +5 -20
- package/src/engine/physics/cloth/playground/main.js +6 -48
- package/src/engine/physics/cloth/playground/rig_build.d.ts.map +1 -1
- package/src/engine/physics/cloth/playground/rig_build.js +302 -296
- 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 +45 -7
- package/src/engine/physics/cloth/solver/ClothState.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/ClothState.js +79 -83
- 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 +6 -1
- package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/cloth_contact_find.js +9 -3
- package/src/engine/physics/cloth/solver/cloth_hold_line.d.ts +114 -0
- package/src/engine/physics/cloth/solver/cloth_hold_line.d.ts.map +1 -0
- package/src/engine/physics/cloth/solver/cloth_hold_line.js +350 -0
- 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 +6 -2
- package/src/engine/physics/cloth/solver/cloth_self_find.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/cloth_self_find.js +19 -68
- 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_solver_constants.d.ts +24 -12
- package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/cloth_solver_constants.js +24 -12
- package/src/engine/physics/cloth/solver/cloth_step.d.ts +16 -0
- package/src/engine/physics/cloth/solver/cloth_step.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/cloth_step.js +189 -48
- package/src/engine/physics/cloth/solver/cloth_step_instance.d.ts +1 -0
- package/src/engine/physics/cloth/solver/cloth_step_instance.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/cloth_step_instance.js +12 -6
- 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/solver/constraint/cloth_leash_row.d.ts +1 -1
- package/src/engine/physics/cloth/solver/constraint/cloth_leash_row.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/constraint/cloth_leash_row.js +353 -346
- package/src/engine/physics/cloth/solver/constraint/cloth_self_row.d.ts +7 -5
- package/src/engine/physics/cloth/solver/constraint/cloth_self_row.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/constraint/cloth_self_row.js +7 -5
- 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 +12 -10
- package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts.map +1 -1
- package/src/engine/physics/cloth/wind/cloth_sample_air.js +60 -82
- 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/FluidObstacleSystem.d.ts +4 -4
- 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/engine/simulation/Ticker.d.ts +13 -0
- package/src/engine/simulation/Ticker.d.ts.map +1 -1
- package/src/engine/simulation/Ticker.js +43 -8
- 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/RENDERER_CONTRACT.md +8 -2
- package/src/shade/playground/image_decode_bench/main.js +2 -1
- package/src/shade/playground/mesh_row_ceiling/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_blas_refit/main.d.ts.map +1 -1
- package/src/shade/playground/skinned_blas_refit/main.js +11 -19
- package/src/shade/playground/skinned_blas_refit/place_character.d.ts +6 -3
- package/src/shade/playground/skinned_blas_refit/place_character.d.ts.map +1 -1
- package/src/shade/playground/skinned_blas_refit/place_character.js +90 -90
- package/src/shade/playground/skinned_mesh_soup/main.d.ts.map +1 -1
- package/src/shade/playground/skinned_mesh_soup/main.js +502 -509
- 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/README.md +129 -109
- package/src/shade/playground/texture_encode/main.d.ts.map +1 -1
- package/src/shade/playground/texture_encode/main.js +1431 -1430
- 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/animation/GPUAnimationManager.d.ts +45 -14
- package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
- package/src/shade/renderer/animation/GPUAnimationManager.js +316 -64
- package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts +5 -0
- package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts.map +1 -1
- package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js +11 -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/BoxGeometry.d.ts +1 -11
- package/src/shade/renderer/geometry/BoxGeometry.d.ts.map +1 -1
- package/src/shade/renderer/geometry/BoxGeometry.js +6 -13
- package/src/shade/renderer/geometry/CapsuleGeometry.d.ts +19 -0
- package/src/shade/renderer/geometry/CapsuleGeometry.d.ts.map +1 -0
- package/src/shade/renderer/geometry/CapsuleGeometry.js +24 -0
- package/src/shade/renderer/geometry/ConeGeometry.d.ts +20 -0
- package/src/shade/renderer/geometry/ConeGeometry.d.ts.map +1 -0
- package/src/shade/renderer/geometry/ConeGeometry.js +33 -0
- package/src/shade/renderer/geometry/CylinderGeometry.d.ts +21 -0
- package/src/shade/renderer/geometry/CylinderGeometry.d.ts.map +1 -0
- package/src/shade/renderer/geometry/CylinderGeometry.js +35 -0
- package/src/shade/renderer/geometry/PlaneGeometry.d.ts +17 -0
- package/src/shade/renderer/geometry/PlaneGeometry.d.ts.map +1 -0
- package/src/shade/renderer/geometry/PlaneGeometry.js +22 -0
- package/src/shade/renderer/geometry/TorusGeometry.d.ts +18 -0
- package/src/shade/renderer/geometry/TorusGeometry.d.ts.map +1 -0
- package/src/shade/renderer/geometry/TorusGeometry.js +23 -0
- package/src/shade/renderer/geometry/UVSphereGeometry.d.ts +21 -0
- package/src/shade/renderer/geometry/UVSphereGeometry.d.ts.map +1 -0
- package/src/shade/renderer/geometry/UVSphereGeometry.js +34 -0
- package/src/shade/renderer/geometry/primitives/make_capsule_geometry.d.ts +19 -0
- package/src/shade/renderer/geometry/primitives/make_capsule_geometry.d.ts.map +1 -0
- package/src/shade/renderer/geometry/primitives/make_capsule_geometry.js +205 -0
- package/src/shade/renderer/geometry/primitives/make_cone_geometry.d.ts +21 -0
- package/src/shade/renderer/geometry/primitives/make_cone_geometry.d.ts.map +1 -0
- package/src/shade/renderer/geometry/primitives/make_cone_geometry.js +36 -0
- package/src/shade/renderer/geometry/primitives/make_cylinder_geometry.d.ts +1 -1
- package/src/shade/renderer/geometry/primitives/make_cylinder_geometry.d.ts.map +1 -1
- package/src/shade/renderer/geometry/primitives/make_cylinder_geometry.js +44 -9
- package/src/shade/renderer/geometry/primitives/make_uv_sphere_geometry.d.ts +20 -0
- package/src/shade/renderer/geometry/primitives/make_uv_sphere_geometry.d.ts.map +1 -0
- package/src/shade/renderer/geometry/primitives/make_uv_sphere_geometry.js +190 -0
- 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/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.js +7 -2
- package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.d.ts +26 -8
- package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.js +56 -39
- package/src/shade/renderer/gpu_primitive/prefix_sum/v1/shader_prefix_scan_csdldf.d.ts +7 -0
- package/src/shade/renderer/gpu_primitive/prefix_sum/v1/shader_prefix_scan_csdldf.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/prefix_sum/v1/shader_prefix_scan_csdldf.js +46 -4
- package/src/shade/renderer/gpu_primitive/prefix_sum/v1/test_prefix_sum.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/prefix_sum/v1/test_prefix_sum.js +4 -2
- package/src/shade/renderer/gpu_primitive/sort/defs.d.ts +2 -2
- package/src/shade/renderer/gpu_primitive/sort/defs.js +79 -79
- package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.d.ts +1 -1
- package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.js +7 -3
- package/src/shade/renderer/particles/GPUParticleSystem.js +1 -1
- package/src/shade/renderer/particles/coherence/graph_particle_bucket.d.ts +4 -3
- package/src/shade/renderer/particles/coherence/graph_particle_bucket.d.ts.map +1 -1
- package/src/shade/renderer/particles/coherence/graph_particle_bucket.js +200 -194
- package/src/shade/renderer/particles/graph_particles.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph_particles.js +6 -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
- package/src/shade/renderer/particles/warmup/graph_particle_warmup.d.ts.map +1 -1
- package/src/shade/renderer/particles/warmup/graph_particle_warmup.js +334 -329
- package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js +7 -2
- package/src/shade/renderer/rasterize/expand/mesh/graph_expand_meshes_to_meshlets.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/mesh/graph_expand_meshes_to_meshlets.js +16 -4
- package/src/shade/renderer/texture/COMPRESSED_TEXTURE_PLAN_2026_09_01.md +2444 -2345
- package/src/shade/renderer/texture/encode/chunk_astc_encode_block_4x4_rgb.d.ts.map +1 -1
- package/src/shade/renderer/texture/encode/chunk_astc_encode_block_4x4_rgb.js +312 -310
- package/src/shade/renderer/texture/encode/chunk_bc1_encode_block.d.ts +3 -3
- package/src/shade/renderer/texture/encode/chunk_bc1_encode_block.d.ts.map +1 -1
- package/src/shade/renderer/texture/encode/chunk_bc1_encode_block.js +383 -375
- package/src/shade/renderer/texture/encode/chunk_bc6h_encode_block_mode11.d.ts.map +1 -1
- package/src/shade/renderer/texture/encode/chunk_bc6h_encode_block_mode11.js +349 -346
- package/src/shade/renderer/texture/encode/chunk_bc7_encode_block.d.ts +58 -0
- package/src/shade/renderer/texture/encode/chunk_bc7_encode_block.d.ts.map +1 -0
- package/src/shade/renderer/texture/encode/chunk_bc7_encode_block.js +536 -0
- package/src/shade/renderer/texture/encode/chunk_bc7_encode_block_mode6.d.ts +21 -7
- package/src/shade/renderer/texture/encode/chunk_bc7_encode_block_mode6.d.ts.map +1 -1
- package/src/shade/renderer/texture/encode/chunk_bc7_encode_block_mode6.js +291 -327
- package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode1.d.ts +25 -0
- package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode1.d.ts.map +1 -0
- package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode1.js +99 -0
- package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode6.d.ts +5 -3
- package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode6.d.ts.map +1 -1
- package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode6.js +47 -71
- package/src/shade/renderer/texture/encode/chunk_bc7_partition_2.d.ts +10 -0
- package/src/shade/renderer/texture/encode/chunk_bc7_partition_2.d.ts.map +1 -0
- package/src/shade/renderer/texture/encode/chunk_bc7_partition_2.js +50 -0
- package/src/shade/renderer/texture/encode/shader_texture_encode_bc7.d.ts +4 -5
- package/src/shade/renderer/texture/encode/shader_texture_encode_bc7.d.ts.map +1 -1
- package/src/shade/renderer/texture/encode/shader_texture_encode_bc7.js +7 -8
- package/src/shade/renderer/water/chunk_water_transport.d.ts.map +1 -1
- package/src/shade/renderer/water/chunk_water_transport.js +7 -5
- package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts.map +1 -1
- package/src/shade/renderer/water/medium/GPUWaterBodies.js +8 -2
- package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.d.ts +3 -2
- package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.d.ts.map +1 -1
- package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.js +3 -2
- package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
- package/src/shade/renderer/water/shader_water.js +3 -1
- package/src/shade/renderer/water/surface/GPUWaterSurface.d.ts.map +1 -1
- package/src/shade/renderer/water/surface/GPUWaterSurface.js +3 -1
- package/src/shade/renderer/water/surface/graph_water_tessellation.d.ts.map +1 -1
- package/src/shade/renderer/water/surface/graph_water_tessellation.js +11 -4
- package/src/shade/renderer/water/surface/particles/GPUWaterParticles.d.ts.map +1 -1
- package/src/shade/renderer/water/surface/particles/GPUWaterParticles.js +37 -20
- package/src/shade/wgsl/validate_wgsl_source.d.ts.map +1 -1
- package/src/shade/wgsl/validate_wgsl_source.js +74 -3
- package/src/engine/graphics3/register_instance_animation.d.ts +0 -114
- package/src/engine/graphics3/register_instance_animation.d.ts.map +0 -1
- package/src/engine/graphics3/register_instance_animation.js +0 -201
|
@@ -1,24 +1,35 @@
|
|
|
1
1
|
import { assert } from "../../../../core/assert.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { array_range_equal_strict } from "../../../../core/collection/array/array_range_equal_strict.js";
|
|
3
|
+
import { pose3_apply_point_array } from "../../../../core/geom/3d/pose/pose3_apply_point_array.js";
|
|
4
|
+
import { pose3_to_local_array } from "../../../../core/geom/3d/pose/pose3_to_local_array.js";
|
|
5
|
+
import { quat3_clamp_angle_array } from "../../../../core/geom/3d/quaternion/quat3_clamp_angle_array.js";
|
|
6
|
+
import {
|
|
7
|
+
quat3_multiply_conjugate_right_array
|
|
8
|
+
} from "../../../../core/geom/3d/quaternion/quat3_multiply_conjugate_right_array.js";
|
|
4
9
|
import { v3_quaternion_apply_array } from "../../../../core/geom/vec3/v3_quaternion_apply.js";
|
|
5
10
|
import { v3_quaternion_apply_inverse_array } from "../../../../core/geom/vec3/v3_quaternion_apply_inverse.js";
|
|
6
11
|
import { EntityObserver } from "../../../ecs/EntityObserver.js";
|
|
12
|
+
import { EventType } from "../../../ecs/EventType.js";
|
|
13
|
+
import { GPUStateAuthorityFlags } from "../../../ecs/gpu/GPUStateAuthorityFlags.js";
|
|
14
|
+
import { gpu_authority_has } from "../../../ecs/gpu/gpu_authority_has.js";
|
|
15
|
+
import { parent_entity_model_of } from "../../../ecs/parent/parent_entity_model_of.js";
|
|
7
16
|
import {
|
|
8
|
-
|
|
9
|
-
} from "../../../ecs/transform-attachment/
|
|
17
|
+
transform_attachment_parent_of
|
|
18
|
+
} from "../../../ecs/transform-attachment/transform_attachment_parent_of.js";
|
|
10
19
|
import {
|
|
11
20
|
TransformAttachmentSystem
|
|
12
21
|
} from "../../../ecs/transform-attachment/TransformAttachmentSystem.js";
|
|
13
22
|
import {
|
|
14
23
|
TRANSFORM64_ROTATION_OFFSET,
|
|
15
|
-
TRANSFORM64_TRANSLATION_OFFSET
|
|
24
|
+
TRANSFORM64_TRANSLATION_OFFSET,
|
|
25
|
+
Transform64
|
|
16
26
|
} from "../../../ecs/transform/Transform64.js";
|
|
17
27
|
import { t64_evaluate_world } from "../../../ecs/transform/t64_evaluate_world.js";
|
|
28
|
+
import { t64_read_pose_array } from "../../../ecs/transform/t64_read_pose_array.js";
|
|
18
29
|
import {
|
|
19
30
|
collect_entity_playbacks
|
|
20
31
|
} from "../../../graphics3/pose/collect_entity_playbacks.js";
|
|
21
|
-
import {
|
|
32
|
+
import { MeshSkin } from "../../../graphics/ecs/mesh-v2/MeshSkin.js";
|
|
22
33
|
import { CLOTH_SELF_RADIUS_MAX_RATIO, CLOTH_SELF_RADIUS_MIN_RATIO } from "../solver/cloth_solver_constants.js";
|
|
23
34
|
import { cloth_air_changed, cloth_sample_air } from "../wind/cloth_sample_air.js";
|
|
24
35
|
import { ClothStepParam } from "../solver/cloth_step_instance.js";
|
|
@@ -26,11 +37,14 @@ import { ClothStepResult } from "../solver/ClothState.js";
|
|
|
26
37
|
import { ClothColliderSystem } from "./ClothColliderSystem.js";
|
|
27
38
|
import { ClothDynamicsFlags } from "./ClothDynamicsFlags.js";
|
|
28
39
|
import { ClothFlags } from "./ClothFlags.js";
|
|
40
|
+
import { ClothHold } from "./ClothHold.js";
|
|
29
41
|
import { ClothInstance } from "./ClothInstance.js";
|
|
42
|
+
import { ClothPin } from "./ClothPin.js";
|
|
43
|
+
import { cloth_apply_holds, cloth_capture_hold, cloth_hold_step } from "./cloth_holds.js";
|
|
30
44
|
import { ClothRig } from "./ClothRig.js";
|
|
31
45
|
import {
|
|
32
|
-
|
|
33
|
-
|
|
46
|
+
CLOTH_FRAME_ROTATION_LIMIT,
|
|
47
|
+
CLOTH_FRAME_TRAVEL_REACH,
|
|
34
48
|
CLOTH_SLEEP_DISPLACEMENT_RATIO,
|
|
35
49
|
CLOTH_SLEEP_SPEED_RATIO,
|
|
36
50
|
CLOTH_SLEEP_STEPS,
|
|
@@ -61,12 +75,9 @@ import { cloth_write_back_rig } from "./cloth_write_back_rig.js";
|
|
|
61
75
|
* # Every cloth in a scene, and everything a step needs that is not arithmetic
|
|
62
76
|
*
|
|
63
77
|
* One {@link ClothInstance} per {@link Cloth} component, stepped at the fixed
|
|
64
|
-
* rate. Per step, per cloth: move the local frame
|
|
65
|
-
* leash rows at
|
|
66
|
-
* it, step, and put the result back on the subtree.
|
|
67
|
-
* leashes are measured against is not recomposed per step — in the entity path
|
|
68
|
-
* it is constant in the anchor's own frame, and `cloth_seed_subtree.js` bakes
|
|
69
|
-
* it.
|
|
78
|
+
* rate. Per step, per cloth: take where its holders are, move the local frame,
|
|
79
|
+
* point the leash rows at what they measure from, gather the colliders that
|
|
80
|
+
* could touch it, step, and put the result back on the subtree.
|
|
70
81
|
*
|
|
71
82
|
* ## Why this is not a `System`
|
|
72
83
|
*
|
|
@@ -101,11 +112,11 @@ import { cloth_write_back_rig } from "./cloth_write_back_rig.js";
|
|
|
101
112
|
*
|
|
102
113
|
* ## The local frame and the inertia model — §7 P7
|
|
103
114
|
*
|
|
104
|
-
* Particles live in the
|
|
115
|
+
* Particles live in the cloth's frame. When the frame moves, the cloth is
|
|
105
116
|
* asked how much of that motion it would like to feel:
|
|
106
117
|
* `ClothDynamics#inertia = 1` keeps every particle's **world** position and
|
|
107
118
|
* velocity, so a cape trails a sprinting character; `0` keeps their **local**
|
|
108
|
-
* ones, so the cloth rides the
|
|
119
|
+
* ones, so the cloth rides the frame as though it were standing still. The
|
|
109
120
|
* blend between the two is a lerp in the local frame, which is all the frame
|
|
110
121
|
* change is.
|
|
111
122
|
*
|
|
@@ -127,14 +138,32 @@ import { cloth_write_back_rig } from "./cloth_write_back_rig.js";
|
|
|
127
138
|
* step's drag response is zero, `cloth_step` takes the uniform-gravity path,
|
|
128
139
|
* and a scene produces the bytes M5 measured.
|
|
129
140
|
*
|
|
141
|
+
* ## Holds
|
|
142
|
+
*
|
|
143
|
+
* A {@link ClothPin} on any entity holds the particles it names. This world
|
|
144
|
+
* keeps one {@link ClothHold} per pin, by the cloth entity it names, for as long
|
|
145
|
+
* as the pin exists — **outside** the seeded instance, because the offsets a
|
|
146
|
+
* hold takes when it begins are the hold's and must survive a re-seed. A pin is
|
|
147
|
+
* only ever *noticed* by the observer; everything it changes in a cloth's state
|
|
148
|
+
* is written in {@link advance}, which is the one window in which the main
|
|
149
|
+
* thread owns that state under both systems.
|
|
150
|
+
*
|
|
151
|
+
* Each step, before anything else, every holder's pose is taken — read off its
|
|
152
|
+
* `Transform64` when the CPU owns it, evaluated exactly when a clip does — and
|
|
153
|
+
* expressed in the cloth's frame. `cloth_holds.js` turns those poses into
|
|
154
|
+
* where the held particles go, the animated pose hung from them, and the leash
|
|
155
|
+
* centres.
|
|
156
|
+
*
|
|
130
157
|
* ## Teleport — §7 P6
|
|
131
158
|
*
|
|
132
|
-
*
|
|
133
|
-
* amount of it
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
159
|
+
* Frame motion past a threshold is not locomotion and is not treated as any
|
|
160
|
+
* amount of it, and neither is a holder jumping that far in the frame — a ship
|
|
161
|
+
* the rope is tied to, moved across the map. `ClothFlags.TeleportKeep` carries
|
|
162
|
+
* the shape across: for the frame that is literally doing nothing, and for a
|
|
163
|
+
* holder it is that holder's own jump applied to what hangs from it. The default
|
|
164
|
+
* re-seeds at the animated pose with zero velocity and opens a stabilisation
|
|
165
|
+
* window in which the velocity limit ramps back from nothing, so the first steps
|
|
166
|
+
* after a reset cannot produce a whip.
|
|
138
167
|
*
|
|
139
168
|
* @author Alex Goldring
|
|
140
169
|
* @copyright Company Named Limited (c) 2026
|
|
@@ -162,24 +191,6 @@ export class ClothWorld {
|
|
|
162
191
|
*/
|
|
163
192
|
instances = [];
|
|
164
193
|
|
|
165
|
-
/**
|
|
166
|
-
* Where a skinned model instance comes from. Anything that answers
|
|
167
|
-
* `instance_of(entity)` with a `PrefabInstance` — skins whose joints
|
|
168
|
-
* are entities — will do, and {@link MeshSystem} is what does in a
|
|
169
|
-
* running engine.
|
|
170
|
-
*
|
|
171
|
-
* Public and assignable because a garment's joints are a *rendering*
|
|
172
|
-
* structure and `MeshSystem` needs a graphics engine, a scene and a loader
|
|
173
|
-
* to exist — so a spec that wants joints without a renderer sets this
|
|
174
|
-
* instead, and gets exactly the interface the system uses.
|
|
175
|
-
*
|
|
176
|
-
* `null` means no rig can seed, which is the same additive shape the
|
|
177
|
-
* collider index has: a scene without one gets M1's cloth rather than an
|
|
178
|
-
* error.
|
|
179
|
-
* @type {{instance_of: function(number): (PrefabInstance|null)}|null}
|
|
180
|
-
*/
|
|
181
|
-
models = null;
|
|
182
|
-
|
|
183
194
|
/**
|
|
184
195
|
* @type {EntityManager|null}
|
|
185
196
|
*/
|
|
@@ -292,6 +303,44 @@ export class ClothWorld {
|
|
|
292
303
|
this
|
|
293
304
|
);
|
|
294
305
|
|
|
306
|
+
/**
|
|
307
|
+
* Every {@link ClothPin} in the dataset, as the hold it makes. A pin is
|
|
308
|
+
* noticed here and nowhere else; what it does to a cloth is written in
|
|
309
|
+
* {@link advance}.
|
|
310
|
+
* @type {EntityObserver}
|
|
311
|
+
* @private
|
|
312
|
+
*/
|
|
313
|
+
__pin_observer = new EntityObserver(
|
|
314
|
+
[ClothPin],
|
|
315
|
+
(pin, entity) => this.#pin_added(pin, entity),
|
|
316
|
+
(pin, entity) => this.#pin_removed(pin, entity),
|
|
317
|
+
this
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Holds by the cloth entity they name, each list ascending by holder — so a
|
|
322
|
+
* particle two pins name goes to the lower holder, every time.
|
|
323
|
+
* @type {Map<number, ClothHold[]>}
|
|
324
|
+
* @private
|
|
325
|
+
*/
|
|
326
|
+
#holds = new Map();
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Bumped for a cloth entity whenever a hold on it appears or goes;
|
|
330
|
+
* {@link ClothInstance#holds_version} is what an instance last applied.
|
|
331
|
+
* @type {Map<number, number>}
|
|
332
|
+
* @private
|
|
333
|
+
*/
|
|
334
|
+
#hold_versions = new Map();
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* The dataset the observers are attached to, for the one thing a pin needs
|
|
338
|
+
* done outside a step: going when its cloth's entity does.
|
|
339
|
+
* @type {EntityComponentDataset|null}
|
|
340
|
+
* @private
|
|
341
|
+
*/
|
|
342
|
+
#dataset = null;
|
|
343
|
+
|
|
295
344
|
/**
|
|
296
345
|
* Resolve the systems a cloth world reads. Called from the owning system's
|
|
297
346
|
* `startup`.
|
|
@@ -311,10 +360,6 @@ export class ClothWorld {
|
|
|
311
360
|
// Optional by design. A scene with no ClothColliderSystem gets cloth
|
|
312
361
|
// that does not collide, rather than cloth that throws.
|
|
313
362
|
this.colliders = entityManager.getSystem(ClothColliderSystem) ?? null;
|
|
314
|
-
|
|
315
|
-
if (this.models === null) {
|
|
316
|
-
this.models = entityManager.getSystem(MeshSystem) ?? null;
|
|
317
|
-
}
|
|
318
363
|
}
|
|
319
364
|
|
|
320
365
|
/**
|
|
@@ -347,7 +392,18 @@ export class ClothWorld {
|
|
|
347
392
|
* @returns {void}
|
|
348
393
|
*/
|
|
349
394
|
attach_dataset(dataset) {
|
|
395
|
+
this.#dataset = dataset;
|
|
396
|
+
|
|
350
397
|
dataset.addObserver(this.__rig_observer, true);
|
|
398
|
+
|
|
399
|
+
// A cloth simulates fine with nothing holding it, so a scene need not
|
|
400
|
+
// have registered the component to have cloth in it.
|
|
401
|
+
dataset.registerComponentType(ClothPin);
|
|
402
|
+
|
|
403
|
+
// nor a skin, to have cloth that is not a rig
|
|
404
|
+
dataset.registerComponentType(MeshSkin);
|
|
405
|
+
|
|
406
|
+
dataset.addObserver(this.__pin_observer, true);
|
|
351
407
|
}
|
|
352
408
|
|
|
353
409
|
/**
|
|
@@ -356,6 +412,378 @@ export class ClothWorld {
|
|
|
356
412
|
*/
|
|
357
413
|
detach_dataset(dataset) {
|
|
358
414
|
dataset.removeObserver(this.__rig_observer, false);
|
|
415
|
+
dataset.removeObserver(this.__pin_observer, false);
|
|
416
|
+
|
|
417
|
+
this.#dataset = null;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* @param {ClothPin} pin
|
|
422
|
+
* @param {number} holder
|
|
423
|
+
* @private
|
|
424
|
+
*/
|
|
425
|
+
#pin_added(pin, holder) {
|
|
426
|
+
const cloth = pin.cloth;
|
|
427
|
+
|
|
428
|
+
let list = this.#holds.get(cloth);
|
|
429
|
+
|
|
430
|
+
if (list === undefined) {
|
|
431
|
+
list = [];
|
|
432
|
+
|
|
433
|
+
this.#holds.set(cloth, list);
|
|
434
|
+
|
|
435
|
+
// A pin names its cloth's entity, and an entity id is reused: when
|
|
436
|
+
// that entity goes, the pins naming it go with it, rather than
|
|
437
|
+
// waiting to hold whatever is spawned under the same id next. The
|
|
438
|
+
// same contract `IKGoal` has with its target.
|
|
439
|
+
const dataset = this.#dataset;
|
|
440
|
+
|
|
441
|
+
if (dataset !== null && dataset.entityExists(cloth)) {
|
|
442
|
+
dataset.addEntityEventListener(cloth, EventType.EntityRemoved, this.#cloth_entity_removed, this);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
const hold = new ClothHold();
|
|
447
|
+
|
|
448
|
+
hold.holder = holder;
|
|
449
|
+
hold.pin = pin;
|
|
450
|
+
|
|
451
|
+
let at = list.length;
|
|
452
|
+
|
|
453
|
+
while (at > 0 && list[at - 1].holder > holder) {
|
|
454
|
+
at--;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
list.splice(at, 0, hold);
|
|
458
|
+
|
|
459
|
+
this.#bump(cloth);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* @param {ClothPin} pin
|
|
464
|
+
* @param {number} holder
|
|
465
|
+
* @private
|
|
466
|
+
*/
|
|
467
|
+
#pin_removed(pin, holder) {
|
|
468
|
+
const cloth = pin.cloth;
|
|
469
|
+
|
|
470
|
+
const list = this.#holds.get(cloth);
|
|
471
|
+
|
|
472
|
+
if (list === undefined) {
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
for (let i = 0; i < list.length; i++) {
|
|
477
|
+
if (list[i].holder === holder) {
|
|
478
|
+
list.splice(i, 1);
|
|
479
|
+
|
|
480
|
+
break;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
if (list.length === 0) {
|
|
485
|
+
this.#holds.delete(cloth);
|
|
486
|
+
|
|
487
|
+
const dataset = this.#dataset;
|
|
488
|
+
|
|
489
|
+
if (dataset !== null && dataset.entityExists(cloth)) {
|
|
490
|
+
dataset.removeEntityEventListener(cloth, EventType.EntityRemoved, this.#cloth_entity_removed, this);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
this.#bump(cloth);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* A cloth's entity has gone: take every pin naming it off its holder.
|
|
499
|
+
*
|
|
500
|
+
* @param {*} event
|
|
501
|
+
* @param {number} cloth
|
|
502
|
+
* @private
|
|
503
|
+
*/
|
|
504
|
+
#cloth_entity_removed(event, cloth) {
|
|
505
|
+
const list = this.#holds.get(cloth);
|
|
506
|
+
|
|
507
|
+
const dataset = this.#dataset;
|
|
508
|
+
|
|
509
|
+
if (list === undefined || dataset === null) {
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// Removing a pin edits the list, so walk a copy.
|
|
514
|
+
const holders = list.map(hold => hold.holder);
|
|
515
|
+
|
|
516
|
+
for (let i = 0; i < holders.length; i++) {
|
|
517
|
+
if (dataset.entityExists(holders[i])) {
|
|
518
|
+
dataset.removeComponentFromEntity(holders[i], ClothPin);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* @param {number} cloth
|
|
525
|
+
* @private
|
|
526
|
+
*/
|
|
527
|
+
#bump(cloth) {
|
|
528
|
+
this.#hold_versions.set(cloth, (this.#hold_versions.get(cloth) ?? 0) + 1);
|
|
529
|
+
|
|
530
|
+
const instance = this.__by_entity.get(cloth);
|
|
531
|
+
|
|
532
|
+
if (instance !== undefined) {
|
|
533
|
+
instance.asleep = false;
|
|
534
|
+
instance.still_steps = 0;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/**
|
|
539
|
+
* The particles a cloth has and the entities they are, enough to say
|
|
540
|
+
* whether a holder hangs from one of them.
|
|
541
|
+
*
|
|
542
|
+
* A holder that cloth itself moves — a link of the same rope, or anything
|
|
543
|
+
* hanging below one — would chase its own write-back one step behind, so it
|
|
544
|
+
* is refused once, by name, and holds nothing. The cloth's own entity is
|
|
545
|
+
* allowed: for a subtree it is the frame, which cloth reads and never writes.
|
|
546
|
+
*
|
|
547
|
+
* @param {ClothInstance} instance
|
|
548
|
+
* @param {ClothHold} hold
|
|
549
|
+
* @returns {string} empty when the hold may hold, otherwise why not
|
|
550
|
+
* @private
|
|
551
|
+
*/
|
|
552
|
+
#refusal(instance, hold) {
|
|
553
|
+
const ecd = this.entityManager.dataset;
|
|
554
|
+
|
|
555
|
+
for (let entity = hold.holder, depth = 0; entity >= 0 && depth < 256; depth++) {
|
|
556
|
+
if (this.#is_output(instance, entity)) {
|
|
557
|
+
return `entity ${hold.holder} holds cloth ${instance.entity} and hangs from entity ${entity}, which that cloth moves`;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
entity = transform_attachment_parent_of(ecd, entity);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
const particles = hold.pin.particles;
|
|
564
|
+
|
|
565
|
+
for (let k = 0; k < particles.length; k++) {
|
|
566
|
+
if (particles[k] >= instance.node_count) {
|
|
567
|
+
return `entity ${hold.holder} holds particle ${particles[k]} of cloth ${instance.entity}, which has ${instance.node_count}`;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
return "";
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* @param {ClothInstance} instance
|
|
576
|
+
* @param {number} entity
|
|
577
|
+
* @returns {boolean} whether cloth writes this entity's pose
|
|
578
|
+
* @private
|
|
579
|
+
*/
|
|
580
|
+
#is_output(instance, entity) {
|
|
581
|
+
const output = instance.node_output;
|
|
582
|
+
const entities = instance.rig === null ? instance.node_entity : instance.node_joint;
|
|
583
|
+
|
|
584
|
+
for (let node = 0; node < instance.node_count; node++) {
|
|
585
|
+
if (output[node] !== 0 && entities[node] === entity) {
|
|
586
|
+
return true;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
return false;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
/**
|
|
594
|
+
* Bring an instance's holds up to date with the pins that name it: pick up a
|
|
595
|
+
* changed set, take the offsets of any hold whose holder has just been found,
|
|
596
|
+
* and re-derive whatever holding decides. Nothing here runs unless something
|
|
597
|
+
* changed.
|
|
598
|
+
*
|
|
599
|
+
* @param {ClothInstance} instance
|
|
600
|
+
* @param {Float64Array} frame_translation the frame the particle positions are in
|
|
601
|
+
* @param {Float64Array} frame_rotation
|
|
602
|
+
* @returns {boolean} whether anything about what holds the cloth changed
|
|
603
|
+
* @private
|
|
604
|
+
*/
|
|
605
|
+
#refresh_holds(instance, frame_translation, frame_rotation) {
|
|
606
|
+
let changed = false;
|
|
607
|
+
|
|
608
|
+
const holds = instance.holds;
|
|
609
|
+
|
|
610
|
+
for (let h = 0; h < holds.length; h++) {
|
|
611
|
+
const hold = holds[h];
|
|
612
|
+
|
|
613
|
+
if (!hold.captured && hold.valid && !hold.refused) {
|
|
614
|
+
cloth_capture_hold(instance, hold, frame_translation, frame_rotation);
|
|
615
|
+
|
|
616
|
+
changed = true;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
if (changed || instance.holds_applied !== instance.holds_version) {
|
|
621
|
+
cloth_apply_holds(instance);
|
|
622
|
+
|
|
623
|
+
instance.holds_applied = instance.holds_version;
|
|
624
|
+
|
|
625
|
+
// A different set of holds is a different cloth to rest; the window
|
|
626
|
+
// that was open measured the old one.
|
|
627
|
+
instance.still_steps = 0;
|
|
628
|
+
instance.sleep_reference = null;
|
|
629
|
+
|
|
630
|
+
changed = true;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
return changed;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* Pick up a changed set of pins: the instance's holds become the registry's,
|
|
638
|
+
* each one admitted or refused.
|
|
639
|
+
*
|
|
640
|
+
* @param {ClothInstance} instance
|
|
641
|
+
* @private
|
|
642
|
+
*/
|
|
643
|
+
#sync_holds(instance) {
|
|
644
|
+
const version = this.#hold_versions.get(instance.entity) ?? 0;
|
|
645
|
+
|
|
646
|
+
if (instance.holds_version === version) {
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
const list = this.#holds.get(instance.entity);
|
|
651
|
+
|
|
652
|
+
instance.holds = list === undefined ? [] : list.slice();
|
|
653
|
+
instance.holds_version = version;
|
|
654
|
+
|
|
655
|
+
for (let h = 0; h < instance.holds.length; h++) {
|
|
656
|
+
const hold = instance.holds[h];
|
|
657
|
+
|
|
658
|
+
const refusal = this.#refusal(instance, hold);
|
|
659
|
+
|
|
660
|
+
hold.refused = refusal !== "";
|
|
661
|
+
|
|
662
|
+
if (hold.refused && !hold.reported) {
|
|
663
|
+
hold.reported = true;
|
|
664
|
+
|
|
665
|
+
console.warn(`ClothSystem: ${refusal}`);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/**
|
|
671
|
+
* Where every holder is this step: in the world, and in the cloth's frame.
|
|
672
|
+
*
|
|
673
|
+
* @param {ClothInstance} instance
|
|
674
|
+
* @param {Float64Array} frame_translation this step's frame
|
|
675
|
+
* @param {Float64Array} frame_rotation
|
|
676
|
+
* @returns {boolean} whether any holder moved, appeared or vanished since
|
|
677
|
+
* the last step
|
|
678
|
+
* @private
|
|
679
|
+
*/
|
|
680
|
+
#evaluate_holds(instance, frame_translation, frame_rotation) {
|
|
681
|
+
let moved = false;
|
|
682
|
+
|
|
683
|
+
const holds = instance.holds;
|
|
684
|
+
|
|
685
|
+
for (let h = 0; h < holds.length; h++) {
|
|
686
|
+
const hold = holds[h];
|
|
687
|
+
|
|
688
|
+
const was_valid = hold.valid;
|
|
689
|
+
|
|
690
|
+
hold.valid = !hold.refused && this.#holder_world(hold.holder, hold.world);
|
|
691
|
+
|
|
692
|
+
if (!hold.valid) {
|
|
693
|
+
moved = moved || was_valid;
|
|
694
|
+
|
|
695
|
+
continue;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
const world = hold.world;
|
|
699
|
+
const pose = hold.pose;
|
|
700
|
+
|
|
701
|
+
// in the frame: q_f⁻¹ · (t − t_f), q_f⁻¹ ⊗ q
|
|
702
|
+
pose3_to_local_array(pose, 0, pose, 3, frame_translation, 0, frame_rotation, 0, world, 0, world, 3);
|
|
703
|
+
|
|
704
|
+
if (!hold.has_previous) {
|
|
705
|
+
moved = true;
|
|
706
|
+
|
|
707
|
+
continue;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
if (!array_range_equal_strict(world, 0, hold.world_previous, 0, 7)) {
|
|
711
|
+
moved = true;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
return moved;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
/**
|
|
719
|
+
* A holder's world pose, `[tx, ty, tz, qx, qy, qz, qw]`.
|
|
720
|
+
*
|
|
721
|
+
* Read off its `Transform64` when the CPU owns that, which is every prop and
|
|
722
|
+
* every hand a script moves. A transform the GPU composes — a bone a clip
|
|
723
|
+
* drives — holds the rest pose under wherever the CPU last composed it, so
|
|
724
|
+
* it is evaluated exactly instead, under the clips of every model on its
|
|
725
|
+
* chain: a pole in a hand belongs to one model and hangs from another's
|
|
726
|
+
* bones, and evaluating it under only its own would put it where the hand
|
|
727
|
+
* was in the bind pose.
|
|
728
|
+
*
|
|
729
|
+
* @param {number} entity
|
|
730
|
+
* @param {Float64Array} out
|
|
731
|
+
* @returns {boolean} false when the entity has no pose to give yet — gone,
|
|
732
|
+
* or hanging from a parent that has no transform
|
|
733
|
+
* @private
|
|
734
|
+
*/
|
|
735
|
+
#holder_world(entity, out) {
|
|
736
|
+
const ecd = this.entityManager.dataset;
|
|
737
|
+
|
|
738
|
+
if (!ecd.entityExists(entity)) {
|
|
739
|
+
return false;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
const transform = ecd.getComponent(entity, Transform64);
|
|
743
|
+
|
|
744
|
+
if (transform === undefined) {
|
|
745
|
+
return false;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
let source = transform;
|
|
749
|
+
|
|
750
|
+
if (gpu_authority_has(ecd, entity, GPUStateAuthorityFlags.Transform64)) {
|
|
751
|
+
const playbacks = PLAYBACKS;
|
|
752
|
+
|
|
753
|
+
playbacks.length = 0;
|
|
754
|
+
|
|
755
|
+
// every model on the chain, each once; and a chain that is not
|
|
756
|
+
// complete yet is not one to evaluate
|
|
757
|
+
MODELS.length = 0;
|
|
758
|
+
|
|
759
|
+
for (let e = entity, depth = 0; e >= 0 && depth < 256; depth++) {
|
|
760
|
+
if (!ecd.entityExists(e) || ecd.getComponent(e, Transform64) === undefined) {
|
|
761
|
+
playbacks.length = 0;
|
|
762
|
+
|
|
763
|
+
return false;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
const model = parent_entity_model_of(ecd, e);
|
|
767
|
+
|
|
768
|
+
if (MODELS.indexOf(model) === -1) {
|
|
769
|
+
MODELS.push(model);
|
|
770
|
+
|
|
771
|
+
collect_entity_playbacks(playbacks, this.entityManager, model);
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
e = transform_attachment_parent_of(ecd, e);
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
t64_evaluate_world(EVALUATED, ecd, entity, playbacks);
|
|
778
|
+
|
|
779
|
+
playbacks.length = 0;
|
|
780
|
+
|
|
781
|
+
source = EVALUATED;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
t64_read_pose_array(out, 0, source);
|
|
785
|
+
|
|
786
|
+
return true;
|
|
359
787
|
}
|
|
360
788
|
|
|
361
789
|
/**
|
|
@@ -489,13 +917,14 @@ export class ClothWorld {
|
|
|
489
917
|
}
|
|
490
918
|
|
|
491
919
|
instance.seeded = false;
|
|
492
|
-
instance.
|
|
920
|
+
instance.frame_valid = false;
|
|
493
921
|
|
|
494
922
|
return instance;
|
|
495
923
|
}
|
|
496
924
|
|
|
497
925
|
/**
|
|
498
|
-
* Wake a sleeping cloth.
|
|
926
|
+
* Wake a sleeping cloth. Frame motion, a holder moving or a hold changing,
|
|
927
|
+
* and a `ClothDynamics` change do this
|
|
499
928
|
* on their own; a caller that has changed the world in some way the cloth
|
|
500
929
|
* cannot see — M6's wind, for one — says so here.
|
|
501
930
|
*
|
|
@@ -519,6 +948,37 @@ export class ClothWorld {
|
|
|
519
948
|
return this.__by_entity.get(entity);
|
|
520
949
|
}
|
|
521
950
|
|
|
951
|
+
/**
|
|
952
|
+
* Which particle of a cloth an entity is: a link of a subtree cloth, or a
|
|
953
|
+
* joint of a rigged one — the number a {@link ClothPin} names it by.
|
|
954
|
+
*
|
|
955
|
+
* For code that has the entity rather than the number, which is what a hand
|
|
956
|
+
* closing on a rope has. It answers once the cloth has seeded, which is its
|
|
957
|
+
* first step.
|
|
958
|
+
*
|
|
959
|
+
* @param {number} cloth the entity carrying the `Cloth`
|
|
960
|
+
* @param {number} entity
|
|
961
|
+
* @returns {number} the particle, or `−1` when the entity is not one of the
|
|
962
|
+
* cloth's, or the cloth has not seeded yet
|
|
963
|
+
*/
|
|
964
|
+
particle_of(cloth, entity) {
|
|
965
|
+
const instance = this.__by_entity.get(cloth);
|
|
966
|
+
|
|
967
|
+
if (instance === undefined || !instance.seeded) {
|
|
968
|
+
return -1;
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
const entities = instance.rig === null ? instance.node_entity : instance.node_joint;
|
|
972
|
+
|
|
973
|
+
for (let node = 0; node < instance.node_count; node++) {
|
|
974
|
+
if (entities[node] === entity) {
|
|
975
|
+
return node;
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
return -1;
|
|
980
|
+
}
|
|
981
|
+
|
|
522
982
|
/**
|
|
523
983
|
* Everything that happens once per tick rather than once per cloth.
|
|
524
984
|
*
|
|
@@ -640,9 +1100,9 @@ export class ClothWorld {
|
|
|
640
1100
|
* simulates the joints of the skinned model the entity is showing. There is
|
|
641
1101
|
* no mode field anywhere, and the solver does not know which ran.
|
|
642
1102
|
*
|
|
643
|
-
* A rig can fail to seed for reasons that are not errors —
|
|
644
|
-
*
|
|
645
|
-
* that does is left unseeded for the next step to try again. A rig that
|
|
1103
|
+
* A rig can fail to seed for reasons that are not errors — it names no skin
|
|
1104
|
+
* yet, or the entity it names carries none yet, a model still loading — and
|
|
1105
|
+
* one that does is left unseeded for the next step to try again. A rig that
|
|
646
1106
|
* fails for a reason that *is* an error says so once and then stops, because
|
|
647
1107
|
* a proxy that does not fit its skin will not start fitting it.
|
|
648
1108
|
*
|
|
@@ -659,6 +1119,10 @@ export class ClothWorld {
|
|
|
659
1119
|
|
|
660
1120
|
cloth_seed_subtree(instance, ecd, this.attachments, dt);
|
|
661
1121
|
|
|
1122
|
+
// A new state holds nothing yet: the holds — offsets and all — are
|
|
1123
|
+
// applied to it on its first step.
|
|
1124
|
+
instance.holds_applied = -1;
|
|
1125
|
+
|
|
662
1126
|
return;
|
|
663
1127
|
}
|
|
664
1128
|
|
|
@@ -673,21 +1137,16 @@ export class ClothWorld {
|
|
|
673
1137
|
return;
|
|
674
1138
|
}
|
|
675
1139
|
|
|
676
|
-
|
|
677
|
-
|
|
1140
|
+
const skin = rig.skin === -1 || !ecd.entityExists(rig.skin)
|
|
1141
|
+
? undefined
|
|
1142
|
+
: ecd.getComponent(rig.skin, MeshSkin);
|
|
678
1143
|
|
|
1144
|
+
if (skin === undefined) {
|
|
1145
|
+
// Not named yet, or not there yet: still loading. Not an error, and
|
|
1146
|
+
// not worth a message.
|
|
679
1147
|
return;
|
|
680
1148
|
}
|
|
681
1149
|
|
|
682
|
-
const model = this.models.instance_of(instance.entity);
|
|
683
|
-
|
|
684
|
-
if (model === null || model === undefined) {
|
|
685
|
-
// Still loading. Not an error, and not worth a message.
|
|
686
|
-
return;
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
const skin = model.skins[rig.skin];
|
|
690
|
-
|
|
691
1150
|
const error = rig.proxy.checkAgainst(skin);
|
|
692
1151
|
|
|
693
1152
|
if (error !== "") {
|
|
@@ -699,6 +1158,8 @@ export class ClothWorld {
|
|
|
699
1158
|
instance.rig = rig;
|
|
700
1159
|
|
|
701
1160
|
cloth_seed_rig(instance, rig.proxy, skin.joints, ecd, dt);
|
|
1161
|
+
|
|
1162
|
+
instance.holds_applied = -1;
|
|
702
1163
|
}
|
|
703
1164
|
|
|
704
1165
|
/**
|
|
@@ -720,8 +1181,9 @@ export class ClothWorld {
|
|
|
720
1181
|
|
|
721
1182
|
/**
|
|
722
1183
|
* Carry one seeded cloth to the edge of its step and write the parameters
|
|
723
|
-
* the step will run on: whatever the
|
|
724
|
-
* the leash rows measure from, and the colliders
|
|
1184
|
+
* the step will run on: whatever the frame and the holders did, where the
|
|
1185
|
+
* held particles go, where the leash rows measure from, and the colliders
|
|
1186
|
+
* within reach.
|
|
725
1187
|
*
|
|
726
1188
|
* @param {ClothInstance} instance
|
|
727
1189
|
* @param {number} dt seconds
|
|
@@ -760,7 +1222,7 @@ export class ClothWorld {
|
|
|
760
1222
|
|
|
761
1223
|
const transform = instance.rig === null
|
|
762
1224
|
? instance.transform
|
|
763
|
-
: this.#
|
|
1225
|
+
: this.#frame_pose(instance);
|
|
764
1226
|
|
|
765
1227
|
const tx = transform[TRANSFORM64_TRANSLATION_OFFSET];
|
|
766
1228
|
const ty = transform[TRANSFORM64_TRANSLATION_OFFSET + 1];
|
|
@@ -771,15 +1233,38 @@ export class ClothWorld {
|
|
|
771
1233
|
const qz = transform[TRANSFORM64_ROTATION_OFFSET + 2];
|
|
772
1234
|
const qw = transform[TRANSFORM64_ROTATION_OFFSET + 3];
|
|
773
1235
|
|
|
774
|
-
const previous_translation = instance.
|
|
775
|
-
const previous_rotation = instance.
|
|
1236
|
+
const previous_translation = instance.frame_translation;
|
|
1237
|
+
const previous_rotation = instance.frame_rotation;
|
|
1238
|
+
|
|
1239
|
+
FRAME_TRANSLATION[0] = tx;
|
|
1240
|
+
FRAME_TRANSLATION[1] = ty;
|
|
1241
|
+
FRAME_TRANSLATION[2] = tz;
|
|
1242
|
+
|
|
1243
|
+
FRAME_ROTATION[0] = qx;
|
|
1244
|
+
FRAME_ROTATION[1] = qy;
|
|
1245
|
+
FRAME_ROTATION[2] = qz;
|
|
1246
|
+
FRAME_ROTATION[3] = qw;
|
|
1247
|
+
|
|
1248
|
+
// What holds the cloth, before anything that might decide it is asleep:
|
|
1249
|
+
// a hold appearing or going is a reason to wake, and so is a holder
|
|
1250
|
+
// moving.
|
|
1251
|
+
this.#sync_holds(instance);
|
|
1252
|
+
|
|
1253
|
+
const holders_moved = this.#evaluate_holds(instance, FRAME_TRANSLATION, FRAME_ROTATION);
|
|
1254
|
+
|
|
1255
|
+
// Positions are still in the frame they were last stepped in, which on
|
|
1256
|
+
// a cloth's first step is this one; a hold begins where its particles
|
|
1257
|
+
// are, so that is the frame its offsets are taken in.
|
|
1258
|
+
const holds_changed = instance.frame_valid
|
|
1259
|
+
? this.#refresh_holds(instance, previous_translation, previous_rotation)
|
|
1260
|
+
: this.#refresh_holds(instance, FRAME_TRANSLATION, FRAME_ROTATION);
|
|
776
1261
|
|
|
777
1262
|
if (instance.cloth.blend !== instance.blend_seen) {
|
|
778
1263
|
instance.asleep = false;
|
|
779
1264
|
instance.still_steps = 0;
|
|
780
1265
|
}
|
|
781
1266
|
|
|
782
|
-
const moved = instance.
|
|
1267
|
+
const moved = instance.frame_valid && (
|
|
783
1268
|
previous_translation[0] !== tx
|
|
784
1269
|
|| previous_translation[1] !== ty
|
|
785
1270
|
|| previous_translation[2] !== tz
|
|
@@ -789,7 +1274,7 @@ export class ClothWorld {
|
|
|
789
1274
|
|| previous_rotation[3] !== qw
|
|
790
1275
|
);
|
|
791
1276
|
|
|
792
|
-
if (moved) {
|
|
1277
|
+
if (moved || holders_moved || holds_changed) {
|
|
793
1278
|
instance.asleep = false;
|
|
794
1279
|
instance.still_steps = 0;
|
|
795
1280
|
}
|
|
@@ -814,7 +1299,7 @@ export class ClothWorld {
|
|
|
814
1299
|
// cheaper than the step it decides whether to skip.
|
|
815
1300
|
if (cloth_air_changed(
|
|
816
1301
|
instance.state, this.wind,
|
|
817
|
-
instance.
|
|
1302
|
+
instance.frame_translation, instance.frame_rotation,
|
|
818
1303
|
instance.air_seen, CLOTH_SLEEP_SPEED_RATIO * instance.reach,
|
|
819
1304
|
instance.age
|
|
820
1305
|
)) {
|
|
@@ -831,33 +1316,58 @@ export class ClothWorld {
|
|
|
831
1316
|
return false;
|
|
832
1317
|
}
|
|
833
1318
|
|
|
834
|
-
|
|
835
|
-
|
|
1319
|
+
// §7 P6. Locomotion moves a frame a fraction of the cloth's own reach a
|
|
1320
|
+
// step; a jump past this is something else, whether it is the frame
|
|
1321
|
+
// that jumped or something holding the cloth, measured in the frame.
|
|
1322
|
+
const threshold = Math.max(CLOTH_TELEPORT_REACH * instance.reach, CLOTH_TELEPORT_FLOOR);
|
|
836
1323
|
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
1324
|
+
const frame_jumped = moved && Math.hypot(
|
|
1325
|
+
tx - previous_translation[0], ty - previous_translation[1], tz - previous_translation[2]
|
|
1326
|
+
) > threshold;
|
|
1327
|
+
|
|
1328
|
+
let holder_jumped = false;
|
|
1329
|
+
|
|
1330
|
+
const holds = instance.holds;
|
|
1331
|
+
|
|
1332
|
+
for (let h = 0; h < holds.length; h++) {
|
|
1333
|
+
const hold = holds[h];
|
|
1334
|
+
|
|
1335
|
+
if (!hold.valid || !hold.has_previous || !hold.captured) {
|
|
1336
|
+
continue;
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
const pose = hold.pose;
|
|
1340
|
+
const before = hold.pose_previous;
|
|
1341
|
+
|
|
1342
|
+
if (Math.hypot(pose[0] - before[0], pose[1] - before[1], pose[2] - before[2]) > threshold) {
|
|
1343
|
+
holder_jumped = true;
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
841
1346
|
|
|
842
|
-
|
|
843
|
-
|
|
1347
|
+
const keep = (instance.cloth.flags & ClothFlags.TeleportKeep) !== 0;
|
|
1348
|
+
|
|
1349
|
+
let reset = false;
|
|
1350
|
+
|
|
1351
|
+
if (frame_jumped || holder_jumped) {
|
|
1352
|
+
instance.teleport_count++;
|
|
1353
|
+
|
|
1354
|
+
if (keep) {
|
|
1355
|
+
instance.holds_dirty = true;
|
|
1356
|
+
|
|
1357
|
+
// The frame's jump needs nothing: the particles are in its frame.
|
|
1358
|
+
// A holder's is carried onto what hangs from it.
|
|
1359
|
+
for (let h = 0; h < holds.length; h++) {
|
|
1360
|
+
const hold = holds[h];
|
|
1361
|
+
|
|
1362
|
+
if (hold.valid && hold.has_previous && hold.captured) {
|
|
1363
|
+
carry_with_holder(instance, h);
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
844
1366
|
} else {
|
|
845
|
-
|
|
846
|
-
// wherever the call was not inlined
|
|
847
|
-
ANCHOR_POSE[0] = tx;
|
|
848
|
-
ANCHOR_POSE[1] = ty;
|
|
849
|
-
ANCHOR_POSE[2] = tz;
|
|
850
|
-
ANCHOR_POSE[3] = qx;
|
|
851
|
-
ANCHOR_POSE[4] = qy;
|
|
852
|
-
ANCHOR_POSE[5] = qz;
|
|
853
|
-
ANCHOR_POSE[6] = qw;
|
|
854
|
-
|
|
855
|
-
move_local_frame(instance, ANCHOR_POSE, previous_translation, previous_rotation);
|
|
1367
|
+
reset = true;
|
|
856
1368
|
}
|
|
857
|
-
} else if (
|
|
858
|
-
|
|
859
|
-
// move_local_frame without rewriting every free position/velocity.
|
|
860
|
-
pin_anchor(instance);
|
|
1369
|
+
} else if (moved) {
|
|
1370
|
+
move_local_frame(instance, FRAME_TRANSLATION, FRAME_ROTATION, previous_translation, previous_rotation);
|
|
861
1371
|
}
|
|
862
1372
|
|
|
863
1373
|
previous_translation[0] = tx;
|
|
@@ -869,13 +1379,30 @@ export class ClothWorld {
|
|
|
869
1379
|
previous_rotation[2] = qz;
|
|
870
1380
|
previous_rotation[3] = qw;
|
|
871
1381
|
|
|
872
|
-
instance.
|
|
1382
|
+
instance.frame_valid = true;
|
|
1383
|
+
|
|
1384
|
+
// Where every held particle goes, the pose hung from them, the leash
|
|
1385
|
+
// centres — from this step's holder poses.
|
|
1386
|
+
cloth_hold_step(instance);
|
|
1387
|
+
|
|
1388
|
+
if (reset) {
|
|
1389
|
+
this.#reset(instance);
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
for (let h = 0; h < holds.length; h++) {
|
|
1393
|
+
const hold = holds[h];
|
|
1394
|
+
|
|
1395
|
+
if (hold.valid) {
|
|
1396
|
+
hold.pose_previous.set(hold.pose);
|
|
1397
|
+
hold.world_previous.set(hold.world);
|
|
873
1398
|
|
|
874
|
-
|
|
1399
|
+
hold.has_previous = true;
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
875
1402
|
|
|
876
1403
|
const dynamics = instance.cloth.dynamics;
|
|
877
1404
|
|
|
878
|
-
// Gravity is a world vector and the solve is in the
|
|
1405
|
+
// Gravity is a world vector and the solve is in the cloth's frame.
|
|
879
1406
|
const gravity = this.gravity;
|
|
880
1407
|
|
|
881
1408
|
// `previous_rotation` has just been set to this step's `q`; vector and rotation go in as arrays
|
|
@@ -894,7 +1421,8 @@ export class ClothWorld {
|
|
|
894
1421
|
// nothing beyond it — `cloth_gather_reach` carries the derivation,
|
|
895
1422
|
// and why the velocity clamp that used to stand here was both far
|
|
896
1423
|
// too wide and missing two terms.
|
|
897
|
-
|
|
1424
|
+
// and as far again as a holder drags it, which no velocity says
|
|
1425
|
+
const reach = cloth_gather_reach(state, this.colliders.index, dt) + instance.kinematic_travel;
|
|
898
1426
|
|
|
899
1427
|
cloth_gather_colliders(instance, this.colliders.index, reach);
|
|
900
1428
|
|
|
@@ -921,7 +1449,7 @@ export class ClothWorld {
|
|
|
921
1449
|
|
|
922
1450
|
instance.air_varies = cloth_sample_air(
|
|
923
1451
|
state, this.wind,
|
|
924
|
-
instance.
|
|
1452
|
+
instance.frame_translation, instance.frame_rotation,
|
|
925
1453
|
instance.air_seen, instance.age
|
|
926
1454
|
);
|
|
927
1455
|
} else {
|
|
@@ -929,6 +1457,7 @@ export class ClothWorld {
|
|
|
929
1457
|
}
|
|
930
1458
|
|
|
931
1459
|
params[offset + ClothStepParam.DRAG_RESPONSE] = drag_response;
|
|
1460
|
+
params[offset + ClothStepParam.KINEMATIC_TRAVEL] = instance.kinematic_travel;
|
|
932
1461
|
|
|
933
1462
|
const self_collision = (dynamics.flags & ClothDynamicsFlags.SelfCollision) !== 0;
|
|
934
1463
|
|
|
@@ -980,8 +1509,10 @@ export class ClothWorld {
|
|
|
980
1509
|
}
|
|
981
1510
|
|
|
982
1511
|
/**
|
|
983
|
-
*
|
|
984
|
-
* entity is playing
|
|
1512
|
+
* A rig's frame joint's world pose, computed on the CPU from the clips the
|
|
1513
|
+
* entity is playing — and, while the playbacks are in hand, the pose in that
|
|
1514
|
+
* frame of every bone the garment hangs from, for the write-back to express
|
|
1515
|
+
* the garment's roots against.
|
|
985
1516
|
*
|
|
986
1517
|
* **Computed, never read back**, for two reasons that are both the engine's
|
|
987
1518
|
* own. A joint of an animated skeleton is the GPU's (`GPUStateAuthority`),
|
|
@@ -997,36 +1528,58 @@ export class ClothWorld {
|
|
|
997
1528
|
* @returns {Transform64}
|
|
998
1529
|
* @private
|
|
999
1530
|
*/
|
|
1000
|
-
#
|
|
1531
|
+
#frame_pose(instance) {
|
|
1001
1532
|
const playbacks = PLAYBACKS;
|
|
1002
1533
|
|
|
1003
1534
|
playbacks.length = 0;
|
|
1004
1535
|
|
|
1005
1536
|
collect_entity_playbacks(playbacks, this.entityManager, instance.entity);
|
|
1006
1537
|
|
|
1007
|
-
|
|
1538
|
+
const ecd = this.entityManager.dataset;
|
|
1539
|
+
|
|
1540
|
+
const frame = instance.frame_pose;
|
|
1541
|
+
|
|
1542
|
+
t64_evaluate_world(frame, ecd, instance.frame_entity, playbacks);
|
|
1543
|
+
|
|
1544
|
+
const node_output = instance.node_output;
|
|
1545
|
+
const boundary = instance.boundary_pose;
|
|
1546
|
+
|
|
1547
|
+
for (let node = 0; node < instance.node_count; node++) {
|
|
1548
|
+
if (node_output[node] !== 0) {
|
|
1549
|
+
continue;
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
t64_evaluate_world(EVALUATED, ecd, instance.node_joint[node], playbacks);
|
|
1553
|
+
|
|
1554
|
+
const b = node * 7;
|
|
1555
|
+
|
|
1556
|
+
pose3_to_local_array(
|
|
1557
|
+
boundary, b,
|
|
1558
|
+
boundary, b + 3,
|
|
1559
|
+
frame, TRANSFORM64_TRANSLATION_OFFSET,
|
|
1560
|
+
frame, TRANSFORM64_ROTATION_OFFSET,
|
|
1561
|
+
EVALUATED, TRANSFORM64_TRANSLATION_OFFSET,
|
|
1562
|
+
EVALUATED, TRANSFORM64_ROTATION_OFFSET
|
|
1563
|
+
);
|
|
1564
|
+
}
|
|
1008
1565
|
|
|
1009
1566
|
playbacks.length = 0;
|
|
1010
1567
|
|
|
1011
|
-
return
|
|
1568
|
+
return frame;
|
|
1012
1569
|
}
|
|
1013
1570
|
|
|
1014
1571
|
/**
|
|
1572
|
+
* §7 P6's `Reset`: every particle onto the animated pose — the rest pose
|
|
1573
|
+
* hung from where its holders now are — at rest, with nothing carried over.
|
|
1574
|
+
*
|
|
1575
|
+
* A held particle lands on its target, and its target is where the predict
|
|
1576
|
+
* carries it to, so it does not move again this step: the jump is taken
|
|
1577
|
+
* between steps rather than dragged through one.
|
|
1578
|
+
*
|
|
1015
1579
|
* @param {ClothInstance} instance
|
|
1016
1580
|
* @private
|
|
1017
1581
|
*/
|
|
1018
|
-
#
|
|
1019
|
-
instance.teleport_count++;
|
|
1020
|
-
|
|
1021
|
-
if ((instance.cloth.flags & ClothFlags.TeleportKeep) !== 0) {
|
|
1022
|
-
// `Keep` carries the cloth's shape across the jump. Particles are
|
|
1023
|
-
// stored relative to the anchor, so that is exactly what happens if
|
|
1024
|
-
// this function does nothing to them — the frame moved and they did
|
|
1025
|
-
// not, which is MagicaCloth2's rigid delta expressed in the frame
|
|
1026
|
-
// that makes it free.
|
|
1027
|
-
return;
|
|
1028
|
-
}
|
|
1029
|
-
|
|
1582
|
+
#reset(instance) {
|
|
1030
1583
|
const state = instance.state;
|
|
1031
1584
|
|
|
1032
1585
|
const node_count = instance.node_count;
|
|
@@ -1043,6 +1596,10 @@ export class ClothWorld {
|
|
|
1043
1596
|
}
|
|
1044
1597
|
|
|
1045
1598
|
state.position_previous.set(state.position);
|
|
1599
|
+
state.kinematic_target.set(state.position);
|
|
1600
|
+
|
|
1601
|
+
instance.kinematic_travel = 0;
|
|
1602
|
+
instance.holds_dirty = true;
|
|
1046
1603
|
state.velocity.fill(0);
|
|
1047
1604
|
state.inertia_blend.fill(0);
|
|
1048
1605
|
|
|
@@ -1078,54 +1635,62 @@ const LOCAL_GRAVITY = new Float64Array(3);
|
|
|
1078
1635
|
const FRAME = new Float64Array(8);
|
|
1079
1636
|
|
|
1080
1637
|
/**
|
|
1081
|
-
* The
|
|
1638
|
+
* The frame's translation and rotation this step, apart, as the holds and {@link move_local_frame}
|
|
1639
|
+
* take them: the transform read once, before anything this step could write it.
|
|
1082
1640
|
* @type {Float64Array}
|
|
1083
1641
|
* @private
|
|
1084
1642
|
*/
|
|
1085
|
-
const
|
|
1643
|
+
const FRAME_TRANSLATION = new Float64Array(3);
|
|
1086
1644
|
|
|
1087
1645
|
/**
|
|
1088
|
-
* {@link move_local_frame}'s `q_now⁻¹`, `[-qx, -qy, -qz, qw]`.
|
|
1089
1646
|
* @type {Float64Array}
|
|
1090
1647
|
* @private
|
|
1091
1648
|
*/
|
|
1092
|
-
const
|
|
1649
|
+
const FRAME_ROTATION = new Float64Array(4);
|
|
1093
1650
|
|
|
1094
1651
|
/**
|
|
1095
|
-
*
|
|
1096
|
-
*
|
|
1097
|
-
* @type {
|
|
1652
|
+
* An exactly evaluated world pose: a holder a clip drives, a bone a garment
|
|
1653
|
+
* hangs from.
|
|
1654
|
+
* @type {Transform64}
|
|
1098
1655
|
* @private
|
|
1099
1656
|
*/
|
|
1100
|
-
const
|
|
1657
|
+
const EVALUATED = new Transform64();
|
|
1101
1658
|
|
|
1102
1659
|
/**
|
|
1103
|
-
*
|
|
1660
|
+
* The models a holder's chain passes through, each once.
|
|
1661
|
+
* @type {number[]}
|
|
1662
|
+
* @private
|
|
1663
|
+
*/
|
|
1664
|
+
const MODELS = [];
|
|
1665
|
+
|
|
1666
|
+
/**
|
|
1667
|
+
* Carry the free particles across a change of frame pose, by however much of it the
|
|
1104
1668
|
* fabric is willing to feel. §7 P7.
|
|
1105
1669
|
*
|
|
1106
1670
|
* A particle at local `p` was at world `t_prev + q_prev·p`. Holding that world
|
|
1107
1671
|
* position fixed, its local coordinates become `D + Q·p` with
|
|
1108
1672
|
* `D = q_now⁻¹·(t_prev − t_now)` and `Q = q_now⁻¹ ⊗ q_prev`. Feeling *all* of
|
|
1109
|
-
* the
|
|
1673
|
+
* the frame's motion is taking that; feeling *none* is leaving `p` alone; and
|
|
1110
1674
|
* `inertia` is the lerp between them. Velocity is carried the same way, minus
|
|
1111
1675
|
* the translation, since a translation of the frame does not rotate a vector.
|
|
1112
1676
|
*
|
|
1113
1677
|
* `D` and `Q` are limited before the lerp. The limits are the cloth's own reach
|
|
1114
|
-
* per step and a fixed angle per step, which is what makes
|
|
1678
|
+
* per step and a fixed angle per step, which is what makes a frame that
|
|
1115
1679
|
* teleports a metre — or spins — something a cape *lags behind* rather than
|
|
1116
1680
|
* something it is fired out of.
|
|
1117
1681
|
*
|
|
1118
1682
|
* Every vector and quaternion goes to its function as an array and an offset: handed over as numbers,
|
|
1119
1683
|
* each was boxed into a heap object wherever the call was not inlined, which until V8 optimises this
|
|
1120
|
-
* is every call, twice per particle per step of a moving
|
|
1684
|
+
* is every call, twice per particle per step of a moving frame.
|
|
1121
1685
|
*
|
|
1122
1686
|
* @param {ClothInstance} instance
|
|
1123
|
-
* @param {Float64Array}
|
|
1687
|
+
* @param {Float64Array} translation the frame's translation now
|
|
1688
|
+
* @param {Float64Array} rotation the frame's rotation now
|
|
1124
1689
|
* @param {Float64Array} previous_translation
|
|
1125
1690
|
* @param {Float64Array} previous_rotation
|
|
1126
1691
|
* @private
|
|
1127
1692
|
*/
|
|
1128
|
-
function move_local_frame(instance,
|
|
1693
|
+
function move_local_frame(instance, translation, rotation, previous_translation, previous_rotation) {
|
|
1129
1694
|
let inertia = instance.cloth.dynamics.inertia;
|
|
1130
1695
|
|
|
1131
1696
|
if (inertia <= 0) {
|
|
@@ -1136,13 +1701,10 @@ function move_local_frame(instance, pose, previous_translation, previous_rotatio
|
|
|
1136
1701
|
inertia = 1;
|
|
1137
1702
|
}
|
|
1138
1703
|
|
|
1139
|
-
|
|
1140
|
-
FRAME
|
|
1141
|
-
FRAME[2] = previous_translation[2] - pose[2];
|
|
1142
|
-
|
|
1143
|
-
v3_quaternion_apply_inverse_array(FRAME, 0, FRAME, 0, pose, 3);
|
|
1704
|
+
// the previous pose in the frame now: D and Q
|
|
1705
|
+
pose3_to_local_array(FRAME, 0, FRAME, 4, translation, 0, rotation, 0, previous_translation, 0, previous_rotation, 0);
|
|
1144
1706
|
|
|
1145
|
-
const travel_limit =
|
|
1707
|
+
const travel_limit = CLOTH_FRAME_TRAVEL_REACH * instance.reach;
|
|
1146
1708
|
|
|
1147
1709
|
const travel = Math.hypot(FRAME[0], FRAME[1], FRAME[2]);
|
|
1148
1710
|
|
|
@@ -1154,21 +1716,10 @@ function move_local_frame(instance, pose, previous_translation, previous_rotatio
|
|
|
1154
1716
|
FRAME[2] *= scale;
|
|
1155
1717
|
}
|
|
1156
1718
|
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
quat3_multiply_array(FRAME, 4, POSE_CONJUGATE, 0, previous_rotation, 0);
|
|
1163
|
-
|
|
1164
|
-
// `|w|` is `cos(θ/2)`, so this is the angle test without an `acos`.
|
|
1165
|
-
const half_angle_cos = FRAME[7] < 0 ? -FRAME[7] : FRAME[7];
|
|
1166
|
-
|
|
1167
|
-
if (half_angle_cos < Math.cos(CLOTH_ANCHOR_ROTATION_LIMIT * 0.5)) {
|
|
1168
|
-
const angle = 2 * Math.acos(half_angle_cos > 1 ? 1 : half_angle_cos);
|
|
1169
|
-
|
|
1170
|
-
quat3_nlerp_array(FRAME, 4, IDENTITY_ROTATION, 0, FRAME, 4, CLOTH_ANCHOR_ROTATION_LIMIT / angle);
|
|
1171
|
-
}
|
|
1719
|
+
// Exactly the limit about the same axis. An nlerp from the identity by `limit / θ` follows the
|
|
1720
|
+
// chord and turned less than the limit the further past it the frame spun: three quarters of it
|
|
1721
|
+
// at a half turn.
|
|
1722
|
+
quat3_clamp_angle_array(FRAME, 4, FRAME, 4, CLOTH_FRAME_ROTATION_LIMIT);
|
|
1172
1723
|
|
|
1173
1724
|
const state = instance.state;
|
|
1174
1725
|
|
|
@@ -1181,7 +1732,16 @@ function move_local_frame(instance, pose, previous_translation, previous_rotatio
|
|
|
1181
1732
|
const dy = FRAME[1];
|
|
1182
1733
|
const dz = FRAME[2];
|
|
1183
1734
|
|
|
1735
|
+
const mass_inverse = state.mass_inverse;
|
|
1736
|
+
|
|
1184
1737
|
for (let i = 0; i < particle_count; i++) {
|
|
1738
|
+
// A held particle belongs to its holder, not to the world: it goes where
|
|
1739
|
+
// its holder takes it, through the step, and not where the frame's
|
|
1740
|
+
// motion would have left it.
|
|
1741
|
+
if (mass_inverse[i] === 0) {
|
|
1742
|
+
continue;
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1185
1745
|
const p = i * 3;
|
|
1186
1746
|
|
|
1187
1747
|
v3_quaternion_apply_array(CARRIED, 0, position, p, FRAME, 4);
|
|
@@ -1196,30 +1756,60 @@ function move_local_frame(instance, pose, previous_translation, previous_rotatio
|
|
|
1196
1756
|
velocity[p + 1] += inertia * (CARRIED[1] - velocity[p + 1]);
|
|
1197
1757
|
velocity[p + 2] += inertia * (CARRIED[2] - velocity[p + 2]);
|
|
1198
1758
|
}
|
|
1199
|
-
|
|
1200
|
-
pin_anchor(instance);
|
|
1201
1759
|
}
|
|
1202
1760
|
|
|
1203
1761
|
/**
|
|
1762
|
+
* `ClothFlags.TeleportKeep` for a holder that jumped: its own jump, in the
|
|
1763
|
+
* frame, applied to everything hanging from it — the particles it holds and
|
|
1764
|
+
* every free one whose nearest held particle is one of them — positions and
|
|
1765
|
+
* velocities alike. What hangs from another holder stays where it is.
|
|
1766
|
+
*
|
|
1204
1767
|
* @param {ClothInstance} instance
|
|
1768
|
+
* @param {number} h index into {@link ClothInstance#holds}
|
|
1205
1769
|
* @private
|
|
1206
1770
|
*/
|
|
1207
|
-
function
|
|
1208
|
-
const
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
velocity
|
|
1219
|
-
|
|
1220
|
-
|
|
1771
|
+
function carry_with_holder(instance, h) {
|
|
1772
|
+
const hold = instance.holds[h];
|
|
1773
|
+
|
|
1774
|
+
const now = hold.pose;
|
|
1775
|
+
const before = hold.pose_previous;
|
|
1776
|
+
|
|
1777
|
+
// the jump's rotation, q_now ⊗ q_before⁻¹
|
|
1778
|
+
quat3_multiply_conjugate_right_array(JUMP, 0, now, 3, before, 3);
|
|
1779
|
+
|
|
1780
|
+
const state = instance.state;
|
|
1781
|
+
const position = state.position;
|
|
1782
|
+
const velocity = state.velocity;
|
|
1783
|
+
|
|
1784
|
+
const node_hold = instance.node_hold;
|
|
1785
|
+
const source = instance.tether_source;
|
|
1786
|
+
const particle_of_node = instance.particle_of_node;
|
|
1787
|
+
|
|
1788
|
+
for (let node = 0; node < instance.node_count; node++) {
|
|
1789
|
+
const owner = node_hold[node] !== -1 ? node_hold[node] : (source[node] === -1 ? -1 : node_hold[source[node]]);
|
|
1790
|
+
|
|
1791
|
+
if (owner !== h) {
|
|
1792
|
+
continue;
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
const p = particle_of_node[node] * 3;
|
|
1796
|
+
|
|
1797
|
+
CARRIED[0] = position[p] - before[0];
|
|
1798
|
+
CARRIED[1] = position[p + 1] - before[1];
|
|
1799
|
+
CARRIED[2] = position[p + 2] - before[2];
|
|
1800
|
+
|
|
1801
|
+
pose3_apply_point_array(position, p, now, 0, JUMP, 0, CARRIED, 0);
|
|
1802
|
+
|
|
1803
|
+
v3_quaternion_apply_array(velocity, p, velocity, p, JUMP, 0);
|
|
1804
|
+
}
|
|
1221
1805
|
}
|
|
1222
1806
|
|
|
1807
|
+
/**
|
|
1808
|
+
* @type {Float64Array}
|
|
1809
|
+
* @private
|
|
1810
|
+
*/
|
|
1811
|
+
const JUMP = new Float64Array(4);
|
|
1812
|
+
|
|
1223
1813
|
/**
|
|
1224
1814
|
* @type {Float64Array}
|
|
1225
1815
|
* @private
|
|
@@ -1285,46 +1875,3 @@ function cloth_inside_sleep_window(instance) {
|
|
|
1285
1875
|
return true;
|
|
1286
1876
|
}
|
|
1287
1877
|
|
|
1288
|
-
/**
|
|
1289
|
-
* Point every leash row at where it measures from: a slack row at the
|
|
1290
|
-
* particle's animated position, a tether at the anchor.
|
|
1291
|
-
*
|
|
1292
|
-
* @param {ClothInstance} instance
|
|
1293
|
-
* @private
|
|
1294
|
-
*/
|
|
1295
|
-
function refresh_leash_targets(instance) {
|
|
1296
|
-
const state = instance.state;
|
|
1297
|
-
|
|
1298
|
-
const target = state.leash_target;
|
|
1299
|
-
|
|
1300
|
-
const animated = instance.animated_position;
|
|
1301
|
-
|
|
1302
|
-
const anchor = instance.particle_of_node[0] * 3;
|
|
1303
|
-
|
|
1304
|
-
const anchor_x = state.position[anchor];
|
|
1305
|
-
const anchor_y = state.position[anchor + 1];
|
|
1306
|
-
const anchor_z = state.position[anchor + 2];
|
|
1307
|
-
|
|
1308
|
-
const node_count = instance.node_count;
|
|
1309
|
-
|
|
1310
|
-
const slack_row = instance.slack_row;
|
|
1311
|
-
const tether_row = instance.tether_row;
|
|
1312
|
-
|
|
1313
|
-
for (let node = 1; node < node_count; node++) {
|
|
1314
|
-
const tether = tether_row[node];
|
|
1315
|
-
|
|
1316
|
-
if (tether >= 0) {
|
|
1317
|
-
target[tether * 3] = anchor_x;
|
|
1318
|
-
target[tether * 3 + 1] = anchor_y;
|
|
1319
|
-
target[tether * 3 + 2] = anchor_z;
|
|
1320
|
-
}
|
|
1321
|
-
|
|
1322
|
-
const slack = slack_row[node];
|
|
1323
|
-
|
|
1324
|
-
if (slack >= 0) {
|
|
1325
|
-
target[slack * 3] = animated[node * 3];
|
|
1326
|
-
target[slack * 3 + 1] = animated[node * 3 + 1];
|
|
1327
|
-
target[slack * 3 + 2] = animated[node * 3 + 2];
|
|
1328
|
-
}
|
|
1329
|
-
}
|
|
1330
|
-
}
|