@woosh/meep-engine 3.22.0 → 3.23.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/package.json +1 -1
- package/src/core/geom/3d/hash-grid/PointHashGrid3.d.ts +118 -0
- package/src/core/geom/3d/hash-grid/PointHashGrid3.d.ts.map +1 -0
- package/src/core/geom/3d/hash-grid/PointHashGrid3.js +283 -0
- package/src/core/geom/3d/shape/BoxShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/BoxShape3D.js +6 -17
- package/src/core/geom/3d/shape/CapsuleShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/CapsuleShape3D.js +3 -14
- package/src/core/geom/3d/shape/CylinderShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/CylinderShape3D.js +3 -21
- package/src/core/geom/3d/shape/PlaneShape3D.d.ts +105 -0
- package/src/core/geom/3d/shape/PlaneShape3D.d.ts.map +1 -0
- package/src/core/geom/3d/shape/PlaneShape3D.js +251 -0
- package/src/core/geom/3d/shape/SphereShape3D.js +3 -3
- package/src/core/geom/3d/shape/json/shape_to_type.d.ts.map +1 -1
- package/src/core/geom/3d/shape/json/shape_to_type.js +3 -0
- package/src/core/geom/3d/shape/json/type_adapters.d.ts +14 -0
- package/src/core/geom/3d/shape/json/type_adapters.d.ts.map +1 -1
- package/src/core/geom/3d/shape/json/type_adapters.js +15 -0
- package/src/core/geom/3d/shape/sdf/sdf3_box.d.ts +51 -0
- package/src/core/geom/3d/shape/sdf/sdf3_box.d.ts.map +1 -0
- package/src/core/geom/3d/shape/sdf/sdf3_box.js +113 -0
- package/src/core/geom/3d/shape/sdf/sdf3_capsule.d.ts +46 -0
- package/src/core/geom/3d/shape/sdf/sdf3_capsule.d.ts.map +1 -0
- package/src/core/geom/3d/shape/sdf/sdf3_capsule.js +82 -0
- package/src/core/geom/3d/shape/sdf/sdf3_cylinder.d.ts +60 -0
- package/src/core/geom/3d/shape/sdf/sdf3_cylinder.d.ts.map +1 -0
- package/src/core/geom/3d/shape/sdf/sdf3_cylinder.js +126 -0
- package/src/core/geom/3d/shape/sdf/sdf3_degenerate_normal.d.ts +50 -0
- package/src/core/geom/3d/shape/sdf/sdf3_degenerate_normal.d.ts.map +1 -0
- package/src/core/geom/3d/shape/sdf/sdf3_degenerate_normal.js +53 -0
- package/src/core/geom/3d/shape/sdf/sdf3_plane.d.ts +52 -0
- package/src/core/geom/3d/shape/sdf/sdf3_plane.d.ts.map +1 -0
- package/src/core/geom/3d/shape/sdf/sdf3_plane.js +61 -0
- package/src/core/geom/3d/shape/sdf/sdf3_sphere.d.ts +41 -0
- package/src/core/geom/3d/shape/sdf/sdf3_sphere.d.ts.map +1 -0
- package/src/core/geom/3d/shape/sdf/sdf3_sphere.js +71 -0
- package/src/core/process/ConcurrencyGate.d.ts +103 -0
- package/src/core/process/ConcurrencyGate.d.ts.map +1 -0
- package/src/core/process/ConcurrencyGate.js +207 -0
- package/src/engine/asset/AssetManager.d.ts +10 -0
- package/src/engine/asset/AssetManager.d.ts.map +1 -1
- package/src/engine/asset/AssetManager.js +10 -0
- package/src/engine/graphics/CONTEXT_LOSS_RECOVERY_PLAN.md +30 -13
- package/src/engine/graphics3/pose/collect_entity_playbacks.d.ts +26 -0
- package/src/engine/graphics3/pose/collect_entity_playbacks.d.ts.map +1 -0
- package/src/engine/graphics3/pose/collect_entity_playbacks.js +40 -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 +74 -101
- package/src/engine/physics/cloth/MEASUREMENTS.md +1287 -4
- package/src/engine/physics/cloth/PLAN.md +1967 -1581
- package/src/engine/physics/cloth/build/ClothProxy.d.ts +147 -0
- package/src/engine/physics/cloth/build/ClothProxy.d.ts.map +1 -0
- package/src/engine/physics/cloth/build/ClothProxy.js +207 -0
- package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts +70 -0
- package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts.map +1 -0
- package/src/engine/physics/cloth/build/cloth_proxy_from_joints.js +256 -0
- package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts +176 -0
- package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts.map +1 -0
- package/src/engine/physics/cloth/collider/ClothColliderIndex.js +435 -0
- package/src/engine/physics/cloth/collider/ClothColliderKind.d.ts +12 -0
- package/src/engine/physics/cloth/collider/ClothColliderKind.d.ts.map +1 -0
- package/src/engine/physics/cloth/collider/ClothColliderKind.js +38 -0
- package/src/engine/physics/cloth/collider/ClothColliderRecord.d.ts +120 -0
- package/src/engine/physics/cloth/collider/ClothColliderRecord.d.ts.map +1 -0
- package/src/engine/physics/cloth/collider/ClothColliderRecord.js +137 -0
- package/src/engine/physics/cloth/collider/cloth_collider_bounds.d.ts +25 -0
- package/src/engine/physics/cloth/collider/cloth_collider_bounds.d.ts.map +1 -0
- package/src/engine/physics/cloth/collider/cloth_collider_bounds.js +190 -0
- package/src/engine/physics/cloth/collider/cloth_collider_pack.d.ts +44 -0
- package/src/engine/physics/cloth/collider/cloth_collider_pack.d.ts.map +1 -0
- package/src/engine/physics/cloth/collider/cloth_collider_pack.js +173 -0
- package/src/engine/physics/cloth/collider/cloth_collider_sdf.d.ts +94 -0
- package/src/engine/physics/cloth/collider/cloth_collider_sdf.d.ts.map +1 -0
- package/src/engine/physics/cloth/collider/cloth_collider_sdf.js +275 -0
- package/src/engine/physics/cloth/ecs/ClothCollider.d.ts +126 -0
- package/src/engine/physics/cloth/ecs/ClothCollider.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/ClothCollider.js +199 -0
- package/src/engine/physics/cloth/ecs/ClothColliderFlags.d.ts +9 -0
- package/src/engine/physics/cloth/ecs/ClothColliderFlags.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/ClothColliderFlags.js +32 -0
- package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts +114 -0
- package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/ClothColliderSystem.js +243 -0
- package/src/engine/physics/cloth/ecs/ClothDynamicsFlags.js +66 -57
- package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +109 -1
- package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothInstance.js +479 -363
- package/src/engine/physics/cloth/ecs/ClothRig.d.ts +95 -0
- package/src/engine/physics/cloth/ecs/ClothRig.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/ClothRig.js +140 -0
- package/src/engine/physics/cloth/ecs/ClothSystem.d.ts +30 -1
- package/src/engine/physics/cloth/ecs/ClothSystem.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothSystem.js +1021 -773
- package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts +90 -0
- package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/cloth_build_rows.js +374 -0
- package/src/engine/physics/cloth/ecs/cloth_dynamics_library.d.ts +32 -3
- package/src/engine/physics/cloth/ecs/cloth_dynamics_library.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_dynamics_library.js +283 -254
- package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts +59 -0
- package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/cloth_gather_colliders.js +328 -0
- package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.d.ts +13 -0
- package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.js +288 -0
- package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts +58 -0
- package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/cloth_seed_rig.js +199 -0
- package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts +8 -63
- package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_seed_subtree.js +317 -645
- package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts +61 -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 +212 -449
- package/src/engine/physics/cloth/ecs/cloth_write_back_rig.d.ts +49 -0
- package/src/engine/physics/cloth/ecs/cloth_write_back_rig.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/cloth_write_back_rig.js +115 -0
- package/src/engine/physics/cloth/playground/README.md +155 -1
- package/src/engine/physics/cloth/playground/collide.html +178 -0
- package/src/engine/physics/cloth/playground/collide_build.d.ts +95 -0
- package/src/engine/physics/cloth/playground/collide_build.d.ts.map +1 -0
- package/src/engine/physics/cloth/playground/collide_build.js +315 -0
- package/src/engine/physics/cloth/playground/collide_main.d.ts +2 -0
- package/src/engine/physics/cloth/playground/collide_main.d.ts.map +1 -0
- package/src/engine/physics/cloth/playground/collide_main.js +720 -0
- package/src/engine/physics/cloth/playground/garment.html +182 -0
- package/src/engine/physics/cloth/playground/garment_build.d.ts +78 -0
- package/src/engine/physics/cloth/playground/garment_build.d.ts.map +1 -0
- package/src/engine/physics/cloth/playground/garment_build.js +359 -0
- package/src/engine/physics/cloth/playground/garment_main.d.ts +2 -0
- package/src/engine/physics/cloth/playground/garment_main.d.ts.map +1 -0
- package/src/engine/physics/cloth/playground/garment_main.js +633 -0
- package/src/engine/physics/cloth/solver/ClothState.d.ts +208 -5
- package/src/engine/physics/cloth/solver/ClothState.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/ClothState.js +302 -8
- package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts +87 -0
- package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts.map +1 -0
- package/src/engine/physics/cloth/solver/cloth_contact_find.js +343 -0
- package/src/engine/physics/cloth/solver/cloth_self_find.d.ts +112 -0
- package/src/engine/physics/cloth/solver/cloth_self_find.d.ts.map +1 -0
- package/src/engine/physics/cloth/solver/cloth_self_find.js +448 -0
- package/src/engine/physics/cloth/solver/cloth_solve_vertex.d.ts +4 -1
- package/src/engine/physics/cloth/solver/cloth_solve_vertex.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/cloth_solve_vertex.js +16 -1
- package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts +112 -5
- package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/cloth_solver_constants.js +117 -6
- package/src/engine/physics/cloth/solver/cloth_step.d.ts +40 -9
- package/src/engine/physics/cloth/solver/cloth_step.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/cloth_step.js +122 -10
- package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.d.ts +95 -0
- package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.d.ts.map +1 -0
- package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.js +285 -0
- package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.d.ts +129 -0
- package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.d.ts.map +1 -0
- package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.js +501 -0
- package/src/engine/physics/cloth/solver/constraint/cloth_self_row.d.ts +75 -0
- package/src/engine/physics/cloth/solver/constraint/cloth_self_row.d.ts.map +1 -0
- package/src/engine/physics/cloth/solver/constraint/cloth_self_row.js +202 -0
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/shade/playground/vgeo_viewer/README.md +18 -0
- package/src/shade/playground/vgeo_viewer/main.js +87 -50
- package/src/shade/renderer/buffer/table/GPUDatabase.d.ts.map +1 -1
- package/src/shade/renderer/buffer/table/GPUDatabase.js +191 -62
- package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts +94 -2
- package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts.map +1 -1
- package/src/shade/renderer/buffer/table/GPUTypedTable.js +414 -2
- package/src/shade/renderer/buffer/table/GPU_TABLE_PARTIAL_UPLOAD_DESCRIPTOR_WORDS.d.ts +14 -0
- package/src/shade/renderer/buffer/table/GPU_TABLE_PARTIAL_UPLOAD_DESCRIPTOR_WORDS.d.ts.map +1 -0
- package/src/shade/renderer/buffer/table/GPU_TABLE_PARTIAL_UPLOAD_DESCRIPTOR_WORDS.js +13 -0
- package/src/shade/renderer/buffer/table/gpu_table_partial_upload_shader.d.ts +17 -0
- package/src/shade/renderer/buffer/table/gpu_table_partial_upload_shader.d.ts.map +1 -0
- package/src/shade/renderer/buffer/table/gpu_table_partial_upload_shader.js +116 -0
- package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts +9 -4
- package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts.map +1 -1
- package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.js +843 -734
- package/src/shade/renderer/geometry/bvh/GPUGeometryMeshletsBVH.d.ts +12 -0
- package/src/shade/renderer/geometry/bvh/GPUGeometryMeshletsBVH.d.ts.map +1 -1
- package/src/shade/renderer/geometry/bvh/GPUGeometryMeshletsBVH.js +13 -0
- package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts +17 -0
- package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
- package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +185 -30
- package/src/shade/renderer/geometry/virtual/MICRON_COMPARISON_2026_08_20.md +17 -0
- package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +141 -24
- package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +204 -64
- package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +110 -10
- package/src/shade/renderer/geometry/virtual/VK_LOD_CLUSTERS_COMPARISON_2026_08_20.md +19 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.d.ts +19 -6
- package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.js +26 -7
- package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts +173 -14
- package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.js +458 -51
- package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.d.ts +49 -13
- package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.js +52 -14
- package/src/shade/renderer/geometry/virtual/format/read/tool/VGEO_MAX_AUDIT_BYTES.d.ts +20 -0
- package/src/shade/renderer/geometry/virtual/format/read/tool/VGEO_MAX_AUDIT_BYTES.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/read/tool/VGEO_MAX_AUDIT_BYTES.js +19 -0
- package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_audit_container.d.ts +27 -0
- package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_audit_container.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_audit_container.js +48 -0
- package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_install_all_pages.d.ts +29 -0
- package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_install_all_pages.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_install_all_pages.js +60 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.d.ts +8 -1
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.js +32 -2
- package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.d.ts +258 -0
- package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.js +723 -0
- package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.d.ts +49 -0
- package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.js +50 -0
- package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
- package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
- package/src/shade/renderer/texture/bindless/GPUBindlessTextureManager.d.ts +3 -0
- package/src/shade/renderer/texture/bindless/GPUBindlessTextureManager.d.ts.map +1 -1
- package/src/shade/renderer/texture/bindless/GPUBindlessTextureManager.js +121 -21
- package/src/shade/renderer/texture/virtual/README.md +6 -4
- package/src/shade/renderer/texture/virtual/VirtualTextureManager.d.ts.map +1 -1
- package/src/shade/renderer/texture/virtual/VirtualTextureManager.js +7 -0
- package/src/shade/renderer/texture/virtual/source/VTSourceTiled.d.ts +3 -3
- package/src/shade/renderer/texture/virtual/source/VTSourceTiled.js +3 -3
- package/src/engine/ecs/system/SystemExecutionPhase.d.ts +0 -9
- package/src/engine/ecs/system/SystemExecutionPhase.d.ts.map +0 -1
- package/src/engine/graphics/texture/virtual/NOTES.md +0 -128
- package/src/engine/graphics/texture/virtual/VT_DEFAULT_PAGE_RESOLUTION.d.ts +0 -6
- package/src/engine/graphics/texture/virtual/VT_DEFAULT_PAGE_RESOLUTION.d.ts.map +0 -1
- package/src/engine/graphics/texture/virtual/VT_DEFAULT_PAGE_RESOLUTION.js +0 -5
- package/src/engine/graphics/texture/virtual/VirtualTextureTileLoader.d.ts +0 -49
- package/src/engine/graphics/texture/virtual/VirtualTextureTileLoader.d.ts.map +0 -1
- package/src/engine/graphics/texture/virtual/VirtualTextureTileLoader.js +0 -264
- package/src/engine/graphics/texture/virtual/VirtualTextureUsage.d.ts +0 -44
- package/src/engine/graphics/texture/virtual/VirtualTextureUsage.d.ts.map +0 -1
- package/src/engine/graphics/texture/virtual/VirtualTextureUsage.js +0 -228
- package/src/engine/graphics/texture/virtual/VirtualTextureUsageShader.d.ts +0 -3
- package/src/engine/graphics/texture/virtual/VirtualTextureUsageShader.d.ts.map +0 -1
- package/src/engine/graphics/texture/virtual/VirtualTextureUsageShader.js +0 -73
- package/src/engine/graphics/texture/virtual/debug/ResidencyDebugView.d.ts +0 -14
- package/src/engine/graphics/texture/virtual/debug/ResidencyDebugView.d.ts.map +0 -1
- package/src/engine/graphics/texture/virtual/debug/ResidencyDebugView.js +0 -85
- package/src/engine/graphics/texture/virtual/debug/UsageDebugView.d.ts +0 -12
- package/src/engine/graphics/texture/virtual/debug/UsageDebugView.d.ts.map +0 -1
- package/src/engine/graphics/texture/virtual/debug/UsageDebugView.js +0 -63
- package/src/engine/graphics/texture/virtual/debug/UsagePyramidDebugView.d.ts +0 -12
- package/src/engine/graphics/texture/virtual/debug/UsagePyramidDebugView.d.ts.map +0 -1
- package/src/engine/graphics/texture/virtual/debug/UsagePyramidDebugView.js +0 -243
- package/src/engine/graphics/texture/virtual/tile/VirtualTextureTile.d.ts +0 -30
- package/src/engine/graphics/texture/virtual/tile/VirtualTextureTile.d.ts.map +0 -1
- package/src/engine/graphics/texture/virtual/tile/VirtualTextureTile.js +0 -39
- package/src/engine/graphics/texture/virtual/tile/compose_finger_print.d.ts +0 -9
- package/src/engine/graphics/texture/virtual/tile/compose_finger_print.d.ts.map +0 -1
- package/src/engine/graphics/texture/virtual/tile/compose_finger_print.js +0 -24
- package/src/engine/graphics/texture/virtual/tile/compose_tile_address.d.ts +0 -9
- package/src/engine/graphics/texture/virtual/tile/compose_tile_address.d.ts.map +0 -1
- package/src/engine/graphics/texture/virtual/tile/compose_tile_address.js +0 -26
- package/src/engine/graphics/texture/virtual/tile/decompose_finger_print.d.ts +0 -11
- package/src/engine/graphics/texture/virtual/tile/decompose_finger_print.d.ts.map +0 -1
- package/src/engine/graphics/texture/virtual/tile/decompose_finger_print.js +0 -12
- package/src/engine/graphics/texture/virtual/tile/finger_print_to_tile_address.d.ts +0 -7
- package/src/engine/graphics/texture/virtual/tile/finger_print_to_tile_address.d.ts.map +0 -1
- package/src/engine/graphics/texture/virtual/tile/finger_print_to_tile_address.js +0 -16
- package/src/engine/graphics/texture/virtual/tile/tile_address_to_finger_print.d.ts +0 -7
- package/src/engine/graphics/texture/virtual/tile/tile_address_to_finger_print.d.ts.map +0 -1
- package/src/engine/graphics/texture/virtual/tile/tile_address_to_finger_print.js +0 -35
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
import { PointHashGrid3 } from "../../../../core/geom/3d/hash-grid/PointHashGrid3.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* # Finding the self-collision pairs, once per step
|
|
5
|
+
*
|
|
6
|
+
* A uniform hash grid over the particles in the cloth's own frame, then for each
|
|
7
|
+
* particle the ones near it that are not already governed by a row. Rebuilt
|
|
8
|
+
* whole every step, exactly like the contact set (`cloth_contact_find.js`) and
|
|
9
|
+
* for the same reasons: one pass in a fixed order, so the step is deterministic.
|
|
10
|
+
*
|
|
11
|
+
* ## Adjacent pairs are excluded, and "adjacent" means "shares a row"
|
|
12
|
+
*
|
|
13
|
+
* §9: "Pairs sharing a triangle or an edge are excluded, since they are already
|
|
14
|
+
* governed by stretch and bend rows and would otherwise fight them." The exact
|
|
15
|
+
* form of that here is **sharing any row at all** — a stretch row, a bend
|
|
16
|
+
* stencil, or a chain's skip row, which is a stretch row too. Two particles a
|
|
17
|
+
* stretch row already holds at 5 cm do not also need a repulsion telling them to
|
|
18
|
+
* be 8 mm apart, and a bend stencil's four particles are a fold the bend row is
|
|
19
|
+
* the model of.
|
|
20
|
+
*
|
|
21
|
+
* The exclusion set is built **once, at seed**, from the row tables the state
|
|
22
|
+
* already carries: `cloth_self_exclusions` walks them and produces a sorted CSR
|
|
23
|
+
* list per particle. Testing a candidate is then a short scan over a handful of
|
|
24
|
+
* neighbours, which at typical garment topology is 16.8 entries a particle
|
|
25
|
+
* (`MEASUREMENTS.md` §8) — small enough that a scan beats a hash.
|
|
26
|
+
*
|
|
27
|
+
* ## The cell is the row's own diameter, and that fixes the neighbourhood
|
|
28
|
+
*
|
|
29
|
+
* Two particles interact when they are closer than `2·self_radius`, so a cell of
|
|
30
|
+
* exactly that makes the 27-cell walk necessary and sufficient. A larger cell
|
|
31
|
+
* would visit more candidates for nothing; a smaller one would need a wider
|
|
32
|
+
* walk, which is the same candidates through more buckets.
|
|
33
|
+
*
|
|
34
|
+
* **That radius is the proxy's resolution rather than the fabric's thickness**,
|
|
35
|
+
* and `ClothState#self_radius` carries why.
|
|
36
|
+
*
|
|
37
|
+
* @author Alex Goldring
|
|
38
|
+
* @copyright Company Named Limited (c) 2026
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Pairs one particle may **originate**, before the rest are dropped.
|
|
43
|
+
*
|
|
44
|
+
* A particle in a fold has a few neighbours across the fold and a few along it;
|
|
45
|
+
* eight is generous for a garment and is what bounds the pair list so a cloth
|
|
46
|
+
* that crumples into a ball cannot allocate its way out of a frame budget. A
|
|
47
|
+
* particle at the limit keeps the eight it found first in grid order, which is
|
|
48
|
+
* arbitrary among equals — and they are equals, because every one of them is
|
|
49
|
+
* inside the same radius.
|
|
50
|
+
*
|
|
51
|
+
* **"Originate", not "is in".** The search emits a pair once, from its lower
|
|
52
|
+
* index, so this caps how many pairs a particle starts and not how many it ends
|
|
53
|
+
* up in: a particle can be the *higher* index of any number of them. What the
|
|
54
|
+
* cap does bound exactly — and the only thing `ClothState` needs it to — is the
|
|
55
|
+
* length of the whole list, at this many per particle, because every pair is
|
|
56
|
+
* charged to exactly one of its two ends.
|
|
57
|
+
* @type {number}
|
|
58
|
+
*/
|
|
59
|
+
export const CLOTH_SELF_PAIRS_PER_PARTICLE = 8;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Build the exclusion lists from a state's persistent rows.
|
|
63
|
+
*
|
|
64
|
+
* @param {ClothState} state
|
|
65
|
+
* @returns {{offset: Int32Array, partner: Int32Array}} CSR, sorted within each particle
|
|
66
|
+
*/
|
|
67
|
+
export function cloth_self_exclusions(state) {
|
|
68
|
+
const particle_count = state.particle_count;
|
|
69
|
+
|
|
70
|
+
/** @type {Set<number>[]} */
|
|
71
|
+
const sets = new Array(particle_count);
|
|
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 };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* The closest two particles get **without a row between them**, in whatever pose
|
|
127
|
+
* the state is in.
|
|
128
|
+
|
|
129
|
+
* This is the length that decides how wide a self-collision row may be written,
|
|
130
|
+
* and it has to be measured rather than assumed. On a triangulated sheet it is
|
|
131
|
+
* two hops — one hop is a stretch row, the mesh diagonal is a stretch row, and
|
|
132
|
+
* the two vertices across a diagonal are a bend stencil — so it comes out at
|
|
133
|
+
* twice the shortest row and the analytic answer and this one agree.
|
|
134
|
+
*
|
|
135
|
+
* **A rigged garment is not a sheet and the two do not agree.** Its proxy is a
|
|
136
|
+
* set of *strips*, and nothing connects one strip to the next: every pair across
|
|
137
|
+
* the gap between two strips is ungoverned, at whatever distance the artist
|
|
138
|
+
* placed the joints. That distance has nothing to do with the link length along
|
|
139
|
+
* a strip, which is what `shortest_row` measures. On the playground's cape they
|
|
140
|
+
* differ by a factor of two — 8.5 cm across the gap against the 16 cm a sheet's
|
|
141
|
+
* topology would predict — and a ceiling derived from the link length instead of
|
|
142
|
+
* measured left the settled cape with three permanently active pairs.
|
|
143
|
+
* `MEASUREMENTS.md` §37.
|
|
144
|
+
*
|
|
145
|
+
* Pinned particles are skipped, exactly as {@link cloth_self_find} skips them,
|
|
146
|
+
* so this measures the pairs the row can actually act on and nothing else.
|
|
147
|
+
*
|
|
148
|
+
* @param {ClothState} state
|
|
149
|
+
* @param {{offset: Int32Array, partner: Int32Array}} exclusions from {@link cloth_self_exclusions}
|
|
150
|
+
* @param {number} search only pairs closer than this are looked for; the walk is
|
|
151
|
+
* bounded by it, and a proxy with nothing that close gets `Infinity` — which is
|
|
152
|
+
* the right answer, because then no radius inside the bound can touch anything
|
|
153
|
+
* @returns {number} metres, or `Infinity`
|
|
154
|
+
*/
|
|
155
|
+
export function cloth_self_closest_free_pair(state, exclusions, search) {
|
|
156
|
+
const particle_count = state.particle_count;
|
|
157
|
+
|
|
158
|
+
if (!(search > 0) || particle_count < 2) {
|
|
159
|
+
return Infinity;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
GRID.build(state.position, particle_count, search);
|
|
163
|
+
|
|
164
|
+
const position = state.position;
|
|
165
|
+
const mass_inverse = state.mass_inverse;
|
|
166
|
+
|
|
167
|
+
const offset = exclusions.offset;
|
|
168
|
+
const partner = exclusions.partner;
|
|
169
|
+
|
|
170
|
+
const grid_offset = GRID.offset;
|
|
171
|
+
const grid_point = GRID.point;
|
|
172
|
+
|
|
173
|
+
const inverse = 1 / search;
|
|
174
|
+
|
|
175
|
+
// The walk is a *maybe*: two cells can hash into one bucket, so a bucket can
|
|
176
|
+
// hand back a point from anywhere. Without this the answer would be the
|
|
177
|
+
// closest ungoverned pair the table happened to collide into view, which is
|
|
178
|
+
// a real distance but not the one `search` was asked for.
|
|
179
|
+
let closest_squared = search * search;
|
|
180
|
+
|
|
181
|
+
for (let i = 0; i < particle_count; i++) {
|
|
182
|
+
if (mass_inverse[i] === 0) {
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const a = i * 3;
|
|
187
|
+
|
|
188
|
+
const x = position[a];
|
|
189
|
+
const y = position[a + 1];
|
|
190
|
+
const z = position[a + 2];
|
|
191
|
+
|
|
192
|
+
const cx = Math.floor(x * inverse);
|
|
193
|
+
const cy = Math.floor(y * inverse);
|
|
194
|
+
const cz = Math.floor(z * inverse);
|
|
195
|
+
|
|
196
|
+
const exclude_start = offset[i];
|
|
197
|
+
const exclude_end = offset[i + 1];
|
|
198
|
+
|
|
199
|
+
let visited = 0;
|
|
200
|
+
|
|
201
|
+
for (let dz = -1; dz <= 1; dz++) {
|
|
202
|
+
for (let dy = -1; dy <= 1; dy++) {
|
|
203
|
+
for (let dx = -1; dx <= 1; dx++) {
|
|
204
|
+
const bucket = GRID.bucketOf(cx + dx, cy + dy, cz + dz);
|
|
205
|
+
|
|
206
|
+
let seen = false;
|
|
207
|
+
|
|
208
|
+
for (let v = 0; v < visited; v++) {
|
|
209
|
+
if (VISITED[v] === bucket) {
|
|
210
|
+
seen = true;
|
|
211
|
+
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (seen) {
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
VISITED[visited++] = bucket;
|
|
221
|
+
|
|
222
|
+
const end = grid_offset[bucket + 1];
|
|
223
|
+
|
|
224
|
+
for (let at = grid_offset[bucket]; at < end; at++) {
|
|
225
|
+
const j = grid_point[at];
|
|
226
|
+
|
|
227
|
+
if (j <= i || mass_inverse[j] === 0) {
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const b = j * 3;
|
|
232
|
+
|
|
233
|
+
const ddx = x - position[b];
|
|
234
|
+
const ddy = y - position[b + 1];
|
|
235
|
+
const ddz = z - position[b + 2];
|
|
236
|
+
|
|
237
|
+
const distance_squared = ddx * ddx + ddy * ddy + ddz * ddz;
|
|
238
|
+
|
|
239
|
+
if (distance_squared >= closest_squared) {
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
let excluded = false;
|
|
244
|
+
|
|
245
|
+
for (let e = exclude_start; e < exclude_end; e++) {
|
|
246
|
+
if (partner[e] === j) {
|
|
247
|
+
excluded = true;
|
|
248
|
+
|
|
249
|
+
break;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (partner[e] > j) {
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (excluded) {
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
closest_squared = distance_squared;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return closest_squared === search * search ? Infinity : Math.sqrt(closest_squared);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Rebuild the pair list.
|
|
273
|
+
*
|
|
274
|
+
* @param {ClothState} state pairs written into `self_pair`, count into `self_count`
|
|
275
|
+
* @param {{offset: Int32Array, partner: Int32Array}} exclusions from {@link cloth_self_exclusions}
|
|
276
|
+
* @returns {number} how many pairs were found
|
|
277
|
+
*/
|
|
278
|
+
export function cloth_self_find(state, exclusions) {
|
|
279
|
+
const particle_count = state.particle_count;
|
|
280
|
+
|
|
281
|
+
const radius = state.self_radius * 2;
|
|
282
|
+
|
|
283
|
+
if (radius <= 0) {
|
|
284
|
+
state.self_count = 0;
|
|
285
|
+
|
|
286
|
+
return 0;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
GRID.build(state.position, particle_count, radius);
|
|
290
|
+
|
|
291
|
+
const position = state.position;
|
|
292
|
+
const mass_inverse = state.mass_inverse;
|
|
293
|
+
|
|
294
|
+
const pair = state.self_pair;
|
|
295
|
+
|
|
296
|
+
const capacity = pair.length / 2;
|
|
297
|
+
|
|
298
|
+
const offset = exclusions.offset;
|
|
299
|
+
const partner = exclusions.partner;
|
|
300
|
+
|
|
301
|
+
let count = 0;
|
|
302
|
+
|
|
303
|
+
const grid_offset = GRID.offset;
|
|
304
|
+
const grid_point = GRID.point;
|
|
305
|
+
|
|
306
|
+
const inverse = 1 / radius;
|
|
307
|
+
|
|
308
|
+
const radius_squared = radius * radius;
|
|
309
|
+
|
|
310
|
+
for (let i = 0; i < particle_count; i++) {
|
|
311
|
+
if (mass_inverse[i] === 0) {
|
|
312
|
+
// A pinned particle cannot be pushed, so a pair on it is a force
|
|
313
|
+
// assembled and thrown away for one end and doubled for the other.
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const a = i * 3;
|
|
318
|
+
|
|
319
|
+
const x = position[a];
|
|
320
|
+
const y = position[a + 1];
|
|
321
|
+
const z = position[a + 2];
|
|
322
|
+
|
|
323
|
+
const cx = Math.floor(x * inverse);
|
|
324
|
+
const cy = Math.floor(y * inverse);
|
|
325
|
+
const cz = Math.floor(z * inverse);
|
|
326
|
+
|
|
327
|
+
const exclude_start = offset[i];
|
|
328
|
+
const exclude_end = offset[i + 1];
|
|
329
|
+
|
|
330
|
+
let found = 0;
|
|
331
|
+
|
|
332
|
+
let visited = 0;
|
|
333
|
+
|
|
334
|
+
for (let dz = -1; dz <= 1 && found < CLOTH_SELF_PAIRS_PER_PARTICLE; dz++) {
|
|
335
|
+
for (let dy = -1; dy <= 1 && found < CLOTH_SELF_PAIRS_PER_PARTICLE; dy++) {
|
|
336
|
+
for (let dx = -1; dx <= 1 && found < CLOTH_SELF_PAIRS_PER_PARTICLE; dx++) {
|
|
337
|
+
const bucket = GRID.bucketOf(cx + dx, cy + dy, cz + dz);
|
|
338
|
+
|
|
339
|
+
let seen = false;
|
|
340
|
+
|
|
341
|
+
for (let v = 0; v < visited; v++) {
|
|
342
|
+
if (VISITED[v] === bucket) {
|
|
343
|
+
seen = true;
|
|
344
|
+
|
|
345
|
+
break;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if (seen) {
|
|
350
|
+
continue;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
VISITED[visited++] = bucket;
|
|
354
|
+
|
|
355
|
+
const end = grid_offset[bucket + 1];
|
|
356
|
+
|
|
357
|
+
for (let at = grid_offset[bucket]; at < end; at++) {
|
|
358
|
+
const j = grid_point[at];
|
|
359
|
+
|
|
360
|
+
// Each pair once, and never a particle against itself.
|
|
361
|
+
// The `j > i` test is what halves the work and it is also
|
|
362
|
+
// what makes the list order a function of the particle
|
|
363
|
+
// numbering rather than of the grid's.
|
|
364
|
+
if (j <= i) {
|
|
365
|
+
continue;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
if (mass_inverse[j] === 0) {
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
const b = j * 3;
|
|
373
|
+
|
|
374
|
+
const ddx = x - position[b];
|
|
375
|
+
const ddy = y - position[b + 1];
|
|
376
|
+
const ddz = z - position[b + 2];
|
|
377
|
+
|
|
378
|
+
if (ddx * ddx + ddy * ddy + ddz * ddz >= radius_squared) {
|
|
379
|
+
continue;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
let excluded = false;
|
|
383
|
+
|
|
384
|
+
for (let e = exclude_start; e < exclude_end; e++) {
|
|
385
|
+
if (partner[e] === j) {
|
|
386
|
+
excluded = true;
|
|
387
|
+
|
|
388
|
+
break;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
if (partner[e] > j) {
|
|
392
|
+
// Sorted, so nothing further can match.
|
|
393
|
+
break;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
if (excluded) {
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if (count >= capacity) {
|
|
402
|
+
// The list is full. Dropping the rest is bounded and
|
|
403
|
+
// visible — `ClothInstance#self_count` against the
|
|
404
|
+
// capacity says so — and is the alternative to a
|
|
405
|
+
// crumpled garment growing an allocation per frame.
|
|
406
|
+
state.self_count = count;
|
|
407
|
+
|
|
408
|
+
return count;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
pair[count * 2] = i;
|
|
412
|
+
pair[count * 2 + 1] = j;
|
|
413
|
+
|
|
414
|
+
count++;
|
|
415
|
+
found++;
|
|
416
|
+
|
|
417
|
+
if (found >= CLOTH_SELF_PAIRS_PER_PARTICLE) {
|
|
418
|
+
break;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
state.self_count = count;
|
|
427
|
+
|
|
428
|
+
return count;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* The grid, module-level and reused across every cloth and by both of the walks
|
|
433
|
+
* in this file. One cloth is stepped at a time and neither walk outlives its own
|
|
434
|
+
* call — {@link cloth_self_find} runs before the step and
|
|
435
|
+
* {@link cloth_self_closest_free_pair} runs once at seed — so a grid per instance
|
|
436
|
+
* would be one allocation per garment for no benefit. Neither may call the other.
|
|
437
|
+
* @type {PointHashGrid3}
|
|
438
|
+
* @private
|
|
439
|
+
*/
|
|
440
|
+
const GRID = new PointHashGrid3();
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Buckets the 27-cell walk has already visited, shared by both walks for the
|
|
444
|
+
* same reason {@link GRID} is: at most 27, never nested.
|
|
445
|
+
* @type {Int32Array}
|
|
446
|
+
* @private
|
|
447
|
+
*/
|
|
448
|
+
const VISITED = new Int32Array(27);
|
|
@@ -8,6 +8,9 @@
|
|
|
8
8
|
* @param {ClothState} state
|
|
9
9
|
* @param {number} particle
|
|
10
10
|
* @param {number} inverse_h_squared `1/h²` for the substep in progress
|
|
11
|
+
* @param {Float32Array|Float64Array|null} [collider_table] packed colliders in
|
|
12
|
+
* the cloth's own frame, posed at this substep. `null` — the M0 and M1 case —
|
|
13
|
+
* skips the contact rows entirely rather than looping over empty slots.
|
|
11
14
|
*/
|
|
12
|
-
export function cloth_solve_vertex(state: ClothState, particle: number, inverse_h_squared: number): void;
|
|
15
|
+
export function cloth_solve_vertex(state: ClothState, particle: number, inverse_h_squared: number, collider_table?: Float32Array | Float64Array | null): void;
|
|
13
16
|
//# sourceMappingURL=cloth_solve_vertex.d.ts.map
|
|
@@ -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":"AAgFA;;;;;;;;;;;;;GAaG;AACH,gEANW,MAAM,qBACN,MAAM,mBACN,YAAY,GAAC,YAAY,GAAC,IAAI,QA6HxC"}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { assert } from "../../../../core/assert.js";
|
|
2
|
+
import { cloth_backstop_accumulate } from "./constraint/cloth_backstop_row.js";
|
|
2
3
|
import { cloth_bend_accumulate } from "./constraint/cloth_bend_row.js";
|
|
4
|
+
import { cloth_contact_accumulate } from "./constraint/cloth_contact_row.js";
|
|
3
5
|
import { cloth_leash_accumulate } from "./constraint/cloth_leash_row.js";
|
|
6
|
+
import { cloth_self_accumulate } from "./constraint/cloth_self_row.js";
|
|
4
7
|
import { cloth_stretch_accumulate } from "./constraint/cloth_stretch_row.js";
|
|
5
8
|
import {
|
|
6
9
|
CVA_F_X,
|
|
@@ -85,8 +88,11 @@ const ACCUMULATOR = new Float64Array(CVA_STRIDE);
|
|
|
85
88
|
* @param {ClothState} state
|
|
86
89
|
* @param {number} particle
|
|
87
90
|
* @param {number} inverse_h_squared `1/h²` for the substep in progress
|
|
91
|
+
* @param {Float32Array|Float64Array|null} [collider_table] packed colliders in
|
|
92
|
+
* the cloth's own frame, posed at this substep. `null` — the M0 and M1 case —
|
|
93
|
+
* skips the contact rows entirely rather than looping over empty slots.
|
|
88
94
|
*/
|
|
89
|
-
export function cloth_solve_vertex(state, particle, inverse_h_squared) {
|
|
95
|
+
export function cloth_solve_vertex(state, particle, inverse_h_squared, collider_table = null) {
|
|
90
96
|
const inverse_mass = state.mass_inverse[particle];
|
|
91
97
|
|
|
92
98
|
if (inverse_mass === 0) {
|
|
@@ -120,6 +126,15 @@ export function cloth_solve_vertex(state, particle, inverse_h_squared) {
|
|
|
120
126
|
cloth_stretch_accumulate(accumulator, state, particle);
|
|
121
127
|
cloth_bend_accumulate(accumulator, state, particle);
|
|
122
128
|
cloth_leash_accumulate(accumulator, state, particle);
|
|
129
|
+
cloth_backstop_accumulate(accumulator, state, particle);
|
|
130
|
+
|
|
131
|
+
if (collider_table !== null) {
|
|
132
|
+
cloth_contact_accumulate(accumulator, state, particle, collider_table);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (state.self_count > 0) {
|
|
136
|
+
cloth_self_accumulate(accumulator, state, particle);
|
|
137
|
+
}
|
|
123
138
|
|
|
124
139
|
const a = accumulator[CVA_H_XX];
|
|
125
140
|
const b = accumulator[CVA_H_XY];
|
|
@@ -49,10 +49,26 @@
|
|
|
49
49
|
* for **transient** rows — a contact that should arrive soft and stiffen rather
|
|
50
50
|
* than shock the mesh on its first frame — and M0 has none.
|
|
51
51
|
*
|
|
52
|
-
* **`β`
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
52
|
+
* **`β` is M2's, and it is 1e3 rather than M0's 1e5 placeholder.** M0 could not
|
|
53
|
+
* choose it: above about 1e4 every M0 scenario gave an identical answer, and
|
|
54
|
+
* with the band collapsed it had no effect at all. M2's contacts are the first
|
|
55
|
+
* transient rows in the system and the ramp is finally live. Measured on a
|
|
56
|
+
* 400-particle sheet landing on the ground, both ends of the range are worse
|
|
57
|
+
* than the middle: **no ramp at all** leaves a fast arrival's penalty at the
|
|
58
|
+
* floor and the multiplier alone to carry it, which settles at 1.95 J of
|
|
59
|
+
* residual kinetic energy against 0.12 J at 1e3; a **fast** ramp reaches the
|
|
60
|
+
* ceiling on violations of a millimetre and gives up most of what the low floor
|
|
61
|
+
* bought, settling three orders of magnitude worse on a gentle landing
|
|
62
|
+
* (6.4e-5 J against 3.2e-8 J). `MEASUREMENTS.md` §17.
|
|
63
|
+
*
|
|
64
|
+
* The scale-dependence the paragraph above warns of is real and is stated
|
|
65
|
+
* rather than removed: `β` has units of N/m², so it is a stiffness *per metre
|
|
66
|
+
* of violation*, and 1e3 against a ceiling of `8·(m/h²)` means the ramp is
|
|
67
|
+
* inert for a millimetre of penetration and reaches the ceiling within a step
|
|
68
|
+
* for a decimetre of it. That shape — gentle where the contact is grazing,
|
|
69
|
+
* immediate where it is a real interpenetration — is what the measurement
|
|
70
|
+
* picked, and a ratio-valued `β` that removed the dependence would have to
|
|
71
|
+
* choose the reference length that shape is built out of.
|
|
56
72
|
*
|
|
57
73
|
* @author Alex Goldring
|
|
58
74
|
* @copyright Company Named Limited (c) 2026
|
|
@@ -63,7 +79,8 @@
|
|
|
63
79
|
*/
|
|
64
80
|
export const CLOTH_ALPHA: number;
|
|
65
81
|
/**
|
|
66
|
-
* Penalty ramp
|
|
82
|
+
* Penalty ramp, N/m². See the module docblock — measured at M2, against the
|
|
83
|
+
* first transient rows the system has.
|
|
67
84
|
* @type {number}
|
|
68
85
|
*/
|
|
69
86
|
export const CLOTH_BETA: number;
|
|
@@ -82,6 +99,96 @@ export const CLOTH_K_MIN_RATIO: number;
|
|
|
82
99
|
* @type {number}
|
|
83
100
|
*/
|
|
84
101
|
export const CLOTH_K_MAX_RATIO: number;
|
|
102
|
+
/**
|
|
103
|
+
* Penalty floor for a **contact** row, as a multiple of the row's `m/h²`.
|
|
104
|
+
*
|
|
105
|
+
* Separate from {@link CLOTH_K_MIN_RATIO}, which is pinned to the ceiling,
|
|
106
|
+
* because a contact is the one row kind that *arrives*: a persistent row has
|
|
107
|
+
* been converging since the cloth was seeded and wants the stiffest penalty the
|
|
108
|
+
* step is stable at, and a contact that starts there shocks the mesh on its
|
|
109
|
+
* first frame.
|
|
110
|
+
*
|
|
111
|
+
* **A thirty-second of the ceiling**, measured. The floor is what decides how
|
|
112
|
+
* hard a new contact hits, and the measurement is unambiguous about the
|
|
113
|
+
* direction: on a sheet landing at 3 m/s, the peak contact force falls from
|
|
114
|
+
* 18.9 N at the ceiling to 0.16 N at an eighth of it and the settled kinetic
|
|
115
|
+
* energy falls by six orders of magnitude, while the penetration *improves*
|
|
116
|
+
* from 1.6 cm to 1.1 cm. Below about an eighth the numbers stop moving — every
|
|
117
|
+
* floor from ×1/8 down to ×1/128 gives the same penetration to three figures —
|
|
118
|
+
* so the value is a margin decision the same way `α·γ` was, and ×1/32 sits in
|
|
119
|
+
* the middle of the flat region with two decades of ramp above it.
|
|
120
|
+
*
|
|
121
|
+
* The reason the floor matters so little to the *residual* is the augmented
|
|
122
|
+
* Lagrangian working as designed: the multiplier carries the load and the
|
|
123
|
+
* penalty only has to be large enough to generate one. See MEASUREMENTS §17.
|
|
124
|
+
* @type {number}
|
|
125
|
+
*/
|
|
126
|
+
export const CLOTH_CONTACT_K_MIN_RATIO: number;
|
|
127
|
+
/**
|
|
128
|
+
* Penalty stiffness for a **self-collision** row, as a multiple of the row's
|
|
129
|
+
* own `m_eff/h²`.
|
|
130
|
+
*
|
|
131
|
+
* It is a plain penalty rather than a hard row because the load it carries is
|
|
132
|
+
* cloth against cloth. `MEASUREMENTS.md` §18 measured why a *collider* contact
|
|
133
|
+
* cannot be soft — 376 N for a sheet arriving at 8 m/s against the 4.6 N a soft
|
|
134
|
+
* row inside M0's dissipative band can deliver — and a self-collision row never
|
|
135
|
+
* sees anything of the kind: what it holds apart weighs grams and is moving at
|
|
136
|
+
* the speed cloth moves relative to itself.
|
|
137
|
+
*
|
|
138
|
+
* **Eight, and the dissipative band is not the reason.** Eight is where M0's
|
|
139
|
+
* band tops out and it would be natural to read this as the same ceiling, but
|
|
140
|
+
* `MEASUREMENTS.md` §32 swept the ratio from 1 to 64 and found no energy growth
|
|
141
|
+
* anywhere: the band was measured on rows that are *on every step*, and a
|
|
142
|
+
* one-sided row that vanishes the instant it is satisfied has no standing spring
|
|
143
|
+
* to pump. What picks eight is the crossing count — it is the joint minimum of
|
|
144
|
+
* the mean, and a stiffer row makes the *worst* case steadily worse by throwing
|
|
145
|
+
* a particle hard enough to put the sheet through itself elsewhere.
|
|
146
|
+
*
|
|
147
|
+
* The consequence is a row with no multiplier, no warm start and no identity
|
|
148
|
+
* across steps, which is what makes rebuilding the pair list from scratch every
|
|
149
|
+
* step affordable. `MEASUREMENTS.md` §33.
|
|
150
|
+
* @type {number}
|
|
151
|
+
*/
|
|
152
|
+
export const CLOTH_SELF_RATIO: number;
|
|
153
|
+
/**
|
|
154
|
+
* Smallest radius a self-collision row is written at, as a multiple of the
|
|
155
|
+
* cloth's shortest row — so the row's **diameter** is one particle spacing.
|
|
156
|
+
*
|
|
157
|
+
* `ClothState#self_radius` carries why the radius is a property of the proxy
|
|
158
|
+
* rather than of the fabric, and `MEASUREMENTS.md` §31 is the sweep: at the
|
|
159
|
+
* fabric's own thickness the row removes 21% of a folding sheet's
|
|
160
|
+
* self-intersections and here it removes 82%.
|
|
161
|
+
* @type {number}
|
|
162
|
+
*/
|
|
163
|
+
export const CLOTH_SELF_RADIUS_MIN_RATIO: number;
|
|
164
|
+
/**
|
|
165
|
+
* Largest radius a self-collision row is written at, as a fraction of the
|
|
166
|
+
* closest two particles get **with no row between them** in the bind pose —
|
|
167
|
+
* `ClothInstance#closest_free_pair`. Two fifths of it, so the row's diameter is
|
|
168
|
+
* four fifths of the nearest thing it could touch and a cloth at rest is never
|
|
169
|
+
* in contact with itself.
|
|
170
|
+
*
|
|
171
|
+
* **A ceiling is needed because the floor is not always reachable.** A thick
|
|
172
|
+
* fabric on a coarse proxy takes its thickness rather than
|
|
173
|
+
* {@link CLOTH_SELF_RADIUS_MIN_RATIO}, and a diameter that reaches the nearest
|
|
174
|
+
* ungoverned pair puts a cloth that is not folded at all in permanent contact
|
|
175
|
+
* with itself — leather, 20 mm thick on a 20 mm proxy, found 1,398 pairs a step
|
|
176
|
+
* across 576 particles standing still. `MEASUREMENTS.md` §36.
|
|
177
|
+
*
|
|
178
|
+
* **And it is measured rather than derived, because a garment is not a sheet.**
|
|
179
|
+
* On a triangulated sheet the closest ungoverned pair is exactly two hops, so
|
|
180
|
+
* this comes out at four fifths of the shortest row and the analytic answer
|
|
181
|
+
* would have done — checked at two spacings, to the precision the proxy's
|
|
182
|
+
* Float32 positions carry. A rigged
|
|
183
|
+
* garment's proxy is *strips* with nothing joining one to the next, so every
|
|
184
|
+
* pair across the gap is ungoverned at whatever distance the artist put the
|
|
185
|
+
* joints, which the shortest row knows nothing about: the playground's cape has
|
|
186
|
+
* 8 cm links and 8.5 cm gaps, half what a sheet would imply. Derived from the
|
|
187
|
+
* link length the ceiling left that cape with three pairs permanently in
|
|
188
|
+
* contact at rest; measured, it has none. `MEASUREMENTS.md` §37.
|
|
189
|
+
* @type {number}
|
|
190
|
+
*/
|
|
191
|
+
export const CLOTH_SELF_RADIUS_MAX_RATIO: number;
|
|
85
192
|
/**
|
|
86
193
|
* The five constants as one frozen object, which is what {@link cloth_step}
|
|
87
194
|
* takes. A sweep passes its own; nothing else should.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloth_solver_constants.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/solver/cloth_solver_constants.js"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"cloth_solver_constants.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/solver/cloth_solver_constants.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0EG;AAEH;;;GAGG;AACH,0BAFU,MAAM,CAEgB;AAEhC;;;;GAIG;AACH,yBAFU,MAAM,CAEc;AAE9B;;;GAGG;AACH,0BAFU,MAAM,CAEa;AAE7B;;;GAGG;AACH,gCAFU,MAAM,CAEmB;AAEnC;;;GAGG;AACH,gCAFU,MAAM,CAEmB;AAEnC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wCAFU,MAAM,CAE8B;AAE9C;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,+BAFU,MAAM,CAEkB;AAElC;;;;;;;;;GASG;AACH,0CAFU,MAAM,CAE+B;AAE/C;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,0CAFU,MAAM,CAE+B;AAE/C;;;;GAIG;AACH,kCAFU,SAAS;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAC,CAAC,CAQvG"}
|