@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
|
@@ -1,645 +1,317 @@
|
|
|
1
|
-
import { assert } from "../../../../core/assert.js";
|
|
2
|
-
import { quat3_multiply } from "../../../../core/geom/3d/quaternion/quat3_multiply.js";
|
|
3
|
-
import { v3_quaternion_apply } from "../../../../core/geom/vec3/v3_quaternion_apply.js";
|
|
4
|
-
import { TransformAttachment } from "../../../ecs/transform-attachment/TransformAttachment.js";
|
|
5
|
-
import {
|
|
6
|
-
TRANSFORM64_ROTATION_OFFSET,
|
|
7
|
-
TRANSFORM64_TRANSLATION_OFFSET,
|
|
8
|
-
Transform64
|
|
9
|
-
} from "../../../ecs/transform/Transform64.js";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* {@link
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* rather than
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
* @
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
instance
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
instance.
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
*
|
|
231
|
-
|
|
232
|
-
*
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
|
|
236
|
-
*
|
|
237
|
-
*
|
|
238
|
-
*
|
|
239
|
-
*
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
*
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
position[node * 3 + 2] = position[p * 3 + 2] + COMPOSE[2];
|
|
319
|
-
|
|
320
|
-
quat3_multiply(
|
|
321
|
-
rotation, node * 4,
|
|
322
|
-
pqx, pqy, pqz, pqw,
|
|
323
|
-
local_rotation[node * 4], local_rotation[node * 4 + 1],
|
|
324
|
-
local_rotation[node * 4 + 2], local_rotation[node * 4 + 3]
|
|
325
|
-
);
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
instance.rest_local_position = local_position;
|
|
329
|
-
instance.rest_local_rotation = local_rotation;
|
|
330
|
-
|
|
331
|
-
instance.animated_position = position;
|
|
332
|
-
instance.animated_rotation = rotation;
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
/**
|
|
336
|
-
* @type {Float64Array}
|
|
337
|
-
* @private
|
|
338
|
-
*/
|
|
339
|
-
const COMPOSE = new Float64Array(3);
|
|
340
|
-
|
|
341
|
-
/**
|
|
342
|
-
* The authored pose a previous seeding captured, keyed by entity, so a re-seed
|
|
343
|
-
* of a live cloth does not mistake the shape the solver left behind for the
|
|
344
|
-
* shape the author authored.
|
|
345
|
-
*
|
|
346
|
-
* @param {ClothInstance} instance
|
|
347
|
-
* @returns {Map<number, {position: number[], rotation: number[]}>}
|
|
348
|
-
* @private
|
|
349
|
-
*/
|
|
350
|
-
function remember_rest_pose(instance) {
|
|
351
|
-
const remembered = new Map();
|
|
352
|
-
|
|
353
|
-
if (!instance.seeded || instance.rest_local_position === null) {
|
|
354
|
-
return remembered;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
for (let node = 1; node < instance.node_count; node++) {
|
|
358
|
-
remembered.set(instance.node_entity[node], {
|
|
359
|
-
position: [
|
|
360
|
-
instance.rest_local_position[node * 3],
|
|
361
|
-
instance.rest_local_position[node * 3 + 1],
|
|
362
|
-
instance.rest_local_position[node * 3 + 2]
|
|
363
|
-
],
|
|
364
|
-
rotation: [
|
|
365
|
-
instance.rest_local_rotation[node * 4],
|
|
366
|
-
instance.rest_local_rotation[node * 4 + 1],
|
|
367
|
-
instance.rest_local_rotation[node * 4 + 2],
|
|
368
|
-
instance.rest_local_rotation[node * 4 + 3]
|
|
369
|
-
]
|
|
370
|
-
});
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
return remembered;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
/**
|
|
377
|
-
* Rows, geodesics and the `ClothState` itself.
|
|
378
|
-
*
|
|
379
|
-
* @param {ClothInstance} instance
|
|
380
|
-
* @param {number} dt
|
|
381
|
-
* @private
|
|
382
|
-
*/
|
|
383
|
-
function build_state(instance, dt) {
|
|
384
|
-
const node_count = instance.node_count;
|
|
385
|
-
|
|
386
|
-
const parent = instance.node_parent;
|
|
387
|
-
const rest = instance.animated_position;
|
|
388
|
-
|
|
389
|
-
const dynamics = instance.cloth.dynamics;
|
|
390
|
-
|
|
391
|
-
const strain_limited = (dynamics.flags & ClothDynamicsFlags.StrainLimit) !== 0;
|
|
392
|
-
|
|
393
|
-
const geodesic = new Float32Array(node_count);
|
|
394
|
-
|
|
395
|
-
const mass_inverse = new Float32Array(node_count);
|
|
396
|
-
|
|
397
|
-
// The anchor is the fixed set: zero inverse mass, and a geodesic of zero,
|
|
398
|
-
// which is what makes every derived radius collapse onto it correctly.
|
|
399
|
-
for (let node = 1; node < node_count; node++) {
|
|
400
|
-
mass_inverse[node] = 1 / CLOTH_PARTICLE_MASS;
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
const stretch_particle = [];
|
|
404
|
-
const stretch_rest = [];
|
|
405
|
-
const stretch_stiffness = [];
|
|
406
|
-
const stretch_force_min = [];
|
|
407
|
-
const stretch_force_max = [];
|
|
408
|
-
|
|
409
|
-
const link_row = new Int32Array(node_count).fill(-1);
|
|
410
|
-
const strain_row = new Int32Array(node_count).fill(-1);
|
|
411
|
-
const skip_row = new Int32Array(node_count).fill(-1);
|
|
412
|
-
|
|
413
|
-
const strain = cloth_strain_allowance(dynamics.stretch);
|
|
414
|
-
|
|
415
|
-
// A skip row spans two links and both of its ends are free, so its
|
|
416
|
-
// effective inertia along the constraint is half a particle's.
|
|
417
|
-
const bend_stiffness = cloth_bend_ratio(dynamics.bend)
|
|
418
|
-
* (CLOTH_PARTICLE_MASS * 0.5) / (dt * dt);
|
|
419
|
-
|
|
420
|
-
let reach = 0;
|
|
421
|
-
|
|
422
|
-
for (let node = 1; node < node_count; node++) {
|
|
423
|
-
const p = parent[node];
|
|
424
|
-
|
|
425
|
-
const length = Math.hypot(
|
|
426
|
-
rest[node * 3] - rest[p * 3],
|
|
427
|
-
rest[node * 3 + 1] - rest[p * 3 + 1],
|
|
428
|
-
rest[node * 3 + 2] - rest[p * 3 + 2]
|
|
429
|
-
);
|
|
430
|
-
|
|
431
|
-
geodesic[node] = geodesic[p] + length;
|
|
432
|
-
|
|
433
|
-
if (geodesic[node] > reach) {
|
|
434
|
-
reach = geodesic[node];
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
link_row[node] = stretch_rest.length;
|
|
438
|
-
|
|
439
|
-
// Hard, bilateral: the fabric row. It is hard because a *penalty* stiff
|
|
440
|
-
// enough to be fabric adds energy rather than dissipating it — see
|
|
441
|
-
// `cloth_dynamics_map.js`, and `MEASUREMENTS.md` §6 for the +6.8 J.
|
|
442
|
-
stretch_particle.push(p, node);
|
|
443
|
-
stretch_rest.push(length);
|
|
444
|
-
stretch_stiffness.push(Infinity);
|
|
445
|
-
stretch_force_min.push(-Infinity);
|
|
446
|
-
stretch_force_max.push(Infinity);
|
|
447
|
-
|
|
448
|
-
if (strain_limited) {
|
|
449
|
-
strain_row[node] = stretch_rest.length;
|
|
450
|
-
|
|
451
|
-
// Hard, one-sided: §6's strain limit, and note the clamp. A row
|
|
452
|
-
// that bounds a distance from ABOVE may only apply force that
|
|
453
|
-
// reduces `C`, which for a distance row is the positive half —
|
|
454
|
-
// `[0, +∞)`. §6's table has this row at `(−∞, 0]`, which is the
|
|
455
|
-
// force that pushes the two ends apart; `cloth_leash_row.js`
|
|
456
|
-
// carries the derivation and a spec that shows it directly.
|
|
457
|
-
stretch_particle.push(p, node);
|
|
458
|
-
stretch_rest.push(length * (1 + strain));
|
|
459
|
-
stretch_stiffness.push(Infinity);
|
|
460
|
-
stretch_force_min.push(0);
|
|
461
|
-
stretch_force_max.push(Infinity);
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
const grandparent = parent[p];
|
|
465
|
-
|
|
466
|
-
if (grandparent >= 0 && bend_stiffness > 0) {
|
|
467
|
-
const span = Math.hypot(
|
|
468
|
-
rest[node * 3] - rest[grandparent * 3],
|
|
469
|
-
rest[node * 3 + 1] - rest[grandparent * 3 + 1],
|
|
470
|
-
rest[node * 3 + 2] - rest[grandparent * 3 + 2]
|
|
471
|
-
);
|
|
472
|
-
|
|
473
|
-
skip_row[node] = stretch_rest.length;
|
|
474
|
-
|
|
475
|
-
// Soft, bilateral: the bending model. Its rest length is read from
|
|
476
|
-
// the authored pose, so a chain authored with a curve holds it.
|
|
477
|
-
stretch_particle.push(grandparent, node);
|
|
478
|
-
stretch_rest.push(span);
|
|
479
|
-
stretch_stiffness.push(bend_stiffness);
|
|
480
|
-
stretch_force_min.push(-Infinity);
|
|
481
|
-
stretch_force_max.push(Infinity);
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
const leash_particle = [];
|
|
486
|
-
const leash_radius = [];
|
|
487
|
-
|
|
488
|
-
const slack_row = new Int32Array(node_count).fill(-1);
|
|
489
|
-
const tether_row = new Int32Array(node_count).fill(-1);
|
|
490
|
-
|
|
491
|
-
const slack_scale = CLOTH_SLACK_REACH * clamp01(dynamics.slack);
|
|
492
|
-
|
|
493
|
-
for (let node = 1; node < node_count; node++) {
|
|
494
|
-
// Tether first: §7 P2's long-range attachment, and the row that makes a
|
|
495
|
-
// low iteration budget viable at all, because being hard it is enforced
|
|
496
|
-
// almost exactly in one iteration however deep the chain is.
|
|
497
|
-
tether_row[node] = leash_radius.length;
|
|
498
|
-
|
|
499
|
-
leash_particle.push(node);
|
|
500
|
-
leash_radius.push(geodesic[node]);
|
|
501
|
-
|
|
502
|
-
if (slack_scale < CLOTH_SLACK_REACH) {
|
|
503
|
-
slack_row[node] = leash_radius.length;
|
|
504
|
-
|
|
505
|
-
leash_particle.push(node);
|
|
506
|
-
leash_radius.push(slack_scale * geodesic[node]);
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
let shortest_row = Infinity;
|
|
511
|
-
|
|
512
|
-
for (let row = 0; row < stretch_rest.length; row++) {
|
|
513
|
-
if (stretch_rest[row] > 0 && stretch_rest[row] < shortest_row) {
|
|
514
|
-
shortest_row = stretch_rest[row];
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
// A cloth of one particle has no rows at all, so it has no correction
|
|
519
|
-
// authority to speak of and its reach is the only length it carries.
|
|
520
|
-
instance.shortest_row = shortest_row < Infinity ? shortest_row : reach;
|
|
521
|
-
|
|
522
|
-
instance.geodesic = geodesic;
|
|
523
|
-
instance.reach = reach;
|
|
524
|
-
instance.link_row = link_row;
|
|
525
|
-
instance.strain_row = strain_row;
|
|
526
|
-
instance.skip_row = skip_row;
|
|
527
|
-
instance.slack_row = slack_row;
|
|
528
|
-
instance.tether_row = tether_row;
|
|
529
|
-
|
|
530
|
-
const state = ClothState.from({
|
|
531
|
-
position: rest,
|
|
532
|
-
mass_inverse,
|
|
533
|
-
stretch_particle: Int32Array.from(stretch_particle),
|
|
534
|
-
stretch_rest: Float32Array.from(stretch_rest),
|
|
535
|
-
stretch_stiffness: Float32Array.from(stretch_stiffness),
|
|
536
|
-
stretch_force_min: Float32Array.from(stretch_force_min),
|
|
537
|
-
stretch_force_max: Float32Array.from(stretch_force_max),
|
|
538
|
-
leash_particle: Int32Array.from(leash_particle),
|
|
539
|
-
leash_radius: Float32Array.from(leash_radius)
|
|
540
|
-
});
|
|
541
|
-
|
|
542
|
-
const particle_of_node = new Int32Array(node_count);
|
|
543
|
-
|
|
544
|
-
for (let particle = 0; particle < node_count; particle++) {
|
|
545
|
-
particle_of_node[state.source_of_particle[particle]] = particle;
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
instance.particle_of_node = particle_of_node;
|
|
549
|
-
instance.blended_position = new Float64Array(node_count * 3);
|
|
550
|
-
instance.blended_rotation = new Float64Array(node_count * 4);
|
|
551
|
-
instance.state = state;
|
|
552
|
-
instance.seeded = true;
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
/**
|
|
556
|
-
* @param {number} v
|
|
557
|
-
* @returns {number}
|
|
558
|
-
* @private
|
|
559
|
-
*/
|
|
560
|
-
function clamp01(v) {
|
|
561
|
-
return v < 0 ? 0 : (v > 1 ? 1 : v);
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
/**
|
|
565
|
-
* Re-parameterise the rows of an already-seeded cloth from its current
|
|
566
|
-
* {@link ClothDynamics}, without walking the subtree again.
|
|
567
|
-
*
|
|
568
|
-
* This is what makes `cloth.dynamics.slack = 0.2` work live: the topology, the
|
|
569
|
-
* rest lengths and the geodesics are properties of the authored pose and do not
|
|
570
|
-
* move, and everything that does move is a number in a row table.
|
|
571
|
-
*
|
|
572
|
-
* The multipliers are **not** reset. A row whose radius has just changed is
|
|
573
|
-
* carrying a force appropriate to the radius it had, and it is one warm start
|
|
574
|
-
* away from carrying the right one; zeroing them would put a visible jolt into
|
|
575
|
-
* every parameter change instead.
|
|
576
|
-
*
|
|
577
|
-
* @param {ClothInstance} instance
|
|
578
|
-
* @param {number} dt
|
|
579
|
-
* @returns {void}
|
|
580
|
-
*/
|
|
581
|
-
export function cloth_reparameterise(instance, dt) {
|
|
582
|
-
const dynamics = instance.cloth.dynamics;
|
|
583
|
-
|
|
584
|
-
const state = instance.state;
|
|
585
|
-
|
|
586
|
-
const node_count = instance.node_count;
|
|
587
|
-
|
|
588
|
-
const strain = cloth_strain_allowance(dynamics.stretch);
|
|
589
|
-
|
|
590
|
-
const bend_stiffness = cloth_bend_ratio(dynamics.bend)
|
|
591
|
-
* (CLOTH_PARTICLE_MASS * 0.5) / (dt * dt);
|
|
592
|
-
|
|
593
|
-
const slack_scale = CLOTH_SLACK_REACH * clamp01(dynamics.slack);
|
|
594
|
-
|
|
595
|
-
for (let node = 1; node < node_count; node++) {
|
|
596
|
-
const link = instance.link_row[node];
|
|
597
|
-
const strain_limit = instance.strain_row[node];
|
|
598
|
-
const skip = instance.skip_row[node];
|
|
599
|
-
const slack = instance.slack_row[node];
|
|
600
|
-
|
|
601
|
-
if (strain_limit >= 0) {
|
|
602
|
-
state.stretch_rest[strain_limit] = state.stretch_rest[link] * (1 + strain);
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
if (skip >= 0) {
|
|
606
|
-
state.stretch_stiffness[skip] = bend_stiffness;
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
if (slack >= 0) {
|
|
610
|
-
state.leash_radius[slack] = slack_scale * instance.geodesic[node];
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
instance.dynamics_seen.copy(dynamics);
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
/**
|
|
618
|
-
* Whether a dynamics change needs the subtree walked again rather than merely
|
|
619
|
-
* re-parameterised.
|
|
620
|
-
*
|
|
621
|
-
* Two fields do: turning the strain limit on or off adds or removes rows, and
|
|
622
|
-
* so does moving `slack` across the bound at which its row is provably
|
|
623
|
-
* inactive. Everything else is a number in a table that already exists.
|
|
624
|
-
*
|
|
625
|
-
* @param {ClothDynamics} before
|
|
626
|
-
* @param {ClothDynamics} after
|
|
627
|
-
* @returns {boolean}
|
|
628
|
-
*/
|
|
629
|
-
export function cloth_dynamics_change_needs_reseed(before, after) {
|
|
630
|
-
const strain_before = (before.flags & ClothDynamicsFlags.StrainLimit) !== 0;
|
|
631
|
-
const strain_after = (after.flags & ClothDynamicsFlags.StrainLimit) !== 0;
|
|
632
|
-
|
|
633
|
-
if (strain_before !== strain_after) {
|
|
634
|
-
return true;
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
const leashed_before = clamp01(before.slack) < 1;
|
|
638
|
-
const leashed_after = clamp01(after.slack) < 1;
|
|
639
|
-
|
|
640
|
-
if (leashed_before !== leashed_after) {
|
|
641
|
-
return true;
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
return (before.bend > 0) !== (after.bend > 0);
|
|
645
|
-
}
|
|
1
|
+
import { assert } from "../../../../core/assert.js";
|
|
2
|
+
import { quat3_multiply } from "../../../../core/geom/3d/quaternion/quat3_multiply.js";
|
|
3
|
+
import { v3_quaternion_apply } from "../../../../core/geom/vec3/v3_quaternion_apply.js";
|
|
4
|
+
import { TransformAttachment } from "../../../ecs/transform-attachment/TransformAttachment.js";
|
|
5
|
+
import {
|
|
6
|
+
TRANSFORM64_ROTATION_OFFSET,
|
|
7
|
+
TRANSFORM64_TRANSLATION_OFFSET,
|
|
8
|
+
Transform64
|
|
9
|
+
} from "../../../ecs/transform/Transform64.js";
|
|
10
|
+
import { Cloth } from "./Cloth.js";
|
|
11
|
+
import { ClothExclude } from "./ClothExclude.js";
|
|
12
|
+
import { ClothInstance } from "./ClothInstance.js";
|
|
13
|
+
import { cloth_build_children, cloth_build_rows } from "./cloth_build_rows.js";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* # Seeding a cloth from an entity subtree — §11.1
|
|
17
|
+
*
|
|
18
|
+
* One particle per entity in the transform subtree of the entity the
|
|
19
|
+
* {@link Cloth} is on, walked breadth-first through
|
|
20
|
+
* `TransformAttachmentSystem#findChildrenOf`, stopping at a nested `Cloth` or a
|
|
21
|
+
* {@link ClothExclude}. Stretch rows along the parent-child links, a bending
|
|
22
|
+
* model along each chain, and the anchor itself as the fixed set — so `d_geo`
|
|
23
|
+
* is distance along the chain from the anchor and every derived quantity in
|
|
24
|
+
* §3.4 works unchanged.
|
|
25
|
+
*
|
|
26
|
+
* ## What "bend rows along each chain" turned out to mean
|
|
27
|
+
*
|
|
28
|
+
* §11.1 asks for bend rows and the row model has one — the quadratic hinge of
|
|
29
|
+
* §6, four particles across the diamond either side of a shared edge. **A chain
|
|
30
|
+
* has no diamond.** `bt_edge_read_diamond` declines a wire edge for exactly
|
|
31
|
+
* that reason, and it is right to: the stencil is a discrete mean curvature over
|
|
32
|
+
* a surface and a rope is not one.
|
|
33
|
+
*
|
|
34
|
+
* The bending model here is instead a **skip row** — an ordinary stretch row
|
|
35
|
+
* between a node and its grandparent, at whatever distance the authored pose
|
|
36
|
+
* puts them. It is §6's own doctrine applied once more ("one row model,
|
|
37
|
+
* parameterised by mode"), it costs no new row kind, and it has the two
|
|
38
|
+
* properties §6 wanted from quadratic bending: there is no normal, no angle and
|
|
39
|
+
* no sign, so nothing degenerates at 0° or 180°, and a fold is high energy
|
|
40
|
+
* rather than a singular configuration. It also does something the quadratic
|
|
41
|
+
* stencil explicitly cannot (§18): because its rest length is read from the
|
|
42
|
+
* authored pose rather than assumed flat, **it holds a curved rest shape**.
|
|
43
|
+
*
|
|
44
|
+
* The row is soft, so its stiffness has to stay inside the dissipative band
|
|
45
|
+
* M0 measured; `cloth_dynamics_map.js` is where that is arranged and why.
|
|
46
|
+
*
|
|
47
|
+
* ## Mass is uniform, and the answer does not depend on it
|
|
48
|
+
*
|
|
49
|
+
* {@link ClothDynamics} carries no mass or density, and it does not need to.
|
|
50
|
+
* Every row scale in this system is a **ratio** of the row's own `m/h²` — the
|
|
51
|
+
* hard rows through the penalty band (`MEASUREMENTS.md` §4 held a chain at a
|
|
52
|
+
* fixed ratio across five decades of particle mass and got the same residual
|
|
53
|
+
* column every time), the soft ones through `cloth_bend_ratio` — and gravity is
|
|
54
|
+
* an acceleration. So the constant below is arbitrary in the strict sense that
|
|
55
|
+
* changing it changes no trajectory, and what matters about it is only that it
|
|
56
|
+
* is the same for every particle.
|
|
57
|
+
*
|
|
58
|
+
* @author Alex Goldring
|
|
59
|
+
* @copyright Company Named Limited (c) 2026
|
|
60
|
+
*/
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Walk the subtree and build everything {@link ClothSystem} needs to step it.
|
|
64
|
+
*
|
|
65
|
+
* @param {ClothInstance} instance seeded in place
|
|
66
|
+
* @param {EntityComponentDataset} ecd
|
|
67
|
+
* @param {TransformAttachmentSystem} attachments
|
|
68
|
+
* @param {number} dt fixed step, seconds — the bend row's scale is a ratio of
|
|
69
|
+
* `m/dt²`, so the step length is part of the rest data
|
|
70
|
+
* @returns {void}
|
|
71
|
+
*/
|
|
72
|
+
export function cloth_seed_subtree(instance, ecd, attachments, dt) {
|
|
73
|
+
const remembered = remember_rest_pose(instance);
|
|
74
|
+
|
|
75
|
+
const anchor = instance.entity;
|
|
76
|
+
|
|
77
|
+
const node_entity = [anchor];
|
|
78
|
+
const node_parent = [-1];
|
|
79
|
+
|
|
80
|
+
const pruned_entity = [];
|
|
81
|
+
const pruned_parent = [];
|
|
82
|
+
|
|
83
|
+
const scratch = [];
|
|
84
|
+
|
|
85
|
+
// Breadth-first, so a node's parent is always already numbered and the
|
|
86
|
+
// write-back can walk forwards.
|
|
87
|
+
for (let node = 0; node < node_entity.length; node++) {
|
|
88
|
+
const entity = node_entity[node];
|
|
89
|
+
|
|
90
|
+
const child_count = attachments.countChildrenOf(entity);
|
|
91
|
+
|
|
92
|
+
if (child_count === 0) {
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
scratch.length = child_count;
|
|
97
|
+
|
|
98
|
+
attachments.findChildrenOf(scratch, 0, entity);
|
|
99
|
+
|
|
100
|
+
for (let i = 0; i < child_count; i++) {
|
|
101
|
+
const child = scratch[i];
|
|
102
|
+
|
|
103
|
+
const excluded = ecd.getComponent(child, ClothExclude) !== undefined
|
|
104
|
+
|| ecd.getComponent(child, Cloth) !== undefined;
|
|
105
|
+
|
|
106
|
+
if (excluded) {
|
|
107
|
+
pruned_entity.push(child);
|
|
108
|
+
pruned_parent.push(node);
|
|
109
|
+
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (ecd.getComponent(child, Transform64) === undefined) {
|
|
114
|
+
// Not in the transform hierarchy in any usable sense. Its own
|
|
115
|
+
// children are unreachable too, so it is a prune rather than a
|
|
116
|
+
// skip — and it is not posed by the write-back either, because
|
|
117
|
+
// there is nothing to pose.
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
node_entity.push(child);
|
|
122
|
+
node_parent.push(node);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const node_count = node_entity.length;
|
|
127
|
+
|
|
128
|
+
instance.node_count = node_count;
|
|
129
|
+
instance.node_entity = Int32Array.from(node_entity);
|
|
130
|
+
instance.node_parent = Int32Array.from(node_parent);
|
|
131
|
+
|
|
132
|
+
instance.pruned_count = pruned_entity.length;
|
|
133
|
+
instance.pruned_entity = Int32Array.from(pruned_entity);
|
|
134
|
+
instance.pruned_parent = Int32Array.from(pruned_parent);
|
|
135
|
+
|
|
136
|
+
instance.pruned_transform = new Array(instance.pruned_count);
|
|
137
|
+
instance.pruned_attachment = new Array(instance.pruned_count);
|
|
138
|
+
|
|
139
|
+
for (let i = 0; i < instance.pruned_count; i++) {
|
|
140
|
+
const entity = instance.pruned_entity[i];
|
|
141
|
+
|
|
142
|
+
instance.pruned_transform[i] = ecd.getComponent(entity, Transform64);
|
|
143
|
+
instance.pruned_attachment[i] = ecd.getComponent(entity, TransformAttachment);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
instance.node_transform = new Array(node_count);
|
|
147
|
+
instance.node_attachment = new Array(node_count);
|
|
148
|
+
|
|
149
|
+
for (let node = 0; node < node_count; node++) {
|
|
150
|
+
const entity = instance.node_entity[node];
|
|
151
|
+
|
|
152
|
+
const transform = ecd.getComponent(entity, Transform64);
|
|
153
|
+
|
|
154
|
+
assert.defined(transform, `Transform64 of cloth node ${node} (entity ${entity})`);
|
|
155
|
+
|
|
156
|
+
instance.node_transform[node] = transform;
|
|
157
|
+
instance.node_attachment[node] = node === 0
|
|
158
|
+
? null
|
|
159
|
+
: ecd.getComponent(entity, TransformAttachment);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
cloth_build_children(instance);
|
|
163
|
+
read_rest_pose(instance, remembered);
|
|
164
|
+
|
|
165
|
+
instance.dynamics_seen.copy(instance.cloth.dynamics);
|
|
166
|
+
|
|
167
|
+
cloth_build_rows(instance, dt);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Capture the authored pose, and compose it into the anchor's frame.
|
|
172
|
+
*
|
|
173
|
+
* The **local** transforms are the source, not the world ones. That is not a
|
|
174
|
+
* preference: the write-back takes ownership of `TransformAttachment#transform`
|
|
175
|
+
* (§11.1), so this is the one moment the authored pose is still readable, and
|
|
176
|
+
* reading the world transforms instead would give the same answer now and the
|
|
177
|
+
* *simulated* pose on any later re-seed.
|
|
178
|
+
*
|
|
179
|
+
* `remembered` carries a previous seeding's capture across a re-seed, keyed by
|
|
180
|
+
* entity, so a structural change to a live cloth keeps the authored pose of
|
|
181
|
+
* every node that was already in it.
|
|
182
|
+
*
|
|
183
|
+
* The composed result is constant — the subtree's authored pose is rigid
|
|
184
|
+
* relative to its anchor, so in the anchor's own frame it does not move — which
|
|
185
|
+
* is why nothing recomposes it per step.
|
|
186
|
+
*
|
|
187
|
+
* @param {ClothInstance} instance
|
|
188
|
+
* @param {Map<number, {position: number[], rotation: number[]}>} remembered
|
|
189
|
+
* @private
|
|
190
|
+
*/
|
|
191
|
+
function read_rest_pose(instance, remembered) {
|
|
192
|
+
const node_count = instance.node_count;
|
|
193
|
+
|
|
194
|
+
const local_position = new Float32Array(node_count * 3);
|
|
195
|
+
const local_rotation = new Float32Array(node_count * 4);
|
|
196
|
+
|
|
197
|
+
const position = new Float32Array(node_count * 3);
|
|
198
|
+
const rotation = new Float32Array(node_count * 4);
|
|
199
|
+
|
|
200
|
+
// The anchor is the origin of the frame it anchors: no offset, no rotation.
|
|
201
|
+
local_rotation[3] = 1;
|
|
202
|
+
rotation[3] = 1;
|
|
203
|
+
|
|
204
|
+
const parent = instance.node_parent;
|
|
205
|
+
|
|
206
|
+
for (let node = 1; node < node_count; node++) {
|
|
207
|
+
const captured = remembered.get(instance.node_entity[node]);
|
|
208
|
+
|
|
209
|
+
if (captured !== undefined) {
|
|
210
|
+
local_position[node * 3] = captured.position[0];
|
|
211
|
+
local_position[node * 3 + 1] = captured.position[1];
|
|
212
|
+
local_position[node * 3 + 2] = captured.position[2];
|
|
213
|
+
|
|
214
|
+
local_rotation[node * 4] = captured.rotation[0];
|
|
215
|
+
local_rotation[node * 4 + 1] = captured.rotation[1];
|
|
216
|
+
local_rotation[node * 4 + 2] = captured.rotation[2];
|
|
217
|
+
local_rotation[node * 4 + 3] = captured.rotation[3];
|
|
218
|
+
} else {
|
|
219
|
+
const attachment = instance.node_attachment[node];
|
|
220
|
+
|
|
221
|
+
const local = attachment === undefined || attachment === null
|
|
222
|
+
? null
|
|
223
|
+
: attachment.transform;
|
|
224
|
+
|
|
225
|
+
if (local === null) {
|
|
226
|
+
// In the walk because something said it was a child, but with no
|
|
227
|
+
// local transform to compose. Its authored pose is its parent's,
|
|
228
|
+
// which is the only answer available and is at least inside the
|
|
229
|
+
// reachable set.
|
|
230
|
+
local_rotation[node * 4 + 3] = 1;
|
|
231
|
+
} else {
|
|
232
|
+
local_position[node * 3] = local[TRANSFORM64_TRANSLATION_OFFSET];
|
|
233
|
+
local_position[node * 3 + 1] = local[TRANSFORM64_TRANSLATION_OFFSET + 1];
|
|
234
|
+
local_position[node * 3 + 2] = local[TRANSFORM64_TRANSLATION_OFFSET + 2];
|
|
235
|
+
|
|
236
|
+
local_rotation[node * 4] = local[TRANSFORM64_ROTATION_OFFSET];
|
|
237
|
+
local_rotation[node * 4 + 1] = local[TRANSFORM64_ROTATION_OFFSET + 1];
|
|
238
|
+
local_rotation[node * 4 + 2] = local[TRANSFORM64_ROTATION_OFFSET + 2];
|
|
239
|
+
local_rotation[node * 4 + 3] = local[TRANSFORM64_ROTATION_OFFSET + 3];
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Compose down the walk. Breadth-first numbering means the parent is
|
|
244
|
+
// always already done, so one forward pass is the whole hierarchy.
|
|
245
|
+
const p = parent[node];
|
|
246
|
+
|
|
247
|
+
const pqx = rotation[p * 4];
|
|
248
|
+
const pqy = rotation[p * 4 + 1];
|
|
249
|
+
const pqz = rotation[p * 4 + 2];
|
|
250
|
+
const pqw = rotation[p * 4 + 3];
|
|
251
|
+
|
|
252
|
+
v3_quaternion_apply(
|
|
253
|
+
COMPOSE, 0,
|
|
254
|
+
local_position[node * 3], local_position[node * 3 + 1], local_position[node * 3 + 2],
|
|
255
|
+
pqx, pqy, pqz, pqw
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
position[node * 3] = position[p * 3] + COMPOSE[0];
|
|
259
|
+
position[node * 3 + 1] = position[p * 3 + 1] + COMPOSE[1];
|
|
260
|
+
position[node * 3 + 2] = position[p * 3 + 2] + COMPOSE[2];
|
|
261
|
+
|
|
262
|
+
quat3_multiply(
|
|
263
|
+
rotation, node * 4,
|
|
264
|
+
pqx, pqy, pqz, pqw,
|
|
265
|
+
local_rotation[node * 4], local_rotation[node * 4 + 1],
|
|
266
|
+
local_rotation[node * 4 + 2], local_rotation[node * 4 + 3]
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
instance.rest_local_position = local_position;
|
|
271
|
+
instance.rest_local_rotation = local_rotation;
|
|
272
|
+
|
|
273
|
+
instance.animated_position = position;
|
|
274
|
+
instance.animated_rotation = rotation;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* @type {Float64Array}
|
|
279
|
+
* @private
|
|
280
|
+
*/
|
|
281
|
+
const COMPOSE = new Float64Array(3);
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* The authored pose a previous seeding captured, keyed by entity, so a re-seed
|
|
285
|
+
* of a live cloth does not mistake the shape the solver left behind for the
|
|
286
|
+
* shape the author authored.
|
|
287
|
+
*
|
|
288
|
+
* @param {ClothInstance} instance
|
|
289
|
+
* @returns {Map<number, {position: number[], rotation: number[]}>}
|
|
290
|
+
* @private
|
|
291
|
+
*/
|
|
292
|
+
function remember_rest_pose(instance) {
|
|
293
|
+
const remembered = new Map();
|
|
294
|
+
|
|
295
|
+
if (!instance.seeded || instance.rest_local_position === null) {
|
|
296
|
+
return remembered;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
for (let node = 1; node < instance.node_count; node++) {
|
|
300
|
+
remembered.set(instance.node_entity[node], {
|
|
301
|
+
position: [
|
|
302
|
+
instance.rest_local_position[node * 3],
|
|
303
|
+
instance.rest_local_position[node * 3 + 1],
|
|
304
|
+
instance.rest_local_position[node * 3 + 2]
|
|
305
|
+
],
|
|
306
|
+
rotation: [
|
|
307
|
+
instance.rest_local_rotation[node * 4],
|
|
308
|
+
instance.rest_local_rotation[node * 4 + 1],
|
|
309
|
+
instance.rest_local_rotation[node * 4 + 2],
|
|
310
|
+
instance.rest_local_rotation[node * 4 + 3]
|
|
311
|
+
]
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return remembered;
|
|
316
|
+
}
|
|
317
|
+
|